"use client"

import { useState, useMemo } from "react"
import { PageHeader } from "@/components/page-header"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import {
  Sheet, SheetContent, SheetHeader, SheetTitle, SheetFooter,
} from "@/components/ui/sheet"
import {
  BellIcon, BellOffIcon, RefreshCwIcon, PlusIcon,
  CableIcon, NetworkIcon, RouteIcon, UserIcon, ServerIcon,
  TimerIcon, WifiOffIcon, TrendingDownIcon,
  EyeIcon, EyeOffIcon, CopyIcon, SendIcon, CheckIcon, XIcon,
  Trash2Icon,
} from "lucide-react"
import { cn } from "@/lib/utils"

// ─── types ────────────────────────────────────────────────────────────────────

type AlertType     = "gre-tunnel" | "bgp-peer" | "bgp-prefix" | "gre-client" | "server" | "rtt" | "loss" | "traffic"
type AlertSeverity = "critical" | "warning" | "info"
type AlertCooldown = "1м" | "5м" | "15м" | "1ч" | "4ч" | "24ч"

interface AlertRule {
  id: string
  name: string
  type: AlertType
  target: string       // display label
  condition: string    // display label
  severity: AlertSeverity
  enabled: boolean
  cooldown: AlertCooldown
  lastFired: string | null   // relative time string
  chatId: string             // override; empty = use global
}

interface HistoryEntry {
  id: string
  ruleName: string
  severity: AlertSeverity
  message: string
  time: string
  sent: boolean
}

interface TelegramConfig {
  token: string
  chatId: string
  connected: boolean
}

// ─── static config ────────────────────────────────────────────────────────────

const TYPE_META: Record<AlertType, {
  Icon: React.FC<{ className?: string }>
  label: string
  iconClass: string
  bg: string
}> = {
  "gre-tunnel": { Icon: CableIcon,        label: "GRE-туннель",    iconClass: "text-violet-500",  bg: "bg-violet-500/10"  },
  "bgp-peer":   { Icon: NetworkIcon,      label: "BGP-сосед",      iconClass: "text-blue-500",    bg: "bg-blue-500/10"    },
  "bgp-prefix": { Icon: RouteIcon,        label: "BGP-префикс",    iconClass: "text-sky-500",     bg: "bg-sky-500/10"     },
  "gre-client": { Icon: UserIcon,         label: "GRE-клиент",     iconClass: "text-purple-500",  bg: "bg-purple-500/10"  },
  "server":     { Icon: ServerIcon,       label: "Сервер",         iconClass: "text-slate-500",   bg: "bg-slate-500/10"   },
  "rtt":        { Icon: TimerIcon,        label: "Задержка (RTT)", iconClass: "text-amber-500",   bg: "bg-amber-500/10"   },
  "loss":       { Icon: WifiOffIcon,      label: "Потери пакетов", iconClass: "text-orange-500",  bg: "bg-orange-500/10"  },
  "traffic":    { Icon: TrendingDownIcon, label: "Низкий трафик",  iconClass: "text-rose-500",    bg: "bg-rose-500/10"    },
}

const SEVERITY_META: Record<AlertSeverity, { label: string; dot: string; badge: string; chip: string }> = {
  critical: {
    label: "Критическое",
    dot:   "bg-red-500",
    badge: "bg-red-100 text-red-700 dark:bg-red-950 dark:text-red-400",
    chip:  "border-red-400 bg-red-500/10 text-red-600 dark:text-red-400",
  },
  warning: {
    label: "Предупреждение",
    dot:   "bg-amber-400",
    badge: "bg-amber-100 text-amber-700 dark:bg-amber-950 dark:text-amber-400",
    chip:  "border-amber-400 bg-amber-500/10 text-amber-600 dark:text-amber-400",
  },
  info: {
    label: "Информационное",
    dot:   "bg-blue-500",
    badge: "bg-blue-100 text-blue-700 dark:bg-blue-950 dark:text-blue-400",
    chip:  "border-blue-400 bg-blue-500/10 text-blue-600 dark:text-blue-400",
  },
}

