import Taro from '@tarojs/taro'
import type { CartItem, DeliveryTask, OrderRecord, UserProfile } from '@/types'
import { backend, defaultPaymentChannel, mapOrder, mapTask, mapUser, type BackendInvoiceRequest, type BackendOrder } from '@/api/backend'
import { safeMiniappPath } from '@/utils/nav'

const keys = {
  user: 'dlbdi-mini:user',
  token: 'dlbdi-mini:token',
  staffToken: 'dlbdi-mini:staff-token',
  cart: 'dlbdi-mini:cart',
  orders: 'dlbdi-mini:orders',
  tasks: 'dlbdi-mini:tasks'
}

const aiLeadDraftPrefix = 'dlbdi-mini:ai-lead-draft:'

export type AiLeadDraft = {
  type?: 'consulting' | 'data_service' | string
  payload?: Record<string, unknown>
  missingFields?: string[]
  pagePath?: string
  submitEndpoint?: string
  createdAt?: string
  source?: string
}

function read<T>(key: string, fallback: T): T {
  try {
    return Taro.getStorageSync(key) || fallback
  } catch {
    return fallback
  }
}

function write<T>(key: string, value: T) {
  Taro.setStorageSync(key, value)
}

export function getUser() {
  return read<UserProfile | null>(keys.user, null)
}

export function saveUser(user: UserProfile | null) {
  write(keys.user, user)
}

export function getToken() {
  return read<string>(keys.token, '')
}

export function saveToken(token: string) {
  write(keys.token, token)
}

export function getStaffToken() {
  return read<string>(keys.staffToken, '')
}

export function saveStaffToken(token: string) {
  write(keys.staffToken, token)
}

export function clearStaffToken() {
  write(keys.staffToken, '')
}

export function ensureStaffLoggedIn(redirect?: string) {
  const token = getStaffToken()
  if (!token) {
    const target = redirect ? safeMiniappPath(redirect, '') : ''
    Taro.redirectTo({ url: `/pages/staff/index/index${target ? `?redirect=${encodeURIComponent(target)}` : ''}` })
    return ''
  }
  return token
}

export function getCart() {
  return read<CartItem[]>(keys.cart, [])
}

export function saveCart(items: CartItem[]) {
  write(keys.cart, items)
}

export function getOrders() {
  return read<OrderRecord[]>(keys.orders, [])
}

export function saveOrders(items: OrderRecord[]) {
  write(keys.orders, items)
}

export function getDeliveryTasks() {
  return read<DeliveryTask[]>(keys.tasks, [])
}

export function saveDeliveryTasks(items: DeliveryTask[]) {
  write(keys.tasks, items)
}

export function getAiLeadDraft(draftKey: string): AiLeadDraft | null {
  const key = String(draftKey || '').trim()
  if (!/^[a-zA-Z0-9._-]{6,80}$/.test(key)) return null
  const value = read<AiLeadDraft | null>(`${aiLeadDraftPrefix}${key}`, null)
  if (!value || typeof value !== 'object' || !value.payload || typeof value.payload !== 'object') return null
  return value
}

export function clearAiLeadDraft(draftKey: string) {
  const key = String(draftKey || '').trim()
  if (!/^[a-zA-Z0-9._-]{6,80}$/.test(key)) return
  try {
    Taro.removeStorageSync(`${aiLeadDraftPrefix}${key}`)
  } catch {}
}

export function ensureLoggedIn(redirect?: string) {
  const user = getUser()
  const target = redirect ? safeMiniappPath(redirect, '') : ''
  if (!user) {
    Taro.navigateTo({ url: `/pages/auth/login/index${target ? `?redirect=${encodeURIComponent(target)}` : ''}` })
    return null
  }
  if (!user.onboardingCompleted) {
    Taro.navigateTo({ url: `/pages/auth/onboarding/index${target ? `?redirect=${encodeURIComponent(target)}` : ''}` })
    return null
  }
  return user
}

export function hasCompletedProfile() {
  const user = getUser()
  return Boolean(user?.onboardingCompleted)
}

export function addToCart(item: CartItem) {
  const items = getCart()
  if (items.some((existing) => existing.id === item.id && existing.type === item.type)) return items
  const next = [...items, item]
  saveCart(next)
  return next
}

export function removeCartItem(id: string) {
  const next = getCart().filter((item) => item.id !== id)
  saveCart(next)
  return next
}

export function createOrders(items: CartItem[], _user: UserProfile) {
  const now = '2026/6/1 09:30:00'
  const bizDate = new Date().toISOString().slice(0, 10).replace(/-/g, '')
  const previous = getOrders()
  const next = items.map((item, index) => {
    return {
      ...item,
      orderNo: `ORD${bizDate}${String(index + 1).padStart(6, '0')}`,
      settlementNo: `CKO${bizDate}${String(index + 1).padStart(6, '0')}`,
      amount: item.price,
      paidAmount: item.price,
      purchasedAt: now,
      productStatus: statusFor(item.type)
    }
  })
  saveOrders([...next, ...previous])
  saveCart([])
  return next
}

