<template>
	<ServicePageScaffold title="到达签到" fallback-url="/pages/mall/delivery/orders/route">
		<ServicePanel title="签到要求" subtitle="定位签到或扫码签到，要求在 50 米范围内并上传现场图片。">
			<text v-if="order != null" class="info-text">服务地址：{{ order.fullAddress }}</text>
			<text class="info-text">当前定位：{{ locationText }}</text>
			<text class="info-text">现场图片：{{ photos.length }} 张</text>
		</ServicePanel>
		<ServicePanel title="签到操作" subtitle="定位失败时要给出清晰提示。">
			<view class="button-stack">
				<button class="secondary-btn" @click="getCurrentLocation">获取 GPS 定位</button>
				<button class="secondary-btn" @click="choosePhoto">拍照上传现场图片</button>
				<input class="note-input" v-model="note" placeholder="补充签到说明，例如入户前核验联系人" />
				<button class="primary-btn" :disabled="submitting" @click="submitCheckin">{{ submitting ? '签到中...' : '完成签到' }}</button>
			</view>
		</ServicePanel>
	</ServicePageScaffold>
</template>

<script setup lang="uts">
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import ServicePageScaffold from '@/components/homeService/ServicePageScaffold.uvue'
import ServicePanel from '@/components/homeService/ServicePanel.uvue'
import type { DeliveryLocationType, DeliveryOrderType } from '@/types/delivery.uts'
import { checkinOrder, getDeliveryOrderDetail } from '@/services/deliveryService.uts'
import { requireDeliveryAuth } from '@/utils/deliveryAuth.uts'
import { getDeliveryRouteParam } from '@/utils/deliveryRoute.uts'

const orderId = ref('')
const order = ref<DeliveryOrderType | null>(null)
const currentLocation = ref<DeliveryLocationType | null>(null)
const locationText = ref('未获取')
const photos = ref([] as Array<string>)
const note = ref('')
const submitting = ref(false)

function toRadians(value: number): number {
	return value * 3.1415926 / 180
}

function calculateDistance(lat1: number, lng1: number, lat2: number, lng2: number): number {
	const earthRadius = 6378137
	const deltaLat = toRadians(lat2 - lat1)
	const deltaLng = toRadians(lng2 - lng1)
	const a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) + Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) * Math.sin(deltaLng / 2) * Math.sin(deltaLng / 2)
	const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
	return earthRadius * c
}

function wrapLocation(): Promise<DeliveryLocationType> {
	return new Promise((resolve, reject) => {
		uni.getLocation({
			type: 'gcj02',
			success: (res) => {
				resolve({ latitude: res.latitude, longitude: res.longitude, address: '当前位置', time: new Date().toISOString().replace('T', ' ').substring(0, 19) })
			},
			fail: () => {
				reject(new Error('定位失败'))
			}
		})
	})
}

function wrapChooseImage(): Promise<Array<string>> {
	return new Promise((resolve, reject) => {
		uni.chooseImage({
			count: 3,
			sourceType: ['camera'],
			success: (res) => {
				resolve(res.tempFilePaths)
			},
			fail: () => {
				reject(new Error('拍照失败'))
			}
		})
	})
}

async function loadData() {
	const authResult = await requireDeliveryAuth({ redirectOnFail: true, toastOnFail: true })
	if (!authResult.ok || orderId.value == '') {
		return
	}
	order.value = await getDeliveryOrderDetail(orderId.value)
}

async function getCurrentLocation() {
	try {
		currentLocation.value = await wrapLocation()
		locationText.value = '纬度 ' + String(currentLocation.value.latitude) + ' / 经度 ' + String(currentLocation.value.longitude)
	} catch (error) {
		uni.showToast({ title: '签到定位失败，请检查定位权限', icon: 'none' })
	}
}

async function choosePhoto() {
	try {
		const selected = await wrapChooseImage()
		photos.value = selected
	} catch (error) {
		uni.showToast({ title: '拍照失败，请重试', icon: 'none' })
	}
}

async function submitCheckin() {
	if (submitting.value) return
	if (order.value == null) return
	if (currentLocation.value == null) {
		await getCurrentLocation()
		if (currentLocation.value == null) return
	}
	if (photos.value.length == 0) {
		uni.showToast({ title: '请至少上传一张现场图片', icon: 'none' })
		return
	}
	const distance = calculateDistance(currentLocation.value.latitude, currentLocation.value.longitude, order.value.latitude, order.value.longitude)
	if (distance > order.value.allowCheckinRadiusMeters) {
		uni.showToast({ title: '距离服务地址超出允许范围，不能签到', icon: 'none' })
		return
	}
	submitting.value = true
	try {
		await checkinOrder(orderId.value, {
			location: currentLocation.value as DeliveryLocationType,
			note: note.value,
			photos: photos.value,
			checkinMode: 'gps'
		})
		uni.showToast({ title: '签到成功', icon: 'success' })
		uni.redirectTo({ url: '/pages/mall/delivery/service-record/index?id=' + orderId.value })
	} finally {
		submitting.value = false
	}
}

onLoad((options) => {
	if (options != null) {
		orderId.value = getDeliveryRouteParam(options as UTSJSONObject, 'id')
	}
	loadData()
})
</script>

<style scoped>
.info-text {
	display: block;
	margin-bottom: 14rpx;
	font-size: 26rpx;
	line-height: 38rpx;
	color: #16324f;
}

.button-stack {
	flex-direction: column;
}

.primary-btn,
.secondary-btn {
	margin-bottom: 18rpx;
	border-radius: 18rpx;
	font-size: 28rpx;
}

.primary-btn {
	background: #0f766e;
	color: #ffffff;
}

.secondary-btn {
	background: #eaf2f0;
	color: #0f766e;
}

.note-input {
	height: 84rpx;
	padding: 0 24rpx;
	margin-bottom: 18rpx;
	border-radius: 18rpx;
	background: #f2f7f6;
	font-size: 28rpx;
}
</style>