"use client"

import { useCallback, useEffect, useState } from "react"
import { toast } from "sonner"
import { FormField, FormToggle } from "@/components/form-kit"
import { Alert, AlertDescription, AlertTitle } from "@/components/reui/alert"
import { Badge } from "@/components/reui/badge"
import { OpsPanel } from "@/components/ops-panel"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { CodeExportSheet, type CodeExportFormat } from "@/components/reui-kit/code-export-sheet"
import type { TrafficFlowSettingsDto } from "@mmapp/contracts/traffic-flow"
import {
  generateTrafficFlowKeys,
  getTrafficFlowHostFiles,
  getTrafficFlowSettings,
  purgeTrafficFlowData,
  putTrafficFlowSettings,
} from "@/shared/api/traffic-flow"
import { formatFlowPurgeResult, NetflowPurgeConfirm } from "@/components/traffic/netflow-purge-dialog"
import { KeyRoundIcon, DownloadIcon, InfoIcon } from "lucide-react"

const HOST_STEPS = [
  "На хосте Docker (не в контейнере mmapp-backend): apt install wireguard (или эквивалент).",
  "Скачайте wg-flow.conf и положите в /etc/wireguard/wg-flow.conf.",
  "wg-quick up wg-flow  (или systemctl enable --now wg-quick@wg-flow).",
  "Firewall: разрешите UDP listen WireGuard. UDP 4739 наружу не открывайте.",
  "В docker-compose у backend раскомментируйте bind IPFIX только на адресе wg-flow.",
  "Проверка: wg show · ss -ulnp | grep 4739 · в этой панели — last datagram.",
]

