'use client'

import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
import type { Dispatch, SetStateAction } from 'react'
import { usePathname, useRouter } from 'next/navigation'
import { backend, clearStaffToken, mapBackendOrder, mapBackendTask, membershipLevelFromBackend, type BackendCheckoutPreview, type BackendInvoiceApplication, type BackendInvoiceRequest, type BackendInvoiceStatus } from '@/lib/backend'

export type CartItemType = 'course' | 'event' | 'data' | 'agent' | 'expert' | 'consulting' | 'membership'

export interface CartItem {
  id: string
  type: CartItemType
  title: string
  price: number
  href: string
  meta?: string
  serviceEntryType?: string
  serviceEntryId?: string
  serviceEntryHref?: string
  billingCycle?: 'monthly' | 'yearly'
  expertId?: string
  expertName?: string
  expertBookingId?: string
  dataServiceRequestId?: string
  consultingRequestId?: string
}

export interface OrderItem extends CartItem {
  quantity: number
}

export interface DeliveryTask {
  id: string
  orderId: string
  productId?: string
  title: string
  type: CartItemType
  status: '待提交资料' | '资料审核中' | '交付中' | '已完成'
  currentStep: number
  steps: string[]
  updatedAt: string
  scheduledAt?: string
}

export interface OrderRecord {
  id: string
  settlementNo?: string
  backendId?: string
  createdAt: string
  items: OrderItem[]
  subtotal: number
  discount: number
  total: number
  paymentMethod: 'wechat' | 'alipay' | 'offline'
  status: '待支付' | '已支付' | '已关闭'
  invoiceStatus?: BackendInvoiceStatus | ''
  invoiceApplication?: BackendInvoiceApplication | null
  note?: string
}

export interface ConsultingRequestInput {
  company: string
  contactName: string
  contactPhone: string
  email: string
  direction: string
  organizationType: string
  industry: string
  city: string
  projectStage: string
  urgency: string
  budgetRange: string
  expectedStart: string
  currentSituation: string
  requirement: string
  goals: string
  preferredContactTime: string
}

export interface ConsultingRequest extends ConsultingRequestInput {
  id: string
  backendId?: string
  createdAt: string
  updatedAt: string
  status: '待受理' | '已分配顾问' | '沟通中' | '方案制定中' | '待确认报价' | '待支付' | '服务中' | '已完成' | '已取消'
  currentStep: number
  steps: string[]
  owner: string
  assigneeName?: string
  progressNote?: string
  solutionSummary?: string
  chargeRequired?: boolean
  quotedTitle?: string
  quotedAmount?: number
  quotedNote?: string
  quotedAt?: string | null
  confirmedAt?: string | null
  orderId?: string | null
  paidAt?: string | null
  finalSummary?: string
  finalFileUrl?: string
}

interface UserProfile {
  id?: string
  name: string
  phone: string
  passportNo?: string
  wechatId?: string
  authProvider?: 'phone' | 'wechat'
  onboardingCompleted?: boolean
  contactPhone?: string
  email?: string
  organization?: string
  title?: string
  city?: string
  address?: string
  industry?: string
  invoiceTitle?: string
  taxNumber?: string
  invoiceEmail?: string
  expertApplicationStatus?: 'pending' | 'approved' | 'rejected' | 'withdrawn' | 'submitted' | 'profile-review' | 'profile-rejected' | 'profile-approved' | string
  expertProfileStatus?: 'draft' | 'published' | 'offline' | string
  membershipLevel: 0 | 1 | 2
}

interface AppContextValue {
  user: UserProfile | null
  token: string
  hydrated: boolean
  accountSyncing: boolean
  cartItems: CartItem[]
  orders: OrderRecord[]
  deliveryTasks: DeliveryTask[]
  consultingRequests: ConsultingRequest[]
  cartCount: number
  cartTotal: number
  login: (credential: string, provider?: UserProfile['authProvider'], code?: string) => Promise<UserProfile>
  loginWithToken: (token: string, provider?: UserProfile['authProvider']) => Promise<UserProfile>
  logout: () => void
  requireLogin: () => boolean
  addCartItem: (item: CartItem) => boolean
  removeCartItem: (id: string, type: CartItemType) => void
  clearCart: () => void
  previewCheckout: (items: CartItem[], couponCode?: string) => Promise<BackendCheckoutPreview | null>
  createOrder: (options?: CreateOrderOptions) => Promise<OrderRecord | null>
  refreshAccount: () => Promise<void>
  createConsultingRequest: (input: ConsultingRequestInput) => Promise<ConsultingRequest | null>
  updateDeliveryTask: (id: string, status: DeliveryTask['status'], payload?: Record<string, unknown>) => Promise<void>
  updateUserProfile: (profile: Partial<Omit<UserProfile, 'membershipLevel' | 'authProvider'>>) => Promise<void>
}

