import { AkReq } from '@/uni_modules/ak-req/index.uts'
import type { UserProfile } from '@/types/mall-types.uts'
import type { DeliveryInfoType } from '@/types/delivery.uts'
import { getDeliveryProfileByUserId } from '@/api/delivery.uts'
import supa from '@/components/supadb/aksupainstance.uts'
import { getCurrentUser, setIsLoggedIn, setUserProfile } from '@/utils/store.uts'

export type DeliveryAuthOptions = {
	redirectOnFail?: boolean
	toastOnFail?: boolean
	redirect?: string
	message?: string
}

export type DeliveryAuthResult = {
	ok: boolean
	message: string
	userInfo: UserProfile | null
	deliveryInfo: DeliveryInfoType | null
}

const DELIVERY_LOGIN_PATH = '/pages/user/login'
const DELIVERY_LOGIN_TARGET = '/pages/user/login?mode=delivery'
const DELIVERY_HOME_PATH = '/pages/mall/delivery/home/index'
const DELIVERY_USER_KEY = 'delivery_user_info'
const DELIVERY_INFO_KEY = 'delivery_info'
const DELIVERY_TOKEN_KEY = 'delivery_token'
const DELIVERY_ROLE_LIST = ['delivery', 'Deliverer', 'deliverer', 'service_staff', 'care_worker'] as Array<string>

let redirectingToDeliveryLogin = false

function hasText(value: string | null): boolean {
	return value != null && value !== ''
}

function shouldShowToast(enabled: boolean | null): boolean {
	return enabled == null || enabled === true
}

function shouldRedirect(enabled: boolean | null): boolean {
	return enabled == null || enabled === true
}

function getCurrentRoute(): string {
	try {
		const pages = getCurrentPages() as Array<UTSJSONObject>
		if (pages.length === 0) {
			return ''
		}
		const currentPage = pages[pages.length - 1]
		const route = currentPage['route']
		if (route != null) {
			return '/' + route
		}
	} catch (e) {}
	return ''
}

function buildFailureResult(message: string, userInfo: UserProfile | null = null): DeliveryAuthResult {
	return {
		ok: false,
		message,
		userInfo,
		deliveryInfo: null
	}
}

function parseUserInfo(raw: string): UserProfile | null {
	try {
		return JSON.parse(raw) as UserProfile
	} catch (e) {
		return null
	}
}

function parseDeliveryInfo(raw: string): DeliveryInfoType | null {
	try {
		return JSON.parse(raw) as DeliveryInfoType
	} catch (e) {
		return null
	}
}

function persistUserInfo(userInfo: UserProfile): void {
	uni.setStorageSync(DELIVERY_USER_KEY, JSON.stringify(userInfo))
}

function persistDeliveryInfo(info: DeliveryInfoType): void {
	uni.setStorageSync(DELIVERY_INFO_KEY, JSON.stringify(info))
}

export function setDeliveryInfo(info: DeliveryInfoType): void {
	persistDeliveryInfo(info)
}

export function clearDeliveryInfo(): void {
	uni.removeStorageSync(DELIVERY_INFO_KEY)
}

export function saveDeliverySession(token: string, userInfo: UserProfile, deliveryInfo: DeliveryInfoType | null): void {
	AkReq.setToken(token, '', Date.now() + 24 * 60 * 60 * 1000)
	uni.setStorageSync(DELIVERY_TOKEN_KEY, token)
	persistUserInfo(userInfo)
	setIsLoggedIn(true)
	setUserProfile(userInfo)
	if (deliveryInfo != null) {
		persistDeliveryInfo(deliveryInfo)
	} else {
		uni.removeStorageSync(DELIVERY_INFO_KEY)
	}
}

export function getToken(): string {
	const stored = uni.getStorageSync(DELIVERY_TOKEN_KEY) as string | null
	if (stored != null && stored != '') {
		return stored
	}
	const token = AkReq.getToken()
	return token != null ? token : ''
}

export function getUserInfo(): UserProfile | null {
	const raw = uni.getStorageSync(DELIVERY_USER_KEY) as string | null
	if (!hasText(raw)) {
		return null
	}
	return parseUserInfo(raw as string)
}

async function resolveUserInfo(): Promise<UserProfile | null> {
	const cached = getUserInfo()
	if (cached != null) {
		return cached
	}
	try {
		const profile = await getCurrentUser()
		if (profile != null) {
			persistUserInfo(profile)
		}
		return profile
	} catch (e) {
		return null
	}
}

export function getDeliveryInfo(): DeliveryInfoType | null {
	const raw = uni.getStorageSync(DELIVERY_INFO_KEY) as string | null
	if (!hasText(raw)) {
		return null
	}
	return parseDeliveryInfo(raw as string)
}

export function isLoggedIn(): boolean {
	if (hasText(getToken()) && getUserInfo() != null) {
		return true
	}
	try {
		const session = supa.getSession()
		return session != null && session.user != null
	} catch (e) {
		return false
	}
}

export function isDelivererRole(userInfo: UserProfile | null): boolean {
	if (userInfo == null) {
		return false
	}
	const role = userInfo.role != null ? userInfo.role : ''
	for (let i = 0; i < DELIVERY_ROLE_LIST.length; i++) {
		if (role == DELIVERY_ROLE_LIST[i]) {
			return true
		}
	}
	return false
}