export async function createBackendOrders(items: CartItem[], options: { clearCart?: boolean; invoiceRequest?: BackendInvoiceRequest } = {}) {
  const token = getToken()
  if (!token) throw new Error('请先登录')
  const dataServiceRequestId = items.find((item) => item.dataServiceRequestId)?.dataServiceRequestId
  const consultingRequestId = items.find((item) => item.consultingRequestId)?.consultingRequestId
  const created = consultingRequestId
    ? await backend.createConsultingCheckout(token, consultingRequestId, options.invoiceRequest)
    : dataServiceRequestId
    ? await backend.createDataServiceCheckout(token, dataServiceRequestId, options.invoiceRequest)
    : await backend.createOrder(token, items, options.invoiceRequest)
  let finalOrder = created
  if (created.status === 'pending_payment') {
    const payment = await backend.createPaymentOrder(token, created.orderNo, defaultPaymentChannel)
    if (defaultPaymentChannel === 'dev') {
      finalOrder = (await backend.succeedDevPayment(payment.paymentOrder.paymentNo)).order
    } else {
      const params = payment.paymentOrder.jsapiParams
      if (!params) throw new Error('微信支付参数生成失败，请稍后重试')
      try {
        await Taro.requestPayment({
          timeStamp: params.timeStamp,
          nonceStr: params.nonceStr,
          package: params.package,
          signType: params.signType,
          paySign: params.paySign
        })
      } catch {
        throw new Error('支付未完成')
      }
      finalOrder = await waitForPaidOrder(token, payment.paymentOrder.paymentNo)
    }
  }
  const previous = getOrders()
  const mapped = mapOrder(finalOrder)
  saveOrders([...mapped, ...previous.filter((item) => item.orderNo !== finalOrder.orderNo)])
  await refreshBackendTasks().catch(() => undefined)
  if (finalOrder.items.some((item) => item.productType === 'membership')) {
    await refreshBackendUser().catch(() => undefined)
  }
  if (options.clearCart !== false) saveCart([])
  return mapped
}

export async function payBackendOrder(orderNo: string) {
  const token = getToken()
  if (!token) throw new Error('请先登录')
  if (!orderNo) throw new Error('订单号不能为空')
  const payment = await backend.createPaymentOrder(token, orderNo, defaultPaymentChannel)
  let finalOrder = payment.order
  if (defaultPaymentChannel === 'dev') {
    finalOrder = (await backend.succeedDevPayment(payment.paymentOrder.paymentNo)).order
  } else if (payment.order.status === 'pending_payment') {
    const params = payment.paymentOrder.jsapiParams
    if (!params) throw new Error('微信支付参数生成失败，请稍后重试')
    try {
      await Taro.requestPayment({
        timeStamp: params.timeStamp,
        nonceStr: params.nonceStr,
        package: params.package,
        signType: params.signType,
        paySign: params.paySign
      })
    } catch {
      throw new Error('支付未完成')
    }
    finalOrder = await waitForPaidOrder(token, payment.paymentOrder.paymentNo)
  }
  const previous = getOrders()
  const mapped = mapOrder(finalOrder)
  saveOrders([...mapped, ...previous.filter((item) => item.orderNo !== finalOrder.orderNo)])
  await refreshBackendTasks().catch(() => undefined)
  await refreshBackendUser().catch(() => undefined)
  return finalOrder
}

async function waitForPaidOrder(token: string, paymentNo: string): Promise<BackendOrder> {
  let latest: BackendOrder | null = null
  for (let index = 0; index < 8; index += 1) {
    const result = await backend.paymentStatus(token, paymentNo)
    latest = result.order
    if (result.canRedirect || result.order.status === 'paid') return result.order
    if (result.paymentOrder.status === 'expired') throw new Error('支付二维码已过期，请重新发起支付')
    if (result.paymentOrder.status === 'failed' || result.paymentOrder.status === 'closed') throw new Error('支付未完成，请重新发起支付')
    await new Promise((resolve) => setTimeout(resolve, 1200))
  }
  if (latest) return latest
  throw new Error('支付结果确认中，请稍后在订单中查看')
}

export async function refreshBackendUser() {
  const token = getToken()
  if (!token) return getUser()
  const user = mapUser(await backend.me(token))
  saveUser(user)
  return user
}

export async function refreshBackendOrders() {
  const token = getToken()
  if (!token) return getOrders()
  const result = await backend.accountOrders(token)
  const orders = result.items.flatMap(mapOrder)
  saveOrders(orders)
  return orders
}

export async function refreshBackendTasks() {
  const token = getToken()
  if (!token) return getDeliveryTasks()
  const result = await backend.accountTasks(token)
  const tasks = result.items.map(mapTask)
  saveDeliveryTasks(tasks)
  return tasks
}

export function getDeliveryTask(id: string) {
  return getDeliveryTasks().find((item) => item.id === id) || null
}

export async function submitBackendTaskMaterials(taskId: string, payload: Record<string, unknown>) {
  const token = getToken()
  if (!token) throw new Error('请先登录')
  const updated = mapTask(await backend.submitTaskMaterials(token, taskId, payload))
  const next = getDeliveryTasks().map((item) => (item.id === taskId ? updated : item))
  saveDeliveryTasks(next.some((item) => item.id === taskId) ? next : [updated, ...next])
  return updated
}

function statusFor(type: CartItem['type']) {
  if (type === 'consulting') return '待联系'
  if (type === 'expert') return '待同意'
  if (type === 'event') return '已报名'
  if (type === 'course') return '已报名'
  if (type === 'agent') return '待提交资料'
  if (type === 'membership') return '已开通'
  return '-'
}
