import { useCallback, useEffect, useState, type ReactNode } from 'react'
import {
  View,
  Text,
  ScrollView,
  StyleSheet,
  RefreshControl,
  Pressable,
  TextInput,
  Switch,
  Linking,
} from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'

import { useBind } from '@/context/BindContext'
import { apiFetch } from '@/lib/api'
import type { NetworkPayload, SiteInfo, SpeedBlock } from '@/lib/pcTypes'
import { theme } from '@/constants/theme'

const EMPTY_SITE: SiteInfo = {
  host: '',
  reachable: false,
  latency_ms: -1,
  error: null,
  resolved_ip: null,
  country: null,
  country_code: null,
  geo_error: null,
}

const EMPTY_SPEED: SpeedBlock = {
  label: '',
  download_mbps: null,
  download_error: null,
  download_bytes_sampled: 0,
  upload_mbps: null,
  upload_error: null,
  upload_target: null,
}

const DEFAULT_NET: NetworkPayload = {
  google: EMPTY_SITE,
  douyin: EMPTY_SITE,
  routes: { different: null, note: '' },
  speed: { overseas: EMPTY_SPEED, domestic: EMPTY_SPEED },
}

function fmtMbps(v: number | null | undefined): string {
  if (v == null || Number.isNaN(v)) return '—'
  return `${v.toFixed(2)} Mbps`
}

type ProxyState = { enabled: boolean; http: string; socks: string }

function SiteCard({
  title,
  site,
  speed,
  loading,
  variant,
  onSolution,
}: {
  title: string
  site: SiteInfo
  speed: SpeedBlock
  loading: boolean
  variant: 'google' | 'douyin'
  onSolution?: () => void
}) {
  const ok = site.reachable
  let badge: ReactNode
  if (loading) {
    badge = <Text style={styles.badgePending}>检测中</Text>
  } else if (ok) {
    badge = <Text style={styles.badgeOk}>可访问</Text>
  } else if (variant === 'google' && onSolution) {
    badge = (
      <Pressable onPress={onSolution}>
        <Text style={styles.badgeLink}>查看解决方案</Text>
      </Pressable>
    )
  } else {
    badge = <Text style={styles.badgeBad}>不可访问</Text>
  }

  return (
    <View style={styles.siteCard}>
      <View style={styles.siteHead}>
        <Text style={styles.siteTitle}>{title}</Text>
        {badge}
      </View>
      <View style={[styles.kvCol, loading && styles.dim]}>
        <View style={styles.kvRow}>
          <Text style={styles.k}>延迟</Text>
          <Text style={styles.v}>
            {loading
              ? '—'
              : site.latency_ms != null && site.latency_ms >= 0
                ? `${site.latency_ms.toFixed(0)} ms`
                : '—'}
          </Text>
        </View>
        <View style={styles.kvRow}>
          <Text style={styles.k}>下行（估算）</Text>
          <Text style={styles.v}>{loading ? '—' : fmtMbps(speed.download_mbps)}</Text>
        </View>
        <View style={styles.kvRow}>
          <Text style={styles.k}>上行（估算）</Text>
          <Text style={styles.v}>{loading ? '—' : fmtMbps(speed.upload_mbps)}</Text>
        </View>
        <View style={styles.kvRow}>
          <Text style={styles.k}>解析 IP</Text>
          <Text style={[styles.v, styles.mono]}>{loading ? '—' : site.resolved_ip ?? '—'}</Text>
        </View>
        <View style={styles.kvRow}>
          <Text style={styles.k}>地区（参考）</Text>
          <Text style={styles.v}>
            {loading ? '—' : site.country ?? '—'}
            {!loading && site.country_code ? ` (${site.country_code})` : ''}
          </Text>
        </View>
      </View>
      {!loading && (site.error || site.geo_error) ? (
        <Text style={styles.siteErr}>
          {[site.error, site.geo_error].filter(Boolean).join(' · ')}
        </Text>
      ) : null}
    </View>
  )
}