const AppContext = createContext<AppContextValue | null>(null)

const userKey = 'dlbdi:user'
const tokenKey = 'dlbdi:token'
const cartKey = 'dlbdi:cart'
const ordersKey = 'dlbdi:orders'
const deliveryTasksKey = 'dlbdi:deliveryTasks'
const consultingRequestsKey = 'dlbdi:consultingRequests'

interface CreateOrderOptions {
  items?: CartItem[]
  paymentMethod?: OrderRecord['paymentMethod']
  clearCartAfter?: boolean
  note?: string
  status?: OrderRecord['status']
  couponCode?: string
  expertBookingId?: string
  dataServiceRequestId?: string
  consultingRequestId?: string
  invoiceRequest?: BackendInvoiceRequest
}

function readJson<T>(key: string, fallback: T): T {
  if (typeof window === 'undefined') return fallback
  try {
    const value = window.localStorage.getItem(key)
    return value ? (JSON.parse(value) as T) : fallback
  } catch {
    return fallback
  }
}

function sameCartItem(a: CartItem, b: Pick<CartItem, 'id' | 'type'>) {
  return a.id === b.id && a.type === b.type
}

const consultingSteps = ['提交需求', '顾问受理', '需求沟通', '方案/报价', '服务执行', '方案反馈']

function mapUserProfile(user: Awaited<ReturnType<typeof backend.me>>): UserProfile {
  return {
    id: user.id,
    name: user.displayName || user.phone || '研究院用户',
    phone: user.phone,
    passportNo: user.passportNo,
    wechatId: user.wechatId,
    contactPhone: user.contactPhone,
    email: user.email,
    organization: user.organization,
    title: user.title,
    city: user.city,
    address: user.address,
    industry: user.industry,
    invoiceTitle: user.invoiceTitle,
    taxNumber: user.taxNumber,
    invoiceEmail: user.invoiceEmail,
    authProvider: user.wechatId && !user.phone ? 'wechat' : 'phone',
    onboardingCompleted: user.onboardingCompleted,
    expertApplicationStatus: user.expertApplicationStatus,
    expertProfileStatus: user.expertProfileStatus,
    membershipLevel: membershipLevelFromBackend(user.membershipLevel),
  }
}

function consultingStatusLabel(status: string): ConsultingRequest['status'] {
  if (status === 'completed') return '已完成'
  if (status === 'in_service') return '服务中'
  if (status === 'pending_payment') return '待支付'
  if (status === 'proposal_ready') return '待确认报价'
  if (status === 'planning') return '方案制定中'
  if (status === 'communicating') return '沟通中'
  if (status === 'assigned') return '已分配顾问'
  if (status === 'cancelled') return '已取消'
  return '待受理'
}

function mapConsultingRequest(request: Awaited<ReturnType<typeof backend.accountConsultingRequests>>['items'][number]): ConsultingRequest {
  return {
    id: request.requestNo || request.id,
    backendId: request.id,
    createdAt: request.createdAt,
    updatedAt: request.updatedAt,
    status: consultingStatusLabel(request.status),
    currentStep: request.currentStep,
    steps: consultingSteps,
    owner: request.owner,
    assigneeName: request.assigneeName || undefined,
    progressNote: request.progressNote,
    solutionSummary: request.solutionSummary,
    chargeRequired: request.chargeRequired,
    quotedTitle: request.quotedTitle,
    quotedAmount: request.quotedAmount,
    quotedNote: request.quotedNote,
    quotedAt: request.quotedAt,
    confirmedAt: request.confirmedAt,
    orderId: request.orderId,
    paidAt: request.paidAt,
    finalSummary: request.finalSummary,
    finalFileUrl: request.finalFileUrl,
    company: request.company,
    contactName: request.contactName,
    contactPhone: request.contactPhone,
    email: request.email,
    direction: request.direction,
    organizationType: request.organizationType,
    industry: request.industry,
    city: request.city,
    projectStage: request.projectStage,
    urgency: request.urgency,
    budgetRange: request.budgetRange,
    expectedStart: request.expectedStart,
    currentSituation: request.currentSituation,
    requirement: request.requirement,
    goals: request.goals,
    preferredContactTime: request.preferredContactTime,
  }
}

