import { Image, Text, View } from '@tarojs/components'
import Taro, { useLoad } from '@tarojs/taro'
import { useEffect, useState } from 'react'
import { Page } from '@/components/ui'
import { backend, type PcScanClientInfo } from '@/api/backend'
import { getToken, getUser } from '@/stores/storage'
import { tapMedium } from '@/utils/feedback'
import { toast } from '@/utils/nav'
import pcLoginConfirmImage from '@/assets/pc-login-confirm.svg'

const fallbackClientInfo: Required<PcScanClientInfo> = {
  region: '未知地区',
  device: '电脑端设备',
  browser: '浏览器'
}

const previewClientInfo: Required<PcScanClientInfo> = {
  region: '中国大陆',
  device: 'Windows 电脑',
  browser: 'Chrome 浏览器'
}

function cleanClientInfoText(value: unknown, fallback: string) {
  const text = String(value || '').trim().replace(/\s+/g, ' ')
  return text ? text.slice(0, 48) : fallback
}

function queryValue(query: Record<string, unknown>, keys: string[]) {
  for (const key of keys) {
    const rawValue = query[key]
    if (rawValue === undefined || rawValue === null) continue
    const text = Array.isArray(rawValue) ? String(rawValue[0] || '') : String(rawValue)
    if (text.trim()) {
      try {
        return decodeURIComponent(text)
      } catch {
        return text
      }
    }
  }
  return ''
}

function clientInfoFromQuery(query: Record<string, unknown>, previewMode: boolean): Required<PcScanClientInfo> {
  const base = previewMode ? previewClientInfo : fallbackClientInfo
  return {
    region: cleanClientInfoText(queryValue(query, ['region', 'clientRegion', 'client_region']), base.region),
    device: cleanClientInfoText(queryValue(query, ['device', 'clientDevice', 'client_device']), base.device),
    browser: cleanClientInfoText(queryValue(query, ['browser', 'clientBrowser', 'client_browser']), base.browser)
  }
}

function mergeClientInfo(current: Required<PcScanClientInfo>, next?: PcScanClientInfo | null): Required<PcScanClientInfo> {
  if (!next) return current
  return {
    region: cleanClientInfoText(next.region, current.region),
    device: cleanClientInfoText(next.device, current.device),
    browser: cleanClientInfoText(next.browser, current.browser)
  }
}