export default function NetworkScreen() {
  const { bind } = useBind()
  const [data, setData] = useState<NetworkPayload | null>(null)
  const [err, setErr] = useState<string | null>(null)
  const [loading, setLoading] = useState(false)
  const [proxy, setProxy] = useState<ProxyState>({ enabled: false, http: '', socks: '' })
  const [proxyMsg, setProxyMsg] = useState('')
  const [savingProxy, setSavingProxy] = useState(false)
  const [refreshing, setRefreshing] = useState(false)

  const loadNet = useCallback(async () => {
    if (!bind) {
      setErr(null)
      setData(null)
      return
    }
    setErr(null)
    setLoading(true)
    try {
      const r = await apiFetch(bind, '/network_status')
      const json = (await r.json()) as NetworkPayload & { error?: string }
      if (!r.ok) {
        setErr(json.error || `请求失败 ${r.status}`)
        setData(null)
        return
      }
      setData(json)
    } catch (e) {
      setErr(e instanceof Error ? e.message : String(e))
      setData(null)
    } finally {
      setLoading(false)
    }
  }, [bind])

  const loadProxy = useCallback(async () => {
    if (!bind) return
    setProxyMsg('')
    try {
      const pr = await apiFetch(bind, '/proxy_config')
      if (pr.ok) {
        const p = (await pr.json()) as ProxyState
        setProxy({
          enabled: !!p.enabled,
          http: String(p.http || ''),
          socks: String(p.socks || ''),
        })
      }
    } catch {
      /* ignore */
    }
  }, [bind])

  const saveProxy = useCallback(async () => {
    if (!bind) {
      setProxyMsg('请先配对')
      return
    }
    setSavingProxy(true)
    setProxyMsg('')
    try {
      const res = await apiFetch(bind, '/proxy_config', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(proxy),
      })
      if (!res.ok) throw new Error(String(res.status))
      setProxyMsg('已保存。重启直播任务后生效。')
    } catch (e) {
      setProxyMsg(e instanceof Error ? e.message : String(e))
    } finally {
      setSavingProxy(false)
    }
  }, [bind, proxy])

  const loadAll = useCallback(async () => {
    await loadNet()
    await loadProxy()
  }, [loadNet, loadProxy])

  useEffect(() => {
    void loadAll()
  }, [loadAll])

  useEffect(() => {
    if (!bind) return
    const id = setInterval(() => void loadNet(), 45000)
    return () => clearInterval(id)
  }, [bind, loadNet])

  const onRefresh = useCallback(async () => {
    setRefreshing(true)
    await loadAll()
    setRefreshing(false)
  }, [loadAll])

  const view = data ?? DEFAULT_NET

  const openSolution = useCallback(() => {
    void Linking.openURL('https://nomadro.com/')
  }, [])

  return (
    <SafeAreaView style={styles.safe} edges={['bottom']}>
      <ScrollView
        contentContainerStyle={styles.scroll}
        refreshControl={
          bind ? (
            <RefreshControl refreshing={refreshing} onRefresh={() => void onRefresh()} tintColor={theme.accent} />
          ) : undefined
        }
      >
        <Text style={styles.h1}>网络</Text>
        <Text style={styles.lead}>连通与测速（与桌面端「网络仪表盘」同源）。</Text>

        {!bind && (
          <View style={styles.banner}>
            <Text style={styles.bannerText}>未绑定 PC：配对后可检测 Google / 抖音 与测速。</Text>
          </View>
        )}

        <View style={styles.cardNet}>
          <View style={styles.cardHead}>
            <Text style={styles.cardTitle}>网络仪表盘</Text>
            <Pressable style={styles.btnSec} onPress={() => void loadNet()} disabled={!bind || loading}>
              <Text style={styles.btnSecText}>{loading ? '检测中…' : '重新检测'}</Text>
            </Pressable>
          </View>
          {err && bind ? <Text style={styles.err}>{err}</Text> : null}
          <View style={styles.siteRow}>
            <SiteCard
              title="Google（海外参考）"
              site={view.google}
              speed={view.speed.overseas}
              loading={loading && !!bind}
              variant="google"
              onSolution={openSolution}
            />
            <SiteCard
              title="抖音（国内参考）"
              site={view.douyin}
              speed={view.speed.domestic}
              loading={loading && !!bind}
              variant="douyin"
            />
          </View>
          {view.routes?.note ? (
            <Text style={styles.routesNote}>{view.routes.note}</Text>
          ) : null}
        </View>

        <View style={styles.cardProxy}>
          <Text style={styles.cardTitle}>录制专用代理</Text>
          <Text style={styles.desc}>
            仅对本软件拉起的 FFmpeg / 录制进程生效，不会修改系统代理。与桌面端「录制专用代理」一致。
          </Text>
          <View style={styles.rowBetween}>
            <Text style={styles.label}>启用仅录制进程使用的代理</Text>
            <Switch
              value={proxy.enabled}
              disabled={!bind}
              onValueChange={(v) => setProxy((p) => ({ ...p, enabled: v }))}
            />
          </View>
          <Text style={styles.label}>HTTP 代理</Text>
          <TextInput
            style={[styles.input, !bind && styles.inputDisabled]}
            value={proxy.http}
            editable={!!bind}
            onChangeText={(t) => setProxy((p) => ({ ...p, http: t }))}
            placeholder="http://127.0.0.1:7890"
            placeholderTextColor={theme.muted}
            autoCapitalize="none"
          />
          <Text style={styles.label}>SOCKS5</Text>
          <TextInput
            style={[styles.input, !bind && styles.inputDisabled]}
            value={proxy.socks}
            editable={!!bind}
            onChangeText={(t) => setProxy((p) => ({ ...p, socks: t }))}
            placeholder="socks5://127.0.0.1:7890"
            placeholderTextColor={theme.muted}
            autoCapitalize="none"
          />
          <View style={styles.row}>
            <Pressable
              style={[styles.btnPri, (!bind || savingProxy) && styles.btnDisabled]}
              disabled={!bind || savingProxy}
              onPress={() => void saveProxy()}
            >
              <Text style={styles.btnPriText}>{savingProxy ? '保存中…' : '保存'}</Text>
            </Pressable>
            <Pressable style={styles.btnSec} disabled={!bind} onPress={() => void loadProxy()}>
              <Text style={styles.btnSecText}>重新读取</Text>
            </Pressable>
          </View>
          {!!proxyMsg && <Text style={proxyMsg.includes('已保存') ? styles.ok : styles.err}>{proxyMsg}</Text>}
        </View>
      </ScrollView>
    </SafeAreaView>
  )
}

