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

import { useBind } from '@/context/BindContext'
import { DEFAULT_EASYTIER_PEER_URLS, parseBindPayload, type BindPayload } from '@/lib/types'
import {
  checkVpnPermissionGranted,
  isExpoEasyTierVpnAvailable,
  saveAndPrepareTunnel,
} from '@/lib/easyTierVpn'
import { theme } from '@/constants/theme'

const ET_RELEASE = 'https://github.com/EasyTier/EasyTier/releases'
const DEFAULT_BOOTSTRAP_PEER = DEFAULT_EASYTIER_PEER_URLS[0]

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

  const etEmbedded = Platform.OS === 'android' && isExpoEasyTierVpnAvailable()

  const applyPayload = useCallback(
    async (p: BindPayload | null) => {
      if (!p) {
        setMsg('无法解析，请确认扫描的是 PC 端“生成绑定二维码”的 JSON。')
        return
      }
      await setBind(p)
      setMsg(
        etEmbedded
          ? '配对已保存。EasyTier 参数已写入本机，可继续申请 VPN 权限。'
          : '配对已保存。请使用开发构建或正式 APK 完成 Android 原生组网。'
      )
      setScanOn(false)
      scannedRef.current = false
    },
    [etEmbedded, setBind],
  )

  const onBarCode = useCallback(
    async ({ data }: { data: string }) => {
      if (scannedRef.current) return
      scannedRef.current = true
      const p = parseBindPayload(data)
      await applyPayload(p)
    },
    [applyPayload],
  )

  const onPasteApply = useCallback(async () => {
    const p = parseBindPayload(paste.trim())
    await applyPayload(p)
  }, [paste, applyPayload])

  const copyEtJson = useCallback(async () => {
    if (!bind) return
    const chunk = {
      networkName: bind.easytier.networkName,
      networkSecret: bind.easytier.networkSecret,
      peerUrls: bind.easytier.peerUrls,
    }
    await Clipboard.setStringAsync(JSON.stringify(chunk, null, 2))
    setMsg('已复制 EasyTier 组网 JSON。')
  }, [bind])

  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
    try {
      const r = await fetch(`${bind.baseUrl}/health`, {
        headers: bind.token ? { Authorization: `Bearer ${bind.token}` } : undefined,
      })
      const j = await r.json().catch(() => ({}))
      Alert.alert('连接测试', r.ok ? `OK: ${JSON.stringify(j)}` : `HTTP ${r.status}`)
    } catch (e) {
      Alert.alert('连接失败', e instanceof Error ? e.message : String(e))
    }
  }, [bind])

  const retryEmbeddedTunnel = useCallback(async () => {
    if (!bind || !etEmbedded) return
    setEtBusy(true)
    try {
      const r = await saveAndPrepareTunnel(bind.easytier)
      if (r.needsVpnPermission) {
        setMsg('请在系统弹窗中允许本应用建立 VPN，授权后再点“检查 VPN 权限”。')
      } else if (r.ok && r.vpnPermissionGranted) {
        setMsg(
          'VPN 权限已就绪，EasyTier 参数也已保存。桌面端已默认附带官方共享引导节点，外网下更容易发现对端。'
        )
      } else {
        setMsg(`组网准备结果：${JSON.stringify(r)}`)
      }
    } catch (e) {
      setMsg(e instanceof Error ? e.message : String(e))
    } finally {
      setEtBusy(false)
    }
  }, [bind, etEmbedded])

  const checkVpn = useCallback(async () => {
    if (!etEmbedded) return
    setEtBusy(true)
    try {
      const ok = await checkVpnPermissionGranted()
      setMsg(
        ok
          ? 'VPN 权限已授予。若仍无法访问 API，请确认当前安装包已包含完整原生 EasyTier 数据面。'
          : '尚未授予 VPN 权限，请先在系统设置中允许本应用建立 VPN。'
      )
    } finally {
      setEtBusy(false)
    }
  }, [etEmbedded])

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

  const bootstrapPeer = bind?.easytier.peerUrls[0] ?? DEFAULT_BOOTSTRAP_PEER

  return (
    <SafeAreaView style={styles.safe} edges={['bottom']}>
      <ScrollView contentContainerStyle={styles.scroll} keyboardShouldPersistTaps="handled">
        <Text style={styles.h1}>远程配对</Text>
        <Text style={styles.lead}>
          在 PC 控制台“网络 - 远程控制”生成二维码后，用手机扫码导入 `baseUrl`、`token` 和 EasyTier
          参数。桌面端现在会默认附带 EasyTier 官方共享引导节点，户外网络下更容易发现对端。
        </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}>组网名 · {bind.easytier.networkName}</Text>
            <Text style={styles.mutedSmall}>引导节点 · {bootstrapPeer}</Text>
            {bind.easytier.peerUrls.length > 1 && (
              <Text style={styles.mutedSmall}>额外引导节点 · {bind.easytier.peerUrls.length - 1} 个</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>
            {etEmbedded ? (
              <View style={styles.etRow}>
                <Pressable
                  style={[styles.btnSecondary, etBusy && styles.btnDisabled]}
                  disabled={etBusy}
                  onPress={() => void retryEmbeddedTunnel()}
                >
                  <Text style={styles.btnSecondaryText}>重新应用组网参数</Text>
                </Pressable>
                <Pressable
                  style={[styles.btnSecondary, etBusy && styles.btnDisabled]}
                  disabled={etBusy}
                  onPress={() => void checkVpn()}
                >
                  <Text style={styles.btnSecondaryText}>检查 VPN 权限</Text>
                </Pressable>
              </View>
            ) : (
              <Text style={styles.mutedSmall}>
                {Platform.OS === 'ios'
                  ? 'iOS 仍需单独接入 Network Extension 与 EasyTier 原生库。'
                  : '当前运行环境未加载原生模块，例如 Expo Go。请使用开发构建或正式 APK。'}
              </Text>
            )}
          </LinearGradient>
        )}

        <View style={styles.block}>
          <Text style={styles.h2}>说明</Text>
          <Text style={styles.body}>
            推流和 FFmpeg 只在 PC 执行；手机只负责保存控制通道地址与 EasyTier 参数。现在桌面端会默认把
            `tcp://public.easytier.top:11010` 写进 `peerUrls`，减少没有公网 IP 时的发现失败。
          </Text>
          <Text style={styles.body}>
            当前 Android 原生模块已经能保存组网参数并申请 VPN 权限；如果你要完全在 App 内跑 EasyTier
            数据面，下一步还需要把 EasyTier Android 原生库继续接进来。
          </Text>
          <Pressable onPress={() => void Linking.openURL(ET_RELEASE)} style={styles.linkRow}>
            <Ionicons name="open-outline" size={18} color={theme.accent} />
            <Text style={styles.link}>EasyTier 官方发布与文档</Text>
          </Pressable>
          {bind && (
            <View style={styles.etActions}>
              <Pressable style={styles.btnSecondary} onPress={() => void copyEtJson()}>
                <Text style={styles.btnSecondaryText}>复制组网 JSON</Text>
              </Pressable>
              <Pressable style={styles.btnSecondary} onPress={() => void copyFull()}>
                <Text style={styles.btnSecondaryText}>复制完整绑定 JSON</Text>
              </Pressable>
            </View>
          )}
        </View>

        <View style={styles.block}>
          <Text style={styles.h2}>扫码</Text>
          {!scanOn ? (
            <Pressable
              style={styles.btnPrimary}
              onPress={async () => {
                const r = await requestPerm()
                if (!r.granted) {
                  setMsg('需要相机权限才能扫码。')
                  return
                }
                scannedRef.current = false
                setScanOn(true)
              }}
            >
              <Ionicons name="qr-code-outline" size={22} color="#fff" style={{ marginRight: 8 }} />
              <Text style={styles.btnPrimaryText}>打开相机扫描 PC 二维码</Text>
            </Pressable>
          ) : perm?.granted ? (
            <View style={styles.camWrap}>
              <CameraView
                style={styles.camera}
                facing="back"
                onBarcodeScanned={onBarCode}
                barcodeScannerSettings={{ barcodeTypes: ['qr'] }}
              />
              <Pressable style={styles.camClose} onPress={() => setScanOn(false)}>
                <Text style={styles.btnPrimaryText}>关闭相机</Text>
              </Pressable>
            </View>
          ) : (
            <Text style={styles.muted}>没有相机权限。</Text>
          )}
        </View>

        <View style={styles.block}>
          <Text style={styles.h2}>手动粘贴 JSON</Text>
          <TextInput
            style={styles.input}
            multiline
            placeholder="粘贴 PC 端显示的绑定 JSON"
            placeholderTextColor={theme.muted}
            value={paste}
            onChangeText={setPaste}
          />
          <Pressable style={styles.btnPrimary} onPress={() => void onPasteApply()}>
            <Text style={styles.btnPrimaryText}>解析并保存</Text>
          </Pressable>
        </View>

        {!!msg && <Text style={styles.msg}>{msg}</Text>}
      </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,
  },
  btnDisabled: { opacity: 0.55 },
  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,
  },
  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: 120,
    borderWidth: 1,
    borderColor: theme.border,
    borderRadius: 10,
    padding: 12,
    color: theme.text,
    fontFamily: 'monospace',
    fontSize: 12,
    marginBottom: 12,
    backgroundColor: theme.bgCard,
  },
  camWrap: { borderRadius: 12, overflow: 'hidden', backgroundColor: '#000' },
  camera: { height: 280, width: '100%' },
  camClose: { padding: 12, alignItems: 'center', backgroundColor: '#111' },
  linkRow: { flexDirection: 'row', alignItems: 'center', gap: 6, marginVertical: 8 },
  link: { color: theme.accent, fontSize: 14 },
  msg: { color: theme.success, fontSize: 14, marginTop: 8 },
})