const TYPE_TARGETS: Record<AlertType, string[]> = {
  "gre-tunnel": ["gre-ivanov-01 / core-01", "gre-ivanov-01 / lab-01", "gre-ivanov-02 / core-01", "gre-ivanov-03 / lab-01", "gre-petrov-01 / core-01", "gre-petrov-01 / lab-01", "gre-kozlov-01 / core-01"],
  "bgp-peer":   ["mt-msk-core-01", "mt-spb-edge-01", "mt-fra-edge-01", "mt-ams-edge-01", "mt-sgp-edge-01", "mt-ams-test-01", "mt-msk-lab-01"],
  "bgp-prefix": ["любой префикс", "185.13.0.0/22", "77.88.8.0/24", "8.8.8.0/24", "1.1.1.0/24"],
  "gre-client": ["gre-ivanov-01", "gre-ivanov-02", "gre-ivanov-03", "gre-petrov-01", "gre-kozlov-01"],
  "server":     ["mt-msk-core-01", "mt-spb-edge-01", "mt-fra-edge-01", "mt-ams-edge-01", "mt-sgp-edge-01", "mt-ams-test-01", "mt-msk-lab-01"],
  "rtt":        ["mt-msk-core-01 → 8.8.8.8", "mt-spb-edge-01 → 8.8.8.8", "mt-fra-edge-01 → 8.8.8.8", "mt-ams-edge-01 → 1.1.1.1", "mt-sgp-edge-01 → 1.1.1.1"],
  "loss":       ["mt-msk-core-01 → 8.8.8.8", "mt-spb-edge-01 → 8.8.8.8", "mt-fra-edge-01 → 8.8.8.8", "mt-ams-edge-01 → 1.1.1.1", "mt-sgp-edge-01 → 1.1.1.1"],
  "traffic":    ["mt-msk-core-01", "mt-spb-edge-01", "mt-fra-edge-01", "mt-ams-edge-01", "mt-sgp-edge-01", "mt-ams-test-01", "mt-msk-lab-01"],
}

const TYPE_CONDITIONS: Record<AlertType, string[]> = {
  "gre-tunnel": ["перешёл в offline", "восстановился"],
  "bgp-peer":   ["разорвал сессию", "восстановил сессию"],
  "bgp-prefix": ["был отозван", "был получен"],
  "gre-client": ["отключился", "подключился"],
  "server":     ["перешёл в offline", "перешёл в degraded", "восстановился"],
  "rtt":        ["> порога", "< порога"],
  "loss":       ["> порога"],
  "traffic":    ["RX < порога", "TX < порога"],
}

const THRESHOLD_UNIT: Partial<Record<AlertType, string>> = {
  rtt:     "мс",
  loss:    "%",
  traffic: "Мбит/с",
}

const COOLDOWNS: AlertCooldown[] = ["1м", "5м", "15м", "1ч", "4ч", "24ч"]

// ─── mock data ────────────────────────────────────────────────────────────────

const INIT_RULES: AlertRule[] = [
  { id: "r1", name: "GRE-туннель Иванов offline",   type: "gre-tunnel", target: "gre-ivanov-01 / core-01",      condition: "перешёл в offline",    severity: "critical", enabled: true,  cooldown: "5м",  lastFired: "3ч назад",   chatId: "" },
  { id: "r2", name: "BGP-сосед core-01 down",       type: "bgp-peer",   target: "mt-msk-core-01",               condition: "разорвал сессию",       severity: "critical", enabled: true,  cooldown: "15м", lastFired: "1д назад",   chatId: "" },
  { id: "r3", name: "Высокая задержка FRA",          type: "rtt",        target: "mt-fra-edge-01 → 8.8.8.8",    condition: "> 120 мс",              severity: "warning",  enabled: true,  cooldown: "15м", lastFired: "45м назад",  chatId: "" },
  { id: "r4", name: "Потери пакетов AMS",            type: "loss",       target: "mt-ams-edge-01 → 1.1.1.1",    condition: "> 5%",                  severity: "warning",  enabled: true,  cooldown: "5м",  lastFired: null,         chatId: "" },
  { id: "r5", name: "Сервер SGP offline",            type: "server",     target: "mt-sgp-edge-01",               condition: "перешёл в offline",    severity: "critical", enabled: true,  cooldown: "1ч",  lastFired: "2д назад",   chatId: "" },
  { id: "r6", name: "BGP-префикс отозван core-01",  type: "bgp-prefix", target: "любой префикс",                condition: "был отозван",           severity: "info",     enabled: true,  cooldown: "5м",  lastFired: "6ч назад",   chatId: "-1009876543210" },
  { id: "r7", name: "GRE-клиент Козлов offline",    type: "gre-client", target: "gre-kozlov-01",                condition: "отключился",            severity: "warning",  enabled: false, cooldown: "1ч",  lastFired: null,         chatId: "" },
  { id: "r8", name: "Низкий трафик AMS-edge",       type: "traffic",    target: "mt-ams-edge-01",               condition: "RX < 10 Мбит/с",       severity: "info",     enabled: false, cooldown: "4ч",  lastFired: null,         chatId: "" },
]