function NetflowSettingsPanel({
  backendUrl,
  enabled,
}: {
  backendUrl: string
  enabled: boolean
}) {
  const [settings, setSettings] = useState<TrafficFlowSettingsDto | null>(null)
  const [busy, setBusy] = useState(false)
  const [exportOpen, setExportOpen] = useState(false)
  const [formats, setFormats] = useState<CodeExportFormat[]>([])
  const [collectorIp, setCollectorIp] = useState("10.255.254.1")
  const [flowPort, setFlowPort] = useState("4739")
  const [wgPort, setWgPort] = useState("51821")
  const [prefix, setPrefix] = useState("10.255.254.0/24")
  const [endpoint, setEndpoint] = useState("")
  const [retention, setRetention] = useState("24")
  const [topN, setTopN] = useState("200")
  const [shareOn, setShareOn] = useState(true)
  const [sharePct, setSharePct] = useState("5")
  const [ingestOn, setIngestOn] = useState(false)
  const [purgeOpen, setPurgeOpen] = useState(false)
  const [purgeBusy, setPurgeBusy] = useState(false)

  const load = useCallback(async () => {
    if (!enabled) return
    const s = await getTrafficFlowSettings(backendUrl)
    setSettings(s)
    setCollectorIp(s.collectorIp)
    setFlowPort(String(s.flowListenPort))
    setWgPort(String(s.wgListenPort))
    setPrefix(s.prefix)
    setEndpoint(s.publicEndpoint)
    setRetention(String(s.retentionHours))
    setTopN(String(s.topN))
    const pct = Number(s.mapServiceMinSharePct ?? 5)
    setShareOn(pct > 0)
    setSharePct(String(pct > 0 ? pct : 5))
    setIngestOn(s.enabled)
  }, [backendUrl, enabled])

  useEffect(() => {
    void load().catch((e: unknown) => {
      toast.error(e instanceof Error ? e.message : "Не удалось загрузить NetFlow")
    })
  }, [load])

  async function handleSave() {
    setBusy(true)
    try {
      const res = await putTrafficFlowSettings(backendUrl, {
        enabled: ingestOn,
        collectorIp,
        flowListenPort: Number.parseInt(flowPort, 10) || 4739,
        wgListenPort: Number.parseInt(wgPort, 10) || 51821,
        prefix,
        publicEndpoint: endpoint,
        retentionHours: Number.parseInt(retention, 10) || 24,
        topN: Number.parseInt(topN, 10) || 200,
        mapServiceMinSharePct: shareOn
          ? Math.min(100, Math.max(1, Number.parseFloat(sharePct) || 5))
          : 0,
      })
      setSettings(res.settings)
      toast.success("Настройки NetFlow сохранены")
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "Не удалось сохранить")
    } finally {
      setBusy(false)
    }
  }

  async function handleKeys() {
    setBusy(true)
    try {
      const res = await generateTrafficFlowKeys(backendUrl)
      setSettings(res.settings)
      toast.success(res.created ? "Ключи хоста созданы" : "Ключи уже есть")
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "Не удалось сгенерировать ключи")
    } finally {
      setBusy(false)
    }
  }

  async function handlePurgeConfirm() {
    setPurgeBusy(true)
    try {
      const result = await purgeTrafficFlowData(backendUrl)
      toast.success(formatFlowPurgeResult(result))
      setPurgeOpen(false)
      await load()
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "Не удалось сбросить NetFlow")
    } finally {
      setPurgeBusy(false)
    }
  }

  async function handleExport() {
    setBusy(true)
    try {
      const res = await getTrafficFlowHostFiles(backendUrl)
      setFormats(res.files.map((f) => ({
        id: f.id,
        label: f.label,
        filename: f.filename,
        code: f.code,
      })))
      setExportOpen(true)
      await load()
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "Не удалось получить файлы")
    } finally {
      setBusy(false)
    }
  }

  return (
    <>
      <OpsPanel
        title="Traffic Flow / NetFlow (IPFIX)"
        description="Дополнение к сбору счётчиков REST. Приём только через WireGuard на хосте Docker MM. Preview: https://reui.io/preview/base/settings-16"
        headerRight={
          <div className="flex items-center gap-2">
            {settings?.listenerBound ? (
              <Badge variant="success">listener {settings.listenerAddress}</Badge>
            ) : (
              <Badge variant="secondary">listener выкл</Badge>
            )}
          </div>
        }
        contentClassName="px-5 py-4 flex flex-col gap-4"
      >
        <Alert>
          <InfoIcon />
          <AlertTitle>Ключи и UDP 4739</AlertTitle>
          <AlertDescription>
            Приватный ключ хранится в SQLite панели, не коммитьте его. Порт IPFIX публикуйте только на адресе wg-flow, не на 0.0.0.0.
          </AlertDescription>
        </Alert>

        <div className="flex items-center gap-3">
          <FormToggle checked={ingestOn} onChange={setIngestOn} />
          <span className="text-sm">Принимать IPFIX</span>
        </div>

        <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
          <FormField label="Collector IP" hint="Адрес в туннеле, куда JH шлёт flow">
            <Input className="font-mono" value={collectorIp} onChange={(e) => setCollectorIp(e.target.value)} />
          </FormField>
          <FormField label="Префикс overlay">
            <Input className="font-mono" value={prefix} onChange={(e) => setPrefix(e.target.value)} />
          </FormField>
          <FormField label="UDP IPFIX">
            <Input className="font-mono" value={flowPort} onChange={(e) => setFlowPort(e.target.value)} />
          </FormField>
          <FormField label="WG listen">
            <Input className="font-mono" value={wgPort} onChange={(e) => setWgPort(e.target.value)} />
          </FormField>
          <FormField label="Публичный endpoint хоста MM" hint="IP или DNS, который видят JH" required>
            <Input className="font-mono" value={endpoint} onChange={(e) => setEndpoint(e.target.value)} placeholder="203.0.113.10" />
          </FormField>
          <FormField label="Public key хоста">
            <Input className="font-mono text-xs" readOnly value={settings?.hostPublicKey || "— сгенерируйте ключи —"} />
          </FormField>
          <FormField label="Хранение (часов)">
            <Input value={retention} onChange={(e) => setRetention(e.target.value)} inputMode="numeric" />
          </FormField>
          <FormField label="Top-N разговоров">
            <Input value={topN} onChange={(e) => setTopN(e.target.value)} inputMode="numeric" />
          </FormField>
          <div className="sm:col-span-2 flex flex-col gap-2">
            <div className="flex items-center gap-3">
              <FormToggle
                checked={shareOn}
                onChange={(on) => {
                  setShareOn(on)
                  if (on && (!sharePct || sharePct === "0")) setSharePct("5")
                }}
              />
              <span className="text-sm">Порог доли на карте</span>
            </div>
            <FormField
              label="Минимум % окна"
              hint="Узел сервиса, если доля байт окна ≥ N%. Выключить — показать все распознанные бренды (макс. 20)"
            >
              <Input
                value={sharePct}
                onChange={(e) => setSharePct(e.target.value)}
                inputMode="decimal"
                disabled={!shareOn}
              />
            </FormField>
          </div>
        </div>

        <p className="text-xs text-muted-foreground">
          Last datagram:{" "}
          {settings?.lastDatagramAt
            ? new Date(settings.lastDatagramAt).toLocaleString("ru-RU")
            : "—"}
          {settings?.lastExporterIp ? ` · ${settings.lastExporterIp}` : ""}
          {settings?.lastError ? ` · ${settings.lastError}` : ""}
        </p>

        <div className="rounded-md border px-4 py-3 flex flex-col gap-2">
          <p className="text-sm font-medium">Туннель на сервере Docker MM</p>
          <ol className="text-xs text-muted-foreground flex flex-col gap-1.5 list-decimal pl-4">
            {HOST_STEPS.map((s) => (
              <li key={s}>{s}</li>
            ))}
          </ol>
        </div>

        <div className="flex flex-wrap gap-2">
          <Button size="sm" disabled={busy || purgeBusy} onClick={() => { void handleSave() }}>
            Сохранить NetFlow
          </Button>
          <Button size="sm" variant="outline" disabled={busy || purgeBusy} onClick={() => { void handleKeys() }}>
            <KeyRoundIcon className="size-4" />
            Ключи хоста
          </Button>
          <Button size="sm" variant="outline" disabled={busy || purgeBusy} onClick={() => { void handleExport() }}>
            <DownloadIcon className="size-4" />
            wg-quick / compose / firewall
          </Button>
        </div>

        <div className="flex items-center justify-between gap-4 rounded-md border border-destructive/30 px-4 py-3">
          <div className="min-w-0">
            <p className="text-sm font-medium">Сбросить данные NetFlow</p>
            <p className="text-xs text-muted-foreground mt-0.5">
              Удалит сессии и агрегаты из SQLite, затем VACUUM. Ключи WG и пиры не трогает.
            </p>
          </div>
          <Button
            size="sm"
            variant="destructive"
            disabled={busy || purgeBusy}
            onClick={() => setPurgeOpen(true)}
          >
            Сбросить
          </Button>
        </div>
      </OpsPanel>

      <CodeExportSheet
        open={exportOpen}
        onClose={() => setExportOpen(false)}
        title="Файлы для хоста Docker MM"
        description="wg-quick, фрагмент compose и firewall. Хост, не контейнер backend."
        formats={formats}
      />

      <NetflowPurgeConfirm
        open={purgeOpen}
        busy={purgeBusy}
        onConfirm={() => { void handlePurgeConfirm() }}
        onCancel={() => { if (!purgeBusy) setPurgeOpen(false) }}
      />
    </>
  )
}

export { NetflowSettingsPanel }