async function refreshAccountState(
  token: string,
  setUser: Dispatch<SetStateAction<UserProfile | null>>,
  setOrders: Dispatch<SetStateAction<OrderRecord[]>>,
  setDeliveryTasks: Dispatch<SetStateAction<DeliveryTask[]>>,
  setConsultingRequests: Dispatch<SetStateAction<ConsultingRequest[]>>,
) {
  try {
    const user = await backend.me(token)
    setUser(mapUserProfile(user))
    const [orders, tasks, consulting] = await Promise.allSettled([
      backend.accountOrders(token),
      backend.accountTasks(token),
      backend.accountConsultingRequests(token),
    ])
    if (orders.status === 'fulfilled') setOrders((orders.value.items || []).map(mapBackendOrder))
    if (tasks.status === 'fulfilled') setDeliveryTasks((tasks.value.items || []).map(mapBackendTask))
    if (consulting.status === 'fulfilled') setConsultingRequests((consulting.value.items || []).map(mapConsultingRequest))
  } catch {
    setUser(null)
  }
}

export function AppProvider({ children }: { children: React.ReactNode }) {
  const router = useRouter()
  const pathname = usePathname()
  const [hydrated, setHydrated] = useState(false)
  const [accountSyncing, setAccountSyncing] = useState(false)
  const [user, setUser] = useState<UserProfile | null>(null)
  const [token, setToken] = useState('')
  const [cartItems, setCartItems] = useState<CartItem[]>([])
  const [orders, setOrders] = useState<OrderRecord[]>([])
  const [deliveryTasks, setDeliveryTasks] = useState<DeliveryTask[]>([])
  const [consultingRequests, setConsultingRequests] = useState<ConsultingRequest[]>([])

  useEffect(() => {
    queueMicrotask(() => {
      const savedUser = readJson<UserProfile | null>(userKey, null)
      const savedToken = readJson<string>(tokenKey, '')
      setUser(savedUser)
      setToken(savedToken)
      setCartItems(readJson<CartItem[]>(cartKey, []))
      setOrders(readJson<OrderRecord[]>(ordersKey, []))
      setDeliveryTasks(readJson<DeliveryTask[]>(deliveryTasksKey, []))
      setConsultingRequests(readJson<ConsultingRequest[]>(consultingRequestsKey, []))
      setHydrated(true)

      if (savedToken) {
        setAccountSyncing(true)
        void refreshAccountState(savedToken, setUser, setOrders, setDeliveryTasks, setConsultingRequests)
          .finally(() => setAccountSyncing(false))
      }
    })
  }, [])

  useEffect(() => {
    if (!hydrated) return
    window.localStorage.setItem(userKey, JSON.stringify(user))
  }, [hydrated, user])

  useEffect(() => {
    if (!hydrated) return
    window.localStorage.setItem(tokenKey, JSON.stringify(token))
  }, [hydrated, token])

  useEffect(() => {
    if (!hydrated) return
    window.localStorage.setItem(cartKey, JSON.stringify(cartItems))
  }, [cartItems, hydrated])

  useEffect(() => {
    if (!hydrated) return
    window.localStorage.setItem(ordersKey, JSON.stringify(orders))
  }, [hydrated, orders])

  useEffect(() => {
    if (!hydrated) return
    window.localStorage.setItem(deliveryTasksKey, JSON.stringify(deliveryTasks))
  }, [deliveryTasks, hydrated])

  useEffect(() => {
    if (!hydrated) return
    window.localStorage.setItem(consultingRequestsKey, JSON.stringify(consultingRequests))
  }, [consultingRequests, hydrated])

  const login = useCallback(async (credential: string, provider: UserProfile['authProvider'] = 'phone', code = '') => {
    const result = provider === 'wechat'
      ? await backend.loginByWechat(credential, code)
      : await backend.loginByPhone(credential, code)
    const profile = {
      ...mapUserProfile(result.user),
      wechatId: provider === 'wechat' ? credential : result.user.wechatId,
      authProvider: provider,
    }
    setToken(result.token)
    setUser(profile)
    const [orders, tasks, consulting] = await Promise.allSettled([
      backend.accountOrders(result.token),
      backend.accountTasks(result.token),
      backend.accountConsultingRequests(result.token),
    ])
    if (orders.status === 'fulfilled') setOrders((orders.value.items || []).map(mapBackendOrder))
    if (tasks.status === 'fulfilled') setDeliveryTasks((tasks.value.items || []).map(mapBackendTask))
    if (consulting.status === 'fulfilled') setConsultingRequests((consulting.value.items || []).map(mapConsultingRequest))
    return profile
  }, [])

  const loginWithToken = useCallback(async (nextToken: string, provider?: UserProfile['authProvider']) => {
    setAccountSyncing(true)
    try {
      const remoteUser = await backend.me(nextToken)
      const profile = {
        ...mapUserProfile(remoteUser),
        ...(provider ? { authProvider: provider } : {}),
      }
      setToken(nextToken)
      setUser(profile)
      const [orders, tasks, consulting] = await Promise.allSettled([
        backend.accountOrders(nextToken),
        backend.accountTasks(nextToken),
        backend.accountConsultingRequests(nextToken),
      ])
      if (orders.status === 'fulfilled') setOrders((orders.value.items || []).map(mapBackendOrder))
      if (tasks.status === 'fulfilled') setDeliveryTasks((tasks.value.items || []).map(mapBackendTask))
      if (consulting.status === 'fulfilled') setConsultingRequests((consulting.value.items || []).map(mapConsultingRequest))
      return profile
    } finally {
      setAccountSyncing(false)
    }
  }, [])

  const logout = useCallback(() => {
    setUser(null)
    setToken('')
    setCartItems([])
    setOrders([])
    setDeliveryTasks([])
    setConsultingRequests([])
    if (typeof window !== 'undefined') {
      window.localStorage.removeItem(userKey)
      window.localStorage.removeItem(tokenKey)
      window.localStorage.removeItem(cartKey)
      window.localStorage.removeItem(ordersKey)
      window.localStorage.removeItem(deliveryTasksKey)
      window.localStorage.removeItem(consultingRequestsKey)
      clearStaffToken()
    }
  }, [])

  const requireLogin = useCallback(() => {
    if (user) return true
    const query = typeof window !== 'undefined' ? window.location.search : ''
    const redirect = encodeURIComponent(`${pathname || '/'}${query}`)
    router.push(`/login-required?redirect=${redirect}&action=account`)
    return false
  }, [pathname, router, user])

  const addCartItem = useCallback((item: CartItem) => {
    if (!user) {
      return false
    }

    setCartItems((items) => {
      if (items.some((existing) => sameCartItem(existing, item))) return items
      return [...items, item]
    })
    return true
  }, [user])

  const removeCartItem = useCallback((id: string, type: CartItemType) => {
    setCartItems((items) => items.filter((item) => !sameCartItem(item, { id, type })))
  }, [])

  const clearCart = useCallback(() => {
    setCartItems([])
  }, [])

  const previewCheckout = useCallback(async (items: CartItem[], couponCode?: string) => {
    if (!token || items.length === 0) return null
    return backend.previewCheckout(token, items, couponCode)
  }, [token])

  const updateUserProfile = useCallback(async (profile: Partial<Omit<UserProfile, 'membershipLevel' | 'authProvider'>>) => {
    if (token) {
      const payload = {
        displayName: profile.name,
        contactPhone: profile.contactPhone,
        email: profile.email,
        organization: profile.organization,
        title: profile.title,
        city: profile.city,
        address: profile.address,
        industry: profile.industry,
        invoiceTitle: profile.invoiceTitle,
        taxNumber: profile.taxNumber,
        invoiceEmail: profile.invoiceEmail,
      }
      const request = profile.onboardingCompleted ? backend.completeOnboarding(token, payload) : backend.updateProfile(token, payload)
      const updated = await request
      setUser((current) => current ? { ...current, ...mapUserProfile(updated) } : current)
      return
    }
    setUser((current) => {
      if (!current) return current
      const nextPhone = profile.phone === '-' ? '' : profile.phone
      const phone = current.authProvider === 'wechat' && nextPhone !== undefined ? nextPhone : current.phone
      return {
        ...current,
        ...profile,
        phone,
      }
    })
  }, [token])

  const createOrder = useCallback(async (options: CreateOrderOptions = {}) => {
    if (!user || !token) return null
    const sourceItems = options.items ?? cartItems
    if (sourceItems.length === 0 && !options.dataServiceRequestId && !options.consultingRequestId) return null

    try {
      const created = options.consultingRequestId
        ? await backend.createConsultingCheckout(token, options.consultingRequestId, options.invoiceRequest)
        : options.dataServiceRequestId
        ? await backend.createDataServiceCheckout(token, options.dataServiceRequestId, options.invoiceRequest)
        : await backend.createOrder(token, sourceItems, options.couponCode, options.expertBookingId, options.dataServiceRequestId, options.consultingRequestId, options.invoiceRequest)
      const finalOrder = created
      const mapped = mapBackendOrder(finalOrder)
      const [orders, tasks, consulting] = await Promise.all([
        backend.accountOrders(token),
        backend.accountTasks(token),
        backend.accountConsultingRequests(token),
      ])
      setOrders(orders.items.map(mapBackendOrder))
      setDeliveryTasks(tasks.items.map(mapBackendTask))
      setConsultingRequests(consulting.items.map(mapConsultingRequest))
      if (options.clearCartAfter ?? !options.items) setCartItems([])
      if (finalOrder.status === 'paid' && finalOrder.items.some((item) => item.productType === 'membership')) {
        const refreshed = await backend.me(token)
        setUser(mapUserProfile(refreshed))
      }
      return mapped
    } catch (error) {
      console.error(error)
      return null
    }
  }, [cartItems, token, user])

  const createConsultingRequest = useCallback(async (input: ConsultingRequestInput) => {
    if (!user || !token) return null
    const request = mapConsultingRequest(await backend.createConsultingRequest(token, input))
    setConsultingRequests((items) => [request, ...items.filter((item) => item.id !== request.id)])
    return request
  }, [token, user])

  const updateDeliveryTask = useCallback(async (id: string, status: DeliveryTask['status'], payload: Record<string, unknown> = {}) => {
    if (token && status === '资料审核中') {
      const updated = await backend.submitAccountTaskMaterials(token, id, payload)
      setDeliveryTasks((items) => items.map((item) => (item.id === id ? mapBackendTask(updated) : item)))
      return
    }
    setDeliveryTasks((items) => items.map((item) => {
      if (item.id !== id) return item
      const currentStep = status === '待提交资料' ? 0 : status === '资料审核中' ? 1 : status === '交付中' ? 2 : item.steps.length - 1
      return { ...item, status, currentStep, updatedAt: new Date().toISOString() }
    }))
  }, [token])

  const refreshAccount = useCallback(async () => {
    if (!token) return
    setAccountSyncing(true)
    try {
      await refreshAccountState(token, setUser, setOrders, setDeliveryTasks, setConsultingRequests)
    } finally {
      setAccountSyncing(false)
    }
  }, [token])

  const value = useMemo<AppContextValue>(() => {
    const cartTotal = cartItems.reduce((sum, item) => sum + item.price, 0)
    return {
      user,
      token,
      hydrated,
      accountSyncing,
      cartItems,
      orders,
      deliveryTasks,
      consultingRequests,
      cartCount: cartItems.length,
      cartTotal,
      login,
      loginWithToken,
      logout,
      requireLogin,
      addCartItem,
      removeCartItem,
      clearCart,
      previewCheckout,
      createOrder,
      refreshAccount,
      createConsultingRequest,
      updateDeliveryTask,
      updateUserProfile,
    }
  }, [accountSyncing, addCartItem, cartItems, clearCart, consultingRequests, createConsultingRequest, createOrder, deliveryTasks, hydrated, login, loginWithToken, logout, orders, previewCheckout, refreshAccount, removeCartItem, requireLogin, token, updateDeliveryTask, updateUserProfile, user])

  return <AppContext.Provider value={value}>{children}</AppContext.Provider>
}

export function useApp() {
  const context = useContext(AppContext)
  if (!context) throw new Error('useApp must be used within AppProvider')
  return context
}