const INIT_HISTORY: HistoryEntry[] = [
  { id: "h1", ruleName: "Высокая задержка FRA",         severity: "warning",  message: "RTT mt-fra-edge-01 → 8.8.8.8: 137 мс (порог 120 мс)",  time: "45м назад",  sent: true  },
  { id: "h2", ruleName: "GRE-туннель Иванов offline",   severity: "critical", message: "gre-ivanov-01 / core-01 перешёл в offline",              time: "3ч назад",   sent: true  },
  { id: "h3", ruleName: "BGP-префикс отозван core-01",  severity: "info",     message: "Префикс 185.13.0.0/22 отозван на mt-msk-core-01",        time: "6ч назад",   sent: true  },
  { id: "h4", ruleName: "BGP-сосед core-01 down",       severity: "critical", message: "BGP-сессия с mt-msk-core-01 разорвана",                  time: "1д назад",   sent: true  },
  { id: "h5", ruleName: "Сервер SGP offline",            severity: "critical", message: "mt-sgp-edge-01 недоступен, ping timeout",                time: "2д назад",   sent: false },
]

const INIT_TG: TelegramConfig = {
  token: "7412358964:AAFkL9xZqBb2pC8nYrVtHmwKjXeOdSuN1A",
  chatId: "-1001234567890",
  connected: true,
}

// ─── small helpers ────────────────────────────────────────────────────────────

function Toggle({ checked, onChange }: { checked: boolean; onChange: (v: boolean) => void }) {
  return (
    <button role="switch" aria-checked={checked} onClick={() => onChange(!checked)}
      className={cn(
        "relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors",
        checked ? "bg-primary" : "bg-muted-foreground/30",
      )}>
      <span className={cn(
        "inline-block h-3.5 w-3.5 rounded-full bg-white shadow transition-transform",
        checked ? "translate-x-4" : "translate-x-0.5",
      )} />
    </button>
  )
}

function FieldLabel({ children }: { children: React.ReactNode }) {
  return <p className="text-sm font-medium mb-1.5 leading-none">{children}</p>
}

function FieldHint({ children }: { children: React.ReactNode }) {
  return <p className="text-xs text-muted-foreground mt-1.5">{children}</p>
}

function NativeSelect({ value, onChange, children, className }: {
  value: string; onChange: (v: string) => void; children: React.ReactNode; className?: string
}) {
  return (
    <select
      value={value}
      onChange={e => onChange(e.target.value)}
      className={cn(
        "h-8 w-full min-w-0 rounded-lg border border-input bg-background px-2.5 py-1",
        "text-sm text-foreground transition-colors outline-none",
        "focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50",
        className,
      )}
    >
      {children}
    </select>
  )
}

function SeverityDot({ severity }: { severity: AlertSeverity }) {
  return <span className={cn("inline-block size-2 rounded-full shrink-0", SEVERITY_META[severity].dot)} />
}

function SeverityBadge({ severity }: { severity: AlertSeverity }) {
  return (
    <span className={cn("text-[10px] px-1.5 py-0.5 rounded-full font-medium whitespace-nowrap", SEVERITY_META[severity].badge)}>
      {severity === "critical" ? "Критич." : severity === "warning" ? "Предупр." : "Инфо"}
    </span>
  )
}

// ─── alert rule row ───────────────────────────────────────────────────────────

