import { useCallback, useEffect, useState } from 'react'
import {
  clipboardSetText,
  tunnelStatus,
  tunnelSetMaster,
  tunnelSetSecret,
  tunnelAdd,
  tunnelUpdate,
  tunnelRemove,
  tunnelToggle
} from '../ipc'
import type { TunnelStatus, TunnelEntry } from '../ipc'
import type { Config } from '../types'
import type { View } from '../App'
import { Modal, ConfirmDialog } from './Modal'
import { IconPlus } from './Icons'

// 子域名前缀校验：合法 DNS 标签（后端亦二次校验，前端仅为体验）
const SUB_RE = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/

interface EditState {
  id: string | null
  subdomain: string
  port: string
}

export function TunnelsPage({ config, onNavigate }: { config: Config; onNavigate: (v: View) => void }) {
  const relayOn = config.settings.mobileRelayEnabled
  const [st, setSt] = useState<TunnelStatus | null>(null)
  const [editing, setEditing] = useState<EditState | null>(null)
  const [deleting, setDeleting] = useState<TunnelEntry | null>(null)
  const [err, setErr] = useState('')
  const [copied, setCopied] = useState<string | null>(null)
  const [secretText, setSecretText] = useState('')

  const refresh = useCallback(async () => {
    try {
      setSt(await tunnelStatus())
    } catch {
      /* 忽略轮询错误 */
    }
  }, [])

  // 中继开启时轮询状态（活/离线、在线、密钥）；关闭则不请求
  useEffect(() => {
    if (!relayOn) return
    void refresh()
    const t = setInterval(() => void refresh(), 1500)
    return () => clearInterval(t)
  }, [refresh, relayOn])

  // 门禁：中继未开 → 只显示提示卡片
  if (!relayOn) {
    return (
      <div className="page" style={{ maxWidth: 720 }}>
        <h2>隧道管理</h2>
        <p className="page-desc">把本机本地 HTTP 端口以子域名映射到公网，供临时预览（用完即关）</p>
        <div className="settings-group">
          <div className="settings-row">
            <div className="settings-label">
              隧道功能需先开启「公网中继」
              <div className="sub">在设置页开启公网中继并填写中继地址后，本页即可用。</div>
            </div>
            <button className="btn" onClick={() => onNavigate({ kind: 'settings' })}>
              去设置开启
            </button>
          </div>
        </div>
      </div>
    )
  }

  const submit = async () => {
    if (!editing) return
    const sub = editing.subdomain.trim().toLowerCase()
    const port = Number(editing.port)
    if (!SUB_RE.test(sub)) {
      setErr('子域名前缀只能含小写字母/数字/连字符，首尾为字母或数字')
      return
    }
    if (st?.entries.some((x) => x.subdomain.toLowerCase() === sub && x.id !== editing.id)) {
      setErr('该子域名前缀已存在')
      return
    }
    if (!Number.isInteger(port) || port < 1 || port > 65535) {
      setErr('本地端口需为 1-65535 的整数')
      return
    }
    setErr('')
    try {
      const next = editing.id ? await tunnelUpdate(editing.id, sub, port) : await tunnelAdd(sub, port)
      setSt(next)
      setEditing(null)
    } catch (e) {
      setErr(String(e))
    }
  }

  const badgeOf = (en: TunnelEntry) => {
    if (!en.enabled) return { text: '已停用', color: 'var(--text-faint)' }
    if (en.conflict) return { text: '前缀冲突', color: 'var(--danger)' }
    if (en.active) return { text: '活跃', color: 'var(--ok)' }
    return { text: '离线', color: 'var(--text-faint)' }
  }

  return (
    <div className="page" style={{ maxWidth: 720 }}>
      <h2>隧道管理</h2>
      <p className="page-desc">
        映射本地 HTTP 端口到 https://前缀.{st?.baseDomain || '你的域名'}/ —— 桌面在线且映射开启时才可访问，用完即关
      </p>
      {err && (
        <div style={{ color: 'var(--danger)', marginBottom: 10 }} onClick={() => setErr('')}>
          {err}
        </div>
      )}

      <div className="settings-group">
        <div className="settings-row">
          <div className="settings-label">
            整体隧道开关
            <div className="sub">中继连接：{st?.online ? '已拨通' : '未连接'}</div>
          </div>
          <button
            className={`switch ${st?.enabled ? 'on' : ''}`}
            onClick={async () => {
              try {
                setSt(await tunnelSetMaster(!st?.enabled))
              } catch (e) {
                setErr(String(e))
              }
            }}
          />
        </div>
        <div className="settings-row">
          <div className="settings-label">
            隧道注册密钥
            <div className="sub">
              须与中继的 TUNNEL_SECRET 一致，不匹配中继将拒绝注册。
              {st?.secretSet ? '（已设置，重填即覆盖）' : '（尚未设置）'}
            </div>
          </div>
          <input
            className="input"
            type="password"
            style={{ width: 240, fontFamily: 'var(--font-mono)' }}
            placeholder={st?.secretSet ? '已设置' : '粘贴注册密钥'}
            value={secretText}
            onChange={(e) => setSecretText(e.target.value)}
            onBlur={async () => {
              const v = secretText.trim()
              if (!v) return
              try {
                setSt(await tunnelSetSecret(v))
                setSecretText('')
              } catch (e) {
                setErr(String(e))
              }
            }}
          />
        </div>
      </div>

      <div className="settings-group">
        {st?.entries.map((en) => {
          const b = badgeOf(en)
          return (
            <div className="settings-row" key={en.id}>
              <div className="settings-label" style={{ minWidth: 0 }}>
                <span style={{ fontFamily: 'var(--font-mono)' }}>{en.subdomain}</span>
                <span className="badge" style={{ marginLeft: 8 }}>
                  :{en.localPort}
                </span>
                <span className="badge" style={{ marginLeft: 6, color: b.color }}>
                  {b.text}
                </span>
                <div className="sub" style={{ userSelect: 'text', wordBreak: 'break-all' }}>
                  {en.url}
                </div>
              </div>
              <button
                className="btn ghost small"
                onClick={async () => {
                  await clipboardSetText(en.url)
                  setCopied(en.id)
                  setTimeout(() => setCopied(null), 1200)
                }}
              >
                {copied === en.id ? '已复制' : '复制'}
              </button>
              <button
                className={`switch ${en.enabled ? 'on' : ''}`}
                title={en.enabled ? '停用' : '启用'}
                onClick={async () => {
                  try {
                    setSt(await tunnelToggle(en.id, !en.enabled))
                  } catch (e) {
                    setErr(String(e))
                  }
                }}
              />
              <button
                className="btn ghost small"
                onClick={() => {
                  setErr('')
                  setEditing({ id: en.id, subdomain: en.subdomain, port: String(en.localPort) })
                }}
              >
                编辑
              </button>
              <button className="btn ghost small" onClick={() => setDeleting(en)}>
                删除
              </button>
            </div>
          )
        })}
        {st && st.entries.length === 0 && (
          <div className="settings-row">
            <div className="sub">还没有映射，点下方「新增映射」创建。</div>
          </div>
        )}
      </div>

      <button
        className="btn"
        onClick={() => {
          setErr('')
          setEditing({ id: null, subdomain: '', port: '' })
        }}
      >
        <IconPlus /> 新增映射
      </button>

      {editing && (
        <Modal
          title={editing.id ? '编辑映射' : '新增映射'}
          onClose={() => setEditing(null)}
          footer={
            <>
              <button className="btn" onClick={() => setEditing(null)}>
                取消
              </button>
              <button className="btn primary" onClick={() => void submit()}>
                保存
              </button>
            </>
          }
        >
          <div style={{ marginBottom: 12 }}>
            <div className="settings-label">子域名前缀</div>
            <input
              className="input"
              style={{ width: '100%', marginTop: 4 }}
              placeholder="如 demo"
              value={editing.subdomain}
              onChange={(e) => setEditing({ ...editing, subdomain: e.target.value })}
            />
            <div className="sub" style={{ marginTop: 4 }}>
              公网地址：https://{editing.subdomain.trim() || '前缀'}.{st?.baseDomain || '你的域名'}/
            </div>
          </div>
          <div>
            <div className="settings-label">本地端口</div>
            <input
              className="input"
              style={{ width: 160, marginTop: 4 }}
              placeholder="如 5173"
              value={editing.port}
              onChange={(e) => setEditing({ ...editing, port: e.target.value.replace(/[^0-9]/g, '') })}
            />
          </div>
          {err && <div style={{ color: 'var(--danger)', marginTop: 10 }}>{err}</div>}
        </Modal>
      )}

      {deleting && (
        <ConfirmDialog
          title="删除映射"
          danger
          confirmText="删除"
          message={`确认删除 ${deleting.subdomain}（:${deleting.localPort}）？`}
          onCancel={() => setDeleting(null)}
          onConfirm={async () => {
            try {
              setSt(await tunnelRemove(deleting.id))
            } catch (e) {
              setErr(String(e))
            }
            setDeleting(null)
          }}
        />
      )}
    </div>
  )
}