const styles = StyleSheet.create({
  safe: { flex: 1, backgroundColor: theme.bg },
  scroll: { padding: 16, paddingBottom: 40 },
  h1: { fontSize: 20, fontWeight: '700', color: theme.text, marginBottom: 6 },
  lead: { fontSize: 14, color: theme.muted, marginBottom: 14, lineHeight: 22 },
  banner: {
    padding: 12,
    borderRadius: 10,
    backgroundColor: 'rgba(124,92,255,0.08)',
    borderWidth: 1,
    borderColor: 'rgba(124,92,255,0.25)',
    marginBottom: 14,
  },
  bannerText: { fontSize: 13, color: theme.text, lineHeight: 20 },
  cardNet: {
    padding: 14,
    borderRadius: 12,
    backgroundColor: theme.bgCard,
    borderWidth: 1,
    borderColor: 'rgba(124,92,255,0.28)',
    marginBottom: 14,
  },
  cardProxy: {
    padding: 14,
    borderRadius: 12,
    backgroundColor: theme.bgCard,
    borderWidth: 1,
    borderColor: 'rgba(61,214,140,0.22)',
    marginBottom: 14,
  },
  cardHead: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 },
  cardTitle: { fontSize: 16, fontWeight: '600', color: theme.text },
  btnSec: {
    paddingVertical: 8,
    paddingHorizontal: 12,
    borderRadius: 8,
    borderWidth: 1,
    borderColor: theme.border,
    backgroundColor: theme.bgElevated,
  },
  btnSecText: { color: theme.text, fontWeight: '600', fontSize: 13 },
  btnPri: {
    paddingVertical: 10,
    paddingHorizontal: 16,
    borderRadius: 10,
    backgroundColor: '#3d7eff',
  },
  btnPriText: { color: '#fff', fontWeight: '700' },
  btnDisabled: { opacity: 0.5 },
  err: { color: theme.danger, marginBottom: 10, fontSize: 13 },
  ok: { color: theme.success, marginTop: 8, fontSize: 13 },
  siteRow: { gap: 12 },
  siteCard: {
    padding: 12,
    borderRadius: 10,
    backgroundColor: theme.bgElevated,
    borderWidth: 1,
    borderColor: theme.border,
    marginBottom: 4,
  },
  siteHead: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 },
  siteTitle: { fontSize: 14, fontWeight: '600', color: theme.text, flex: 1 },
  badgePending: { fontSize: 11, fontWeight: '700', color: theme.muted },
  badgeOk: { fontSize: 11, fontWeight: '700', color: theme.success },
  badgeBad: { fontSize: 11, fontWeight: '700', color: theme.danger },
  badgeLink: { fontSize: 11, fontWeight: '700', color: theme.accent, textDecorationLine: 'underline' },
  kvCol: { gap: 6 },
  kvRow: { flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', gap: 8 },
  dim: { opacity: 0.72 },
  k: { fontSize: 12, color: theme.muted, fontWeight: '600', marginTop: 4 },
  v: { fontSize: 13, color: theme.text },
  mono: { fontFamily: 'monospace', fontSize: 12 },
  siteErr: { fontSize: 11, color: theme.warn, marginTop: 8, lineHeight: 16 },
  routesNote: { fontSize: 12, color: theme.muted, marginTop: 10, lineHeight: 18 },
  desc: { fontSize: 13, color: theme.muted, lineHeight: 20, marginBottom: 12 },
  rowBetween: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 },
  label: { fontSize: 12, color: theme.muted, marginBottom: 6 },
  input: {
    borderWidth: 1,
    borderColor: theme.border,
    borderRadius: 10,
    padding: 10,
    color: theme.text,
    marginBottom: 12,
    backgroundColor: theme.bg,
  },
  inputDisabled: { opacity: 0.6 },
  row: { flexDirection: 'row', gap: 10, flexWrap: 'wrap', marginTop: 4 },
})