function AlertRuleRow({ rule, onToggle, onDelete }: {
  rule: AlertRule
  onToggle: (id: string, enabled: boolean) => void
  onDelete: (id: string) => void
}) {
  const { Icon, iconClass, bg } = TYPE_META[rule.type]

  return (
    <div className={cn(
      "flex items-center gap-3 px-4 py-3 hover:bg-muted/20 transition-colors group",
      !rule.enabled && "opacity-55",
    )}>
      {/* toggle */}
      <Toggle checked={rule.enabled} onChange={v => onToggle(rule.id, v)} />

      {/* severity dot */}
      <SeverityDot severity={rule.severity} />

      {/* type icon */}
      <div className={cn("size-7 rounded-md flex items-center justify-center shrink-0", bg)}>
        <Icon className={cn("size-3.5", iconClass)} />
      </div>

      {/* name + target */}
      <div className="flex-1 min-w-0">
        <p className="text-sm font-medium truncate">{rule.name}</p>
        <p className="text-[11px] text-muted-foreground truncate">
          {TYPE_META[rule.type].label} · <span className="font-mono">{rule.target}</span>
          {" · "}{rule.condition}
        </p>
      </div>

      {/* cooldown */}
      <span className="text-[10px] font-mono px-1.5 py-0.5 rounded bg-muted text-muted-foreground shrink-0">
        {rule.cooldown}
      </span>

      {/* chat override badge */}
      {rule.chatId && (
        <span className="text-[10px] font-mono px-1.5 py-0.5 rounded border border-border text-muted-foreground hidden xl:inline shrink-0">
          #{rule.chatId.slice(-6)}
        </span>
      )}

      {/* last fired */}
      <span className={cn(
        "text-[11px] shrink-0 w-[80px] text-right",
        rule.lastFired ? "text-muted-foreground" : "text-muted-foreground/40",
      )}>
        {rule.lastFired ?? "—"}
      </span>

      {/* severity badge */}
      <div className="hidden lg:block shrink-0">
        <SeverityBadge severity={rule.severity} />
      </div>

      {/* actions (visible on hover) */}
      <div className="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity shrink-0">
        <button
          onClick={() => onDelete(rule.id)}
          className="size-7 rounded flex items-center justify-center text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-colors">
          <Trash2Icon className="size-3.5" />
        </button>
      </div>
    </div>
  )
}

// ─── telegram config card ─────────────────────────────────────────────────────

function TelegramCard({ cfg, onChange }: {
  cfg: TelegramConfig
  onChange: (c: TelegramConfig) => void
}) {
  const [showToken, setShowToken] = useState(false)
  const [testing, setTesting]     = useState(false)
  const [testResult, setTestResult] = useState<"ok" | "fail" | null>(null)

  const handleTest = () => {
    setTesting(true)
    setTestResult(null)
    setTimeout(() => {
      setTesting(false)
      setTestResult(cfg.connected ? "ok" : "fail")
      setTimeout(() => setTestResult(null), 3000)
    }, 1400)
  }

  const _maskedToken = cfg.token.replace(/:.+/, ":••••••••••••••••••••••••")

  return (
    <Card>
      <CardHeader className="pb-3 pt-4 px-4">
        <CardTitle className="text-sm flex items-center justify-between">
          <span className="flex items-center gap-2">
            <span className="text-base">✈️</span> Telegram
          </span>
          <span className={cn(
            "flex items-center gap-1.5 text-[11px] font-normal px-2 py-0.5 rounded-full",
            cfg.connected
              ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-950 dark:text-emerald-400"
              : "bg-muted text-muted-foreground",
          )}>
            <span className={cn("size-1.5 rounded-full", cfg.connected ? "bg-emerald-500" : "bg-muted-foreground")} />
            {cfg.connected ? "Подключён" : "Не настроен"}
          </span>
        </CardTitle>
      </CardHeader>
      <CardContent className="px-4 pb-4 space-y-3">

        {/* bot token */}
        <div>
          <FieldLabel>Bot Token</FieldLabel>
          <div className="flex gap-1.5">
            <Input
              type={showToken ? "text" : "password"}
              value={cfg.token}
              onChange={e => onChange({ ...cfg, token: e.target.value })}
              className="text-xs font-mono h-8"
              placeholder="1234567890:AAF..."
            />
            <button
              onClick={() => setShowToken(v => !v)}
              className="size-8 rounded-md border border-input flex items-center justify-center text-muted-foreground hover:text-foreground hover:bg-muted transition-colors shrink-0">
              {showToken ? <EyeOffIcon className="size-3.5" /> : <EyeIcon className="size-3.5" />}
            </button>
            <button
              onClick={() => navigator.clipboard.writeText(cfg.token)}
              className="size-8 rounded-md border border-input flex items-center justify-center text-muted-foreground hover:text-foreground hover:bg-muted transition-colors shrink-0">
              <CopyIcon className="size-3.5" />
            </button>
          </div>
        </div>

        {/* default chat id */}
        <div>
          <FieldLabel>Chat ID по умолчанию</FieldLabel>
          <Input
            value={cfg.chatId}
            onChange={e => onChange({ ...cfg, chatId: e.target.value })}
            className="text-xs font-mono h-8"
            placeholder="-100xxxxxxxxxx"
          />
          <p className="text-[10px] text-muted-foreground mt-1">
            Для групп используйте отрицательный ID. Каждое правило может переопределить.
          </p>
        </div>

        {/* test button */}
        <Button
          size="sm" variant="outline" className="w-full h-8 text-xs gap-2"
          onClick={handleTest} disabled={testing}>
          {testing ? (
            <RefreshCwIcon className="size-3.5 animate-spin" />
          ) : testResult === "ok" ? (
            <CheckIcon className="size-3.5 text-emerald-500" />
          ) : testResult === "fail" ? (
            <XIcon className="size-3.5 text-destructive" />
          ) : (
            <SendIcon className="size-3.5" />
          )}
          {testing ? "Отправка…"
            : testResult === "ok" ? "Сообщение отправлено"
            : testResult === "fail" ? "Ошибка отправки"
            : "Отправить тестовое сообщение"}
        </Button>
      </CardContent>
    </Card>
  )
}