export async function checkDeliveryAccount(userInfo: UserProfile): Promise<DeliveryInfoType | null> {
	const userId = userInfo.id != null ? userInfo.id : ''
	if (!hasText(userId)) {
		return null
	}
	return await getDeliveryProfileByUserId(userId)
}

export function clearDeliveryAuth(): void {
	try {
		AkReq.clearToken()
	} catch (e) {}
	uni.removeStorageSync(DELIVERY_TOKEN_KEY)
	uni.removeStorageSync(DELIVERY_USER_KEY)
	uni.removeStorageSync('user_id')
	clearDeliveryInfo()
	setIsLoggedIn(false)
	setUserProfile({ username: '', email: '' } as UserProfile)
}

export async function logoutDelivery(): Promise<void> {
	clearDeliveryAuth()
	try {
		await supa.signOut()
	} catch (e) {}
}

function getRedirectTarget(explicitRedirect: string | null): string {
	if (hasText(explicitRedirect)) {
		return explicitRedirect as string
	}
	const currentRoute = getCurrentRoute()
	if (hasText(currentRoute) && currentRoute !== DELIVERY_LOGIN_PATH) {
		return currentRoute
	}
	return DELIVERY_HOME_PATH
}

export function redirectToDeliveryLogin(redirect?: string): void {
	const currentRoute = getCurrentRoute()
	if (currentRoute == DELIVERY_LOGIN_PATH) {
		return
	}
	if (redirectingToDeliveryLogin) {
		return
	}
	redirectingToDeliveryLogin = true
	let targetUrl = DELIVERY_LOGIN_TARGET
	const redirectTarget = getRedirectTarget(redirect != null ? redirect : null)
	if (hasText(redirectTarget)) {
		targetUrl = DELIVERY_LOGIN_TARGET + '&redirect=' + encodeURIComponent(redirectTarget)
	}
	uni.reLaunch({
		url: targetUrl,
		complete: () => {
			setTimeout(() => {
				redirectingToDeliveryLogin = false
			}, 300)
		}
	})
}

export function goDeliveryHome(): void {
	uni.reLaunch({ url: DELIVERY_HOME_PATH })
}

export function isCurrentDeliveryPage(): boolean {
	return getCurrentRoute().startsWith('/pages/mall/delivery/')
}

export function handleDeliveryUnauthorized(message?: string, redirect?: string): void {
	clearDeliveryAuth()
	redirectToDeliveryLogin(redirect)
	if (message != null && message != '') {
		uni.showToast({ title: message, icon: 'none' })
	}
}

function handleFailure(message: string, options?: DeliveryAuthOptions, userInfo: UserProfile | null = null): DeliveryAuthResult {
	clearDeliveryAuth()
	if (shouldShowToast(options?.toastOnFail ?? null) && hasText(message)) {
		uni.showToast({ title: message, icon: 'none' })
	}
	if (shouldRedirect(options?.redirectOnFail ?? null)) {
		redirectToDeliveryLogin(getRedirectTarget(options?.redirect ?? null))
	}
	return buildFailureResult(message, userInfo)
}

export async function requireDeliveryAuth(options?: DeliveryAuthOptions): Promise<DeliveryAuthResult> {
	const currentRoute = getCurrentRoute()
	const onLoginPage = currentRoute == DELIVERY_LOGIN_PATH
	const effectiveOptions: DeliveryAuthOptions = {
		redirectOnFail: onLoginPage ? false : options?.redirectOnFail,
		toastOnFail: options?.toastOnFail,
		redirect: options?.redirect,
		message: options?.message
	}

	if (!isLoggedIn()) {
		return handleFailure(options?.message != null ? options.message : '请先登录服务人员账号', effectiveOptions)
	}

	const userInfo = await resolveUserInfo()
	if (userInfo == null) {
		return handleFailure('登录状态已失效，请重新登录', effectiveOptions)
	}

	if (!isDelivererRole(userInfo)) {
		return handleFailure('当前账号不是上门服务人员账号', effectiveOptions, userInfo)
	}

	const deliveryInfo = await checkDeliveryAccount(userInfo)
	if (deliveryInfo == null) {
		return handleFailure('当前账号未绑定服务人员档案', effectiveOptions, userInfo)
	}

	if (deliveryInfo.status == 'disabled' || deliveryInfo.status == 'locked' || deliveryInfo.status == 'suspended') {
		return handleFailure('账号不可接单', effectiveOptions, userInfo)
	}

	if (deliveryInfo.usesMock && (!hasText(deliveryInfo.organizationId) || !hasText(deliveryInfo.organizationName))) {
		return handleFailure('当前账号未绑定服务机构', effectiveOptions, userInfo)
	}

	if (deliveryInfo.usesMock && deliveryInfo.certificateStatus == 'expired') {
		return handleFailure('资质已过期，请联系管理员', effectiveOptions, userInfo)
	}

	persistUserInfo(userInfo)
	persistDeliveryInfo(deliveryInfo)
	return {
		ok: true,
		message: '',
		userInfo,
		deliveryInfo
	}
}