import { useCallback, useEffect, useRef, useState } from 'react'
import {
  View,
  Text,
  TextInput,
  Pressable,
  ScrollView,
  StyleSheet,
  Alert,
  Platform,
} from 'react-native'
import * as Clipboard from 'expo-clipboard'
import { CameraView, useCameraPermissions } from 'expo-camera'
import { Ionicons } from '@expo/vector-icons'
import { LinearGradient } from 'expo-linear-gradient'
import { SafeAreaView } from 'react-native-safe-area-context'

import { useBind } from '@/context/BindContext'
import { parseBindPayload, type BindPayload } from '@/lib/types'
import { theme } from '@/constants/theme'

function normalizeHostInput(hostInput: string): { baseUrl: string; port: number } | null {
  const s = hostInput.trim()
  if (!s) return null

  if (/^https?:\/\//i.test(s)) {
    try {
      const u = new URL(s)
      const port = Number(u.port || (u.protocol === 'https:' ? 443 : 80))
      if (!Number.isFinite(port)) return null
      return { baseUrl: u.origin, port }
    } catch {
      return null
    }
  }

  const noPath = s.split('/')[0]
  const i = noPath.lastIndexOf(':')
  if (i <= 0) return null
  const host = noPath.slice(0, i).trim()
  const port = Number(noPath.slice(i + 1))
  if (!host || !Number.isFinite(port) || port <= 0) return null
  return { baseUrl: `http://${host}:${port}`, port }
}