// ─── history card ─────────────────────────────────────────────────────────────

function HistoryCard({ entries }: { entries: HistoryEntry[] }) {
  return (
    <Card>
      <CardHeader className="pb-2 pt-4 px-4">
        <CardTitle className="text-sm">Журнал срабатываний</CardTitle>
      </CardHeader>
      <CardContent className="px-4 pb-4">
        {entries.length === 0 ? (
          <p className="text-xs text-muted-foreground py-2">Нет срабатываний</p>
        ) : (
          <div className="flex flex-col gap-2.5">
            {entries.map(e => (
              <div key={e.id} className="flex gap-2.5 items-start">
                <SeverityDot severity={e.severity} />
                <div className="flex-1 min-w-0">
                  <p className="text-[11px] font-medium leading-tight truncate">{e.ruleName}</p>
                  <p className="text-[10px] text-muted-foreground leading-snug mt-0.5 line-clamp-2">{e.message}</p>
                </div>
                <div className="text-right shrink-0">
                  <p className="text-[10px] text-muted-foreground whitespace-nowrap">{e.time}</p>
                  <span className={cn(
                    "text-[9px] font-medium px-1 py-0.5 rounded mt-0.5 inline-block",
                    e.sent
                      ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-950 dark:text-emerald-400"
                      : "bg-red-100 text-red-700 dark:bg-red-950 dark:text-red-400",
                  )}>
                    {e.sent ? "✓ отправлено" : "✗ ошибка"}
                  </span>
                </div>
              </div>
            ))}
          </div>
        )}
      </CardContent>
    </Card>
  )
}

// ─── add rule sheet ───────────────────────────────────────────────────────────

const BLANK_FORM = {
  name:      "",
  type:      "gre-tunnel" as AlertType,
  target:    "",
  condition: "",
  threshold: "",
  severity:  "warning" as AlertSeverity,
  cooldown:  "5м" as AlertCooldown,
  chatId:    "",
}