export default function PcConfirmPage() {
  const [sessionId, setSessionId] = useState('')
  const [previewMode, setPreviewMode] = useState(false)
  const [clientInfo, setClientInfo] = useState<Required<PcScanClientInfo>>(fallbackClientInfo)
  const [checking, setChecking] = useState(false)
  const [confirming, setConfirming] = useState(false)
  const [canceling, setCanceling] = useState(false)

  useLoad((query) => {
    const nextSessionId = String(query.sessionId || query.session_id || '')
    const nextPreviewMode = String(query.preview || '') === '1'
    setPreviewMode(nextPreviewMode)
    setSessionId(nextSessionId)
    setClientInfo(clientInfoFromQuery(query as Record<string, unknown>, nextPreviewMode))
    if (!nextSessionId && !nextPreviewMode) {
      toast('电脑端登录会话无效')
      Taro.reLaunch({ url: '/pages/home/index' })
    }
  })

  useEffect(() => {
    if (!sessionId || previewMode) return
    void prepareConfirm()
  }, [previewMode, sessionId])

  function loginUrl() {
    return `/pages/auth/login/index?redirect=${encodeURIComponent('/pages/home/index')}&pcSessionId=${encodeURIComponent(sessionId)}`
  }

  function onboardingUrl() {
    return `/pages/auth/onboarding/index?redirect=${encodeURIComponent('/pages/home/index')}&pcSessionId=${encodeURIComponent(sessionId)}`
  }

  function handlePcLoginError(error: unknown) {
    const code = (error as { code?: string })?.code
    const statusCode = Number((error as { statusCode?: unknown })?.statusCode || 0)
    if (code === 'phone_required') {
      toast('请先绑定手机号')
      Taro.redirectTo({ url: loginUrl() })
      return
    }
    if (code === 'profile_required') {
      toast('请先完善资料')
      Taro.redirectTo({ url: onboardingUrl() })
      return
    }
    if (code === 'pc_login_expired' || statusCode === 410) {
      toast('二维码已过期，请刷新电脑端二维码')
      Taro.reLaunch({ url: '/pages/home/index' })
      return
    }
    if (code === 'pc_login_session_closed') {
      toast('扫码登录会话已结束')
      Taro.reLaunch({ url: '/pages/home/index' })
      return
    }
    toast(error instanceof Error ? error.message : '确认登录失败')
  }

  async function prepareConfirm() {
    if (previewMode) return true
    const token = getToken()
    const user = getUser()
    if (!token || !user) {
      toast('请先完成微信登录')
      Taro.redirectTo({ url: loginUrl() })
      return false
    }
    if (!user.phone) {
      toast('请先绑定手机号')
      Taro.redirectTo({ url: loginUrl() })
      return false
    }
    if (!user.onboardingCompleted) {
      void backend.preparePcScanLogin(token, sessionId).catch(() => undefined)
      Taro.redirectTo({ url: onboardingUrl() })
      return false
    }

    setChecking(true)
    try {
      const result = await backend.preparePcScanLogin(token, sessionId)
      setClientInfo((current) => mergeClientInfo(current, result.client))
      if (result.nextAction === 'bind_phone') {
        toast('请先绑定手机号')
        Taro.redirectTo({ url: loginUrl() })
        return false
      }
      if (result.nextAction === 'complete_profile') {
        toast('请先完善资料')
        Taro.redirectTo({ url: onboardingUrl() })
        return false
      }
      return true
    } catch (error) {
      handlePcLoginError(error)
      return false
    } finally {
      setChecking(false)
    }
  }

  async function confirmLogin() {
    if (checking || confirming) return
    tapMedium()
    const ready = await prepareConfirm()
    if (!ready) return
    if (previewMode) {
      toast('授权页预览')
      return
    }
    const token = getToken()
    const user = getUser()
    if (!token || !user) {
      toast('请先完成微信登录')
      Taro.navigateTo({ url: `/pages/auth/login/index?pcSessionId=${encodeURIComponent(sessionId)}` })
      return
    }
    if (!user.onboardingCompleted) {
      Taro.navigateTo({ url: `/pages/auth/onboarding/index?pcSessionId=${encodeURIComponent(sessionId)}` })
      return
    }
    if (!sessionId) {
      toast('电脑端登录会话无效')
      return
    }

    setConfirming(true)
    try {
      await backend.confirmPcScanLogin(token, sessionId)
      toast('电脑端已登录')
      Taro.reLaunch({ url: '/pages/home/index' })
    } catch (error) {
      handlePcLoginError(error)
    } finally {
      setConfirming(false)
    }
  }

  async function cancelLogin() {
    if (canceling) return
    tapMedium()
    setCanceling(true)
    try {
      const token = getToken()
      if (!previewMode && token && sessionId) await backend.cancelPcScanLogin(token, sessionId)
    } catch {
      // 取消失败不阻断用户离开，PC 端最多等待二维码自然过期。
    } finally {
      setCanceling(false)
      Taro.reLaunch({ url: '/pages/home/index' })
    }
  }

  return (
    <Page>
      <View className="auth-minimal auth-flow-shell pc-confirm-shell">
        <View className="auth-flow-head pc-confirm-head">
          <Text className="auth-flow-title">确认登录电脑端</Text>
          <Text className="auth-flow-subtitle">请确认当前操作由你本人发起</Text>
        </View>
        <Image className="pc-confirm-illustration" src={pcLoginConfirmImage} mode="aspectFit" />
        <View className="pc-confirm-meta">
          <View className="pc-confirm-meta-row">
            <Text className="pc-confirm-meta-label">地区</Text>
            <Text className="pc-confirm-meta-value">{clientInfo.region}</Text>
          </View>
          <View className="pc-confirm-meta-row">
            <Text className="pc-confirm-meta-label">使用设备</Text>
            <Text className="pc-confirm-meta-value">{clientInfo.device}</Text>
          </View>
          <View className="pc-confirm-meta-row last">
            <Text className="pc-confirm-meta-label">浏览器</Text>
            <Text className="pc-confirm-meta-value">{clientInfo.browser}</Text>
          </View>
        </View>
        <View className="pc-confirm-actions">
          <View className={checking || confirming ? 'auth-big-btn primary disabled' : 'auth-big-btn primary'} onClick={() => void confirmLogin()}>
            <Text>{checking ? '校验中...' : confirming ? '确认中...' : '确认登录'}</Text>
          </View>
          <View className="pc-confirm-cancel" onClick={cancelLogin}>
            <Text>{canceling ? '取消中...' : '取消'}</Text>
          </View>
        </View>
      </View>
    </Page>
  )
}