export default function BindScreen() {
  const { bind, setBind, clear, ready } = useBind()
  const [msg, setMsg] = useState('')
  const [hostText, setHostText] = useState('')
  const [scanOn, setScanOn] = useState(false)
  const [perm, requestPerm] = useCameraPermissions()
  const scannedRef = useRef(false)

  useEffect(() => {
    if (!scanOn) scannedRef.current = false
  }, [scanOn])

  useEffect(() => {
    if (!bind?.baseUrl) {
      setHostText('')
      return
    }
    const v = bind.baseUrl.replace(/^https?:\/\//i, '')
    setHostText(v)
  }, [bind?.baseUrl])

  const applyPayload = useCallback(
    async (p: BindPayload) => {
      await setBind(p)
      setMsg('已导入绑定（含 token）。可在下方修改 IP/域名与端口后再点「保存」。')
    },
    [setBind],
  )

  const onBarcodeScanned = useCallback(
    (result: { data: string }) => {
      if (scannedRef.current) return
      const p = parseBindPayload(result.data)
      if (!p) {
        setMsg('二维码内容不是有效的绑定 JSON（需 v1、baseUrl 等字段）。')
        return
      }
      scannedRef.current = true
      void (async () => {
        await applyPayload(p)
        setScanOn(false)
      })()
    },
    [applyPayload],
  )

  const onPasteJson = useCallback(async () => {
    const raw = (await Clipboard.getStringAsync()).trim()
    const p = parseBindPayload(raw)
    if (!p) {
      setMsg('剪贴板内容不是有效的绑定 JSON。')
      return
    }
    await applyPayload(p)
  }, [applyPayload])

  const onSaveHost = useCallback(async () => {
    const n = normalizeHostInput(hostText)
    if (!n) {
      setMsg('请输入 `ip/域名:端口`（或带 http:// 的 baseUrl）。')
      return
    }
    const p: BindPayload = { v: 1, baseUrl: n.baseUrl, port: n.port, token: bind?.token ?? '' }
    await setBind(p)
    setMsg('已保存绑定地址；未改动的 token 已保留。')
  }, [hostText, bind?.token, setBind])

  const onResetHost = useCallback(async () => {
    setMsg('')
    Alert.alert('清除配对', '确定要删除当前绑定地址吗？', [
      { text: '取消', style: 'cancel' },
      { text: '清除', style: 'destructive', onPress: () => void clear() },
    ])
  }, [clear])

  const copyFull = useCallback(async () => {
    if (!bind) return
    await Clipboard.setStringAsync(JSON.stringify(bind, null, 2))
    setMsg('已复制完整绑定 JSON。')
  }, [bind])

  const testConn = useCallback(async () => {
    if (!bind) return
    const url = `${bind.baseUrl}/health`
    setMsg('正在测试 API 连接…')
    const ac = new AbortController()
    const t = setTimeout(() => ac.abort(), 15000)
    try {
      const r = await fetch(url, {
        signal: ac.signal,
        headers: bind.token ? { Authorization: `Bearer ${bind.token}` } : undefined,
      })
      const j = await r.json().catch(() => ({}))
      setMsg('')
      Alert.alert('连接测试', r.ok ? `OK: ${JSON.stringify(j)}` : `HTTP ${r.status}`)
    } catch (e) {
      const isAbort = e instanceof Error && e.name === 'AbortError'
      setMsg('')
      Alert.alert(
        isAbort ? '连接超时' : '连接失败',
        isAbort
          ? '15 秒内无响应。请确认手机能访问绑定里的 baseUrl:端口（或域名:端口），PC 上 web2 服务已启动，且防火墙/网络路由允许（换网后可能需要重新扫码或改地址）。'
          : e instanceof Error
            ? e.message
            : String(e),
      )
    } finally {
      clearTimeout(t)
    }
  }, [bind])

  const openScan = useCallback(async () => {
    setMsg('')
    if (Platform.OS === 'web') {
      setMsg('网页版请使用「从剪贴板导入 JSON」。')
      return
    }
    if (!perm?.granted) {
      const r = await requestPerm()
      if (!r.granted) {
        setMsg('需要相机权限才能扫码。')
        return
      }
    }
    setScanOn(true)
  }, [perm?.granted, requestPerm])

  if (!ready) {
    return (
      <SafeAreaView style={styles.safe}>
        <Text style={styles.muted}>加载中...</Text>
      </SafeAreaView>
    )
  }

  return (
    <SafeAreaView style={styles.safe} edges={['bottom']}>
      <ScrollView contentContainerStyle={styles.scroll} keyboardShouldPersistTaps="handled">
        <Text style={styles.h1}>远程配对</Text>
        <Text style={styles.lead}>
          PC 端生成二维码后扫码导入；导入后可在下方编辑 `ip/域名:端口` 再保存，token 会保留。也可仅手动填写地址（需自行保证与 PC 上 token 一致）。
        </Text>

        {!!msg && <Text style={styles.msgBanner}>{msg}</Text>}

        {bind && (
          <LinearGradient colors={['#1e3a5f', theme.bgCard]} style={styles.card}>
            <Text style={styles.cardTitle}>当前已绑定</Text>
            <Text style={styles.mono}>{bind.baseUrl}</Text>
            <Text style={styles.mutedSmall}>token：{bind.token ? '已保存' : '无'}</Text>
            <View style={styles.row}>
              <Pressable style={styles.btn} onPress={() => void testConn()}>
                <Text style={styles.btnText}>测试 API</Text>
              </Pressable>
              <Pressable
                style={[styles.btn, styles.btnDanger]}
                onPress={() => {
                  Alert.alert('清除配对', '确定要清除当前保存的绑定信息吗？', [
                    { text: '取消', style: 'cancel' },
                    { text: '清除', style: 'destructive', onPress: () => void clear() },
                  ])
                }}
              >
                <Text style={styles.btnText}>清除</Text>
              </Pressable>
            </View>
          </LinearGradient>
        )}

        <View style={styles.block}>
          <Text style={styles.h2}>扫码或导入 JSON</Text>
          <Text style={styles.body}>与 PC 端「远程控制」面板中的二维码内容一致（含 baseUrl、port、token）。</Text>
          <View style={styles.etRow}>
            <Pressable style={styles.btnPrimary} onPress={() => void openScan()}>
              <Ionicons name="qr-code-outline" size={20} color="#fff" />
              <Text style={styles.btnPrimaryText}> 扫二维码</Text>
            </Pressable>
            <Pressable style={styles.btnSecondary} onPress={() => void onPasteJson()}>
              <Text style={styles.btnSecondaryText}>从剪贴板导入 JSON</Text>
            </Pressable>
          </View>
        </View>

        {scanOn && Platform.OS !== 'web' && (
          <View style={styles.camWrap}>
            <CameraView
              style={styles.camera}
              facing="back"
              barcodeScannerSettings={{ barcodeTypes: ['qr'] }}
              onBarcodeScanned={onBarcodeScanned}
            />
            <Pressable style={styles.camClose} onPress={() => setScanOn(false)}>
              <Text style={styles.btnText}>关闭相机</Text>
            </Pressable>
          </View>
        )}

        <View style={styles.block}>
          <Text style={styles.h2}>绑定地址（可编辑）</Text>
          <Text style={styles.body}>
            格式：`ip/域名:端口`（如 `192.168.21.222:8001`）。保存时会保留当前已存储的 token；若仅手填地址且从未扫码，请确保 token 与 PC 一致。
          </Text>
          <TextInput
            style={styles.input}
            placeholder="ip/域名:端口"
            placeholderTextColor={theme.muted}
            value={hostText}
            onChangeText={setHostText}
            autoCapitalize="none"
            autoCorrect={false}
          />
          <View style={styles.row}>
            <Pressable style={styles.btn} onPress={() => void onSaveHost()}>
              <Text style={styles.btnText}>保存</Text>
            </Pressable>
            <Pressable style={[styles.btn, styles.btnDanger]} onPress={() => void onResetHost()}>
              <Text style={styles.btnText}>删除/重置</Text>
            </Pressable>
          </View>
        </View>

        <View style={styles.block}>
          <Text style={styles.h2}>说明</Text>
          <Text style={styles.body}>推流、转码在 PC 侧执行；手机保存远程控制用的 baseUrl 与 token。</Text>
          {bind && (
            <View style={styles.etActions}>
              <Pressable style={styles.btnSecondary} onPress={() => void copyFull()}>
                <Text style={styles.btnSecondaryText}>复制完整绑定 JSON</Text>
              </Pressable>
            </View>
          )}
        </View>
      </ScrollView>
    </SafeAreaView>
  )
}

const styles = StyleSheet.create({
  safe: { flex: 1, backgroundColor: theme.bg },
  scroll: { padding: 20, paddingBottom: 40 },
  h1: { fontSize: 22, fontWeight: '700', color: theme.text, marginBottom: 8 },
  lead: { fontSize: 14, color: theme.muted, lineHeight: 22, marginBottom: 16 },
  h2: { fontSize: 16, fontWeight: '600', color: theme.text, marginBottom: 8 },
  body: { fontSize: 14, color: theme.muted, lineHeight: 22, marginBottom: 10 },
  block: { marginBottom: 22 },
  card: {
    borderRadius: 12,
    padding: 16,
    marginBottom: 18,
    borderWidth: 1,
    borderColor: theme.border,
  },
  cardTitle: { fontSize: 13, fontWeight: '600', color: theme.accent, marginBottom: 8 },
  mono: { fontFamily: 'monospace', fontSize: 13, color: theme.text, marginBottom: 6 },
  muted: { color: theme.muted, fontSize: 14 },
  mutedSmall: { color: theme.muted, fontSize: 12, marginTop: 6 },
  row: { flexDirection: 'row', gap: 10, marginTop: 12 },
  etRow: { flexDirection: 'row', flexWrap: 'wrap', gap: 10, marginTop: 12 },
  etActions: { gap: 10, marginTop: 12 },
  btn: {
    backgroundColor: theme.bgElevated,
    paddingVertical: 10,
    paddingHorizontal: 14,
    borderRadius: 8,
    borderWidth: 1,
    borderColor: theme.border,
  },
  btnDanger: { backgroundColor: 'rgba(245,101,101,0.15)' },
  btnText: { color: theme.text, fontWeight: '600', fontSize: 14 },
  btnPrimary: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: '#3d7eff',
    paddingVertical: 14,
    borderRadius: 10,
    flex: 1,
    minWidth: '45%',
  },
  btnPrimaryText: { color: '#fff', fontWeight: '700', fontSize: 15 },
  btnSecondary: {
    borderWidth: 1,
    borderColor: theme.border,
    borderRadius: 10,
    paddingVertical: 12,
    paddingHorizontal: 12,
    alignItems: 'center',
    backgroundColor: theme.bgCard,
    flex: 1,
    minWidth: '45%',
  },
  btnSecondaryText: { color: theme.text, fontWeight: '600', fontSize: 13 },
  input: {
    minHeight: 52,
    borderWidth: 1,
    borderColor: theme.border,
    borderRadius: 10,
    padding: 12,
    color: theme.text,
    fontFamily: 'monospace',
    fontSize: 14,
    marginBottom: 12,
    backgroundColor: theme.bgCard,
  },
  camWrap: { borderRadius: 12, overflow: 'hidden', backgroundColor: '#000', marginBottom: 18 },
  camera: { height: 280, width: '100%' },
  camClose: { padding: 12, alignItems: 'center', backgroundColor: '#111' },
  msgBanner: {
    color: theme.success,
    fontSize: 14,
    lineHeight: 22,
    marginBottom: 14,
    padding: 12,
    borderRadius: 10,
    backgroundColor: 'rgba(61,126,255,0.12)',
    borderWidth: 1,
    borderColor: theme.border,
  },
})