function AddRuleSheet({ open, onClose, onSave }: {
  open: boolean
  onClose: () => void
  onSave: (rule: Omit<AlertRule, "id" | "lastFired" | "enabled">) => void
}) {
  const [form, setForm] = useState({ ...BLANK_FORM })

  // reset when open
  const handleOpen = (o: boolean) => { if (o) setForm({ ...BLANK_FORM }) }

  const targets    = TYPE_TARGETS[form.type]
  const conditions = TYPE_CONDITIONS[form.type]
  const unit       = THRESHOLD_UNIT[form.type]

  const conditionDisplay = unit && form.threshold
    ? `${form.condition.replace("порога", form.threshold + " " + unit)}`
    : form.condition

  const canSave = form.name.trim() && form.target && form.condition && (!unit || form.threshold)

  const handleSave = () => {
    if (!canSave) return
    onSave({
      name:      form.name.trim(),
      type:      form.type,
      target:    form.target,
      condition: conditionDisplay || form.condition,
      severity:  form.severity,
      cooldown:  form.cooldown,
      chatId:    form.chatId.trim(),
    })
    onClose()
  }

  return (
    <Sheet open={open} onOpenChange={o => { if (!o) onClose(); handleOpen(o) }}>
      {/* p-0 + gap-0: we control all spacing internally */}
      <SheetContent className="flex flex-col overflow-hidden p-0 gap-0 sm:max-w-md">

        {/* ── fixed header ── */}
        <SheetHeader className="shrink-0 px-6 pt-5 pb-4 border-b">
          <SheetTitle className="flex items-center gap-2 text-base">
            <BellIcon className="size-4" />
            Новое правило оповещения
          </SheetTitle>
        </SheetHeader>

        {/* ── scrollable body ── */}
        <div className="flex-1 overflow-y-auto px-6 py-5 flex flex-col gap-5">

          {/* name */}
          <div className="flex flex-col gap-1.5">
            <FieldLabel>Название правила</FieldLabel>
            <Input
              placeholder="Например: GRE-туннель Иванов offline"
              value={form.name}
              onChange={e => setForm(f => ({ ...f, name: e.target.value }))}
            />
          </div>

          {/* type */}
          <div className="flex flex-col gap-1.5">
            <FieldLabel>Тип события</FieldLabel>
            <NativeSelect
              value={form.type}
              onChange={v => setForm(f => ({ ...f, type: v as AlertType, target: "", condition: "", threshold: "" }))}
            >
              {(Object.entries(TYPE_META) as [AlertType, typeof TYPE_META[AlertType]][]).map(([t, m]) => (
                <option key={t} value={t}>{m.label}</option>
              ))}
            </NativeSelect>
          </div>

          {/* target + condition on same row when both are simple selects */}
          <div className="grid grid-cols-2 gap-3">
            <div className="flex flex-col gap-1.5">
              <FieldLabel>Объект</FieldLabel>
              <NativeSelect value={form.target} onChange={v => setForm(f => ({ ...f, target: v }))}>
                <option value="" disabled>— выбрать —</option>
                {targets.map(t => <option key={t} value={t}>{t}</option>)}
              </NativeSelect>
            </div>
            <div className="flex flex-col gap-1.5">
              <FieldLabel>Условие</FieldLabel>
              <NativeSelect value={form.condition} onChange={v => setForm(f => ({ ...f, condition: v }))}>
                <option value="" disabled>— выбрать —</option>
                {conditions.map(c => <option key={c} value={c}>{c}</option>)}
              </NativeSelect>
            </div>
          </div>

          {/* threshold — only for RTT / loss / traffic */}
          {unit && (
            <div className="flex flex-col gap-1.5">
              <FieldLabel>Пороговое значение</FieldLabel>
              <div className="flex items-center gap-0">
                <Input
                  type="number" min="0"
                  value={form.threshold}
                  onChange={e => setForm(f => ({ ...f, threshold: e.target.value }))}
                  className="rounded-r-none"
                  placeholder="0"
                />
                <span className="h-8 px-3 flex items-center rounded-r-lg border border-l-0 border-input
                  bg-muted text-sm text-muted-foreground shrink-0">
                  {unit}
                </span>
              </div>
            </div>
          )}

          {/* severity — vertical radio cards */}
          <div className="flex flex-col gap-1.5">
            <FieldLabel>Серьёзность</FieldLabel>
            <div className="flex flex-col gap-1.5">
              {(["critical", "warning", "info"] as AlertSeverity[]).map(s => {
                const active = form.severity === s
                return (
                  <button key={s} onClick={() => setForm(f => ({ ...f, severity: s }))}
                    className={cn(
                      "flex items-center gap-3 rounded-lg border px-3 py-2.5 text-left transition-colors w-full",
                      active ? SEVERITY_META[s].chip : "border-input hover:bg-muted/50 text-foreground",
                    )}>
                    <span className={cn("size-2.5 rounded-full shrink-0", SEVERITY_META[s].dot)} />
                    <div className="min-w-0">
                      <p className="text-sm font-medium leading-none">{SEVERITY_META[s].label}</p>
                      <p className="text-xs text-muted-foreground mt-0.5 leading-none">
                        {s === "critical" ? "Немедленное уведомление, звуковой сигнал"
                          : s === "warning" ? "Важное событие, тихое уведомление"
                          : "Информационное, без уведомления"}
                      </p>
                    </div>
                    {active && <CheckIcon className="size-4 ml-auto shrink-0 opacity-70" />}
                  </button>
                )
              })}
            </div>
          </div>

          {/* cooldown */}
          <div className="flex flex-col gap-1.5">
            <FieldLabel>Повторять не чаще чем</FieldLabel>
            <div className="flex gap-1.5 flex-wrap">
              {COOLDOWNS.map(c => (
                <button key={c} onClick={() => setForm(f => ({ ...f, cooldown: c }))}
                  className={cn(
                    "px-3 py-1.5 rounded-lg border text-sm font-mono transition-colors",
                    form.cooldown === c
                      ? "border-primary bg-primary/10 text-primary font-semibold"
                      : "border-input text-muted-foreground hover:bg-muted/50 hover:text-foreground",
                  )}>
                  {c}
                </button>
              ))}
            </div>
          </div>

          {/* chat id override */}
          <div className="flex flex-col gap-1.5">
            <FieldLabel>Chat ID — переопределить</FieldLabel>
            <Input
              value={form.chatId}
              onChange={e => setForm(f => ({ ...f, chatId: e.target.value }))}
              className="font-mono text-sm"
              placeholder="-100xxxxxxxxxx"
            />
            <FieldHint>Пусто → используется глобальный Chat ID из настроек Telegram</FieldHint>
          </div>

          {/* Telegram message preview */}
          {form.name && form.target && form.condition && (
            <div className="rounded-xl border border-border bg-muted/40 overflow-hidden">
              <div className="px-3 py-2 border-b border-border/60 flex items-center gap-1.5">
                <span className="text-[10px] font-semibold text-muted-foreground uppercase tracking-wide">
                  Предпросмотр сообщения
                </span>
              </div>
              <div className="px-3 py-2.5 font-mono text-xs leading-relaxed space-y-0.5">
                <p>
                  {form.severity === "critical" ? "🔴" : form.severity === "warning" ? "🟡" : "🔵"}
                  {" "}<span className="font-semibold">{form.name}</span>
                </p>
                <p className="text-muted-foreground">Объект: {form.target}</p>
                <p className="text-muted-foreground">
                  Событие: {conditionDisplay || form.condition}
                </p>
                <p className="text-muted-foreground">Cooldown: {form.cooldown}</p>
                <p className="text-muted-foreground">
                  Chat: {form.chatId || "(глобальный)"}
                </p>
              </div>
            </div>
          )}
        </div>

        {/* ── fixed footer ── */}
        <SheetFooter className="shrink-0 px-6 py-4 border-t flex-row gap-2">
          <Button variant="outline" className="flex-1" onClick={onClose}>Отмена</Button>
          <Button className="flex-1" onClick={handleSave} disabled={!canSave}>
            Сохранить правило
          </Button>
        </SheetFooter>
      </SheetContent>
    </Sheet>
  )
}

// ─── page ─────────────────────────────────────────────────────────────────────

type SeverityFilter = AlertSeverity | "all"

export default function AlertsPage() {
  const [rules,   setRules]   = useState<AlertRule[]>(INIT_RULES)
  const [history]             = useState<HistoryEntry[]>(INIT_HISTORY)
  const [tg,      setTg]      = useState<TelegramConfig>(INIT_TG)
  const [sheetOpen, setSheetOpen] = useState(false)
  const [sevFilter, setSevFilter] = useState<SeverityFilter>("all")
  const [onlyActive, setOnlyActive] = useState(false)
  const [search, setSearch]   = useState("")

  const total    = rules.length
  const active   = rules.filter(r => r.enabled).length
  const critical = rules.filter(r => r.severity === "critical").length
  const warning  = rules.filter(r => r.severity === "warning").length
  const info     = rules.filter(r => r.severity === "info").length

  const filteredRules = useMemo(() => rules.filter(r => {
    if (sevFilter !== "all" && r.severity !== sevFilter) return false
    if (onlyActive && !r.enabled) return false
    if (search && !r.name.toLowerCase().includes(search.toLowerCase()) &&
      !r.target.toLowerCase().includes(search.toLowerCase())) return false
    return true
  }), [rules, sevFilter, onlyActive, search])

  const handleToggle = (id: string, enabled: boolean) =>
    setRules(rs => rs.map(r => r.id === id ? { ...r, enabled } : r))

  const handleDelete = (id: string) =>
    setRules(rs => rs.filter(r => r.id !== id))

  const handleAdd = (rule: Omit<AlertRule, "id" | "lastFired" | "enabled">) => {
    setRules(rs => [...rs, {
      ...rule,
      id: `r${Date.now()}`,
      enabled: true,
      lastFired: null,
    }])
  }

  // Summary chip click handler
  const handleChip = (sev: SeverityFilter) =>
    setSevFilter(f => f === sev ? "all" : sev)

  const chipActive = (sev: SeverityFilter) => sevFilter === sev

  return (
    <div className="flex flex-col h-full">
      <PageHeader
        crumbs={[{ label: "Система" }, { label: "Оповещения" }]}
        actions={
          <>
            <Button variant="outline" size="sm">
              <RefreshCwIcon className="size-4" />Обновить
            </Button>
            <Button size="sm" onClick={() => setSheetOpen(true)}>
              <PlusIcon className="size-4" />Добавить правило
            </Button>
          </>
        }
      />

      <div className="flex-1 overflow-y-auto p-6">
        <div className="flex flex-col gap-5">

          {/* ── summary chip bar ── */}
          <div className="flex items-center gap-2 flex-wrap">

            {/* stat chips */}
            {([
              { key: "all",      label: `Всего: ${total}`,          cls: "border-border bg-muted/50 text-foreground" },
              { key: "critical", label: `Критических: ${critical}`, cls: SEVERITY_META.critical.chip },
              { key: "warning",  label: `Предупреждений: ${warning}`, cls: SEVERITY_META.warning.chip },
              { key: "info",     label: `Информационных: ${info}`,  cls: SEVERITY_META.info.chip },
            ] as { key: SeverityFilter; label: string; cls: string }[]).map(({ key, label, cls }) => (
              <button key={key} onClick={() => handleChip(key)}
                className={cn(
                  "text-xs px-3 py-1.5 rounded-full border font-medium transition-colors",
                  chipActive(key)
                    ? cls
                    : "border-border bg-muted/40 text-muted-foreground hover:bg-muted",
                )}>
                {label}
              </button>
            ))}

            <div className="w-px h-4 bg-border mx-1" />

            {/* active count chip */}
            <button onClick={() => setOnlyActive(v => !v)}
              className={cn(
                "text-xs px-3 py-1.5 rounded-full border font-medium transition-colors",
                onlyActive
                  ? "border-emerald-400 bg-emerald-500/10 text-emerald-600 dark:text-emerald-400"
                  : "border-border bg-muted/40 text-muted-foreground hover:bg-muted",
              )}>
              Активных: {active}
            </button>

            {/* telegram status */}
            <span className={cn(
              "ml-auto text-xs px-3 py-1.5 rounded-full border flex items-center gap-1.5 font-medium",
              tg.connected
                ? "border-emerald-400 bg-emerald-500/10 text-emerald-600 dark:text-emerald-400"
                : "border-red-400 bg-red-500/10 text-red-600 dark:text-red-400",
            )}>
              <span className={cn("size-1.5 rounded-full", tg.connected ? "bg-emerald-500" : "bg-red-500")} />
              {tg.connected ? "Telegram: Подключён" : "Telegram: Не настроен"}
            </span>
          </div>

          {/* ── main layout ── */}
          <div className="grid grid-cols-1 xl:grid-cols-[1fr_300px] gap-5 items-start">

            {/* ── rules card ── */}
            <Card>
              <CardHeader className="pb-0 pt-4 px-4">
                <div className="flex items-center justify-between gap-3">
                  <CardTitle className="text-sm">Правила оповещения</CardTitle>
                  <Input
                    placeholder="Поиск…"
                    value={search}
                    onChange={e => setSearch(e.target.value)}
                    className="h-7 text-xs max-w-[200px]"
                  />
                </div>
              </CardHeader>

              <CardContent className="px-0 pb-0 pt-2">
                {filteredRules.length === 0 ? (
                  <div className="flex flex-col items-center justify-center py-12 text-muted-foreground/40">
                    <BellOffIcon className="size-8 mb-2 opacity-40" />
                    <p className="text-sm">Правила не найдены</p>
                  </div>
                ) : (
                  <div className="divide-y divide-border/60">
                    {filteredRules.map(r => (
                      <AlertRuleRow
                        key={r.id}
                        rule={r}
                        onToggle={handleToggle}
                        onDelete={handleDelete}
                      />
                    ))}
                  </div>
                )}

                {/* footer */}
                <div className="px-4 py-2.5 border-t flex items-center justify-between text-[11px] text-muted-foreground">
                  <span>
                    {filteredRules.length} из {total} правил
                    {onlyActive && " · только активные"}
                    {sevFilter !== "all" && ` · ${SEVERITY_META[sevFilter].label.toLowerCase()}`}
                  </span>
                  <button
                    onClick={() => setSheetOpen(true)}
                    className="flex items-center gap-1 hover:text-foreground transition-colors">
                    <PlusIcon className="size-3" />Добавить правило
                  </button>
                </div>
              </CardContent>
            </Card>

            {/* ── right sidebar ── */}
            <div className="flex flex-col gap-5">
              <TelegramCard cfg={tg} onChange={setTg} />
              <HistoryCard entries={history} />
            </div>
          </div>
        </div>
      </div>

      <AddRuleSheet
        open={sheetOpen}
        onClose={() => setSheetOpen(false)}
        onSave={handleAdd}
      />
    </div>
  )
}
