"use client"

import { useCallback, useEffect, useMemo, useState, type ReactNode } from "react"
import { PageHeader } from "@/components/page-header"
import { routerCertificates, servers as mockServers } from "@/lib/data"
import type { CertStatus, Server } from "@/lib/data"
import type { CertificateDto } from "@mmapp/contracts/certificates"
import { Flag } from "@/components/flag"
import { Card, CardContent } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import {
  Sheet,
  SheetContent,
  SheetHeader,
  SheetTitle,
  SheetDescription,
  SheetFooter,
  SheetClose,
} from "@/components/ui/sheet"
import { cn } from "@/lib/utils"
import { useDataSource } from "@/lib/data-source"
import { listServers } from "@/shared/api/servers"
import { toFrontendServer } from "@/entities/server/model/mappers"
import {
  createCertificateIssueJob,
  getAcmeSettings,
  getCertificateIssueJob,
  listCertificates,
  putAcmeSettings,
  refreshCertificates,
  testAcmeSettings,
} from "@/shared/api/certificates"
import { toast } from "sonner"
import {
  SearchIcon,
  ShieldCheckIcon,
  ShieldAlertIcon,
  ShieldOffIcon,
  BadgeCheckIcon,
  AlertTriangleIcon,
  AlertCircleIcon,
  CalendarIcon,
  KeyRoundIcon,
  ServerIcon,
  PlusIcon,
  ChevronDownIcon,
  ChevronRightIcon,
  RefreshCwIcon,
} from "lucide-react"

const STATUS_CONFIG: Record<
  CertStatus,
  {
    label: string
    icon: ReactNode
    badge: string
    row: string
  }
> = {
  valid: {
    label: "Действителен",
    icon: <BadgeCheckIcon className="size-4 text-emerald-500" />,
    badge: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border-emerald-500/20",
    row: "",
  },
  expired: {
    label: "Истёк",
    icon: <ShieldOffIcon className="size-4 text-red-500" />,
    badge: "bg-red-500/10 text-red-600 dark:text-red-400 border-red-500/20",
    row: "bg-red-500/5",
  },
  revoked: {
    label: "Отозван",
    icon: <ShieldAlertIcon className="size-4 text-amber-500" />,
    badge: "bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/20",
    row: "bg-amber-500/5",
  },
}

const CERT_TABLE_GRID_CLASS =
  "grid grid-cols-[1.25rem_minmax(0,1.35fr)_minmax(0,0.85fr)_minmax(0,1fr)_9.5rem_minmax(0,8.5rem)_6rem] gap-3"

function daysLeftColor(days: number): string {
  if (days < 0) return "text-red-500"
  if (days <= 7) return "text-red-500"
  if (days <= 30) return "text-amber-500"
  return "text-emerald-600 dark:text-emerald-400"
}

function daysLeftBar(days: number, total = 365): number {
  if (days <= 0) return 0
  return Math.min(100, Math.round((days / total) * 100))
}

function Field({
  label,
  hint,
  required,
  children,
}: {
  label: string
  hint?: string
  required?: boolean
  children: ReactNode
}) {
  return (
    <div className="flex flex-col gap-1.5">
      <label className="text-sm font-medium">
        {label}
        {required && <span className="text-destructive ml-0.5">*</span>}
      </label>
      {children}
      {hint && <p className="text-xs text-muted-foreground">{hint}</p>}
    </div>
  )
}

function Toggle({ checked, onChange }: { checked: boolean; onChange: (v: boolean) => void }) {
  return (
    <button
      type="button"
      role="switch"
      aria-checked={checked}
      onClick={() => onChange(!checked)}
      className={cn(
        "relative inline-flex h-5 w-9 shrink-0 rounded-full border-2 border-transparent transition-colors",
        checked ? "bg-primary" : "bg-input",
      )}
    >
      <span
        className={cn(
          "pointer-events-none block h-4 w-4 rounded-full bg-white shadow-sm transition-transform",
          checked ? "translate-x-4" : "translate-x-0",
        )}
      />
    </button>
  )
}

function SectionTitle({ children }: { children: ReactNode }) {
  return (
    <div className="flex items-center gap-2 py-0.5">
      <span className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">{children}</span>
      <div className="flex-1 h-px bg-border" />
    </div>
  )
}

function mockToDto(cert: (typeof routerCertificates)[number]): CertificateDto {
  return {
    id: cert.id,
    name: cert.name,
    serverId: cert.serverId,
    commonName: cert.commonName,
    sans: cert.sans,
    issuedBy: cert.issuedBy,
    validFrom: cert.validFrom,
    validUntil: cert.validUntil,
    daysLeft: cert.daysLeft,
    keySize: cert.keySize,
    usage: cert.usage,
    trusted: cert.trusted,
    status: cert.status,
  }
}

function CertPartDaysBar({ cert, pct }: { cert: CertificateDto; pct: number }) {
  return (
    <div
      className={cn(
        "h-full rounded-full transition-all",
        cert.daysLeft < 0
          ? "bg-red-500"
          : cert.daysLeft <= 7
            ? "bg-red-500"
            : cert.daysLeft <= 30
              ? "bg-amber-500"
              : "bg-emerald-500",
      )}
      style={{ width: `${pct}%` }}
    />
  )
}

function CertPartDays({ cert, pct }: { cert: CertificateDto; pct: number }) {
  return (
    <>
      <div className="flex items-center justify-between text-xs mb-1">
        <span className={cn("font-mono font-medium", daysLeftColor(cert.daysLeft))}>
          {cert.daysLeft < 0 ? `Истёк ${-cert.daysLeft}д назад` : `${cert.daysLeft}д осталось`}
        </span>
        <span className="text-muted-foreground text-[10px]">{cert.validUntil}</span>
      </div>
      <div className="h-1.5 bg-muted rounded-full overflow-hidden">
        <CertPartDaysBar cert={cert} pct={pct} />
      </div>
    </>
  )
}

function CertPartDetailDates({ cert }: { cert: CertificateDto }) {
  return (
    <div>
      <p className="text-muted-foreground mb-1">Действителен с</p>
      <p className="font-mono">{cert.validFrom}</p>
    </div>
  )
}

function CertPartDetailSans({ cert }: { cert: CertificateDto }) {
  return (
    <div>
      <p className="text-muted-foreground mb-1">SAN / Alt Names</p>
      <div className="flex flex-wrap gap-1">
        {cert.sans.length > 0
          ? cert.sans.map((s) => (
              <span key={s} className="font-mono bg-muted px-1.5 py-0.5 rounded">
                {s}
              </span>
            ))
          : <span className="text-muted-foreground">—</span>}
      </div>
    </div>
  )
}

function CertPartDetailTrusted({ cert }: { cert: CertificateDto }) {
  return (
    <div>
      <p className="text-muted-foreground mb-1">Trusted</p>
      <p className={cert.trusted ? "text-emerald-600 dark:text-emerald-400" : "text-red-500"}>
        {cert.trusted ? "Да (доверенный)" : "Нет (не доверенный)"}
      </p>
    </div>
  )
}

function CertListRow({
  cert,
  cfg,
  pct,
  server,
  expanded,
  onToggle,
}: {
  cert: CertificateDto
  cfg: (typeof STATUS_CONFIG)[CertStatus]
  pct: number
  server?: Server
  expanded: boolean
  onToggle: () => void
}) {
  return (
    <div className={cn("border-b last:border-b-0", cfg.row)}>
      <div
        className={cn(
          CERT_TABLE_GRID_CLASS,
          "px-4 py-3 items-center hover:bg-muted/30 transition-colors cursor-pointer",
        )}
        onClick={onToggle}
      >
        <button
          type="button"
          className="text-muted-foreground"
          onClick={(e) => {
            e.stopPropagation()
            onToggle()
          }}
        >
          {expanded ? <ChevronDownIcon className="size-3.5" /> : <ChevronRightIcon className="size-3.5" />}
        </button>
        <div className="min-w-0">
          <div className="flex items-center gap-2 min-w-0">
            <span className="shrink-0">{cfg.icon}</span>
            <span className="font-medium text-sm truncate" title={cert.name}>
              {cert.name}
            </span>
          </div>
          <p className="text-xs text-muted-foreground font-mono mt-0.5 truncate" title={cert.commonName}>
            {cert.commonName}
          </p>
        </div>
        <div className="flex items-center gap-1.5 text-xs text-muted-foreground min-w-0">
          {server
            ? (
                <>
                  <Flag code={server.country} size={12} />
                  <span className="font-mono truncate">{server.name}</span>
                </>
              )
            : (
                <>
                  <ServerIcon className="size-3.5" />
                  <span className="font-mono truncate">{cert.serverName ?? cert.serverId}</span>
                </>
              )}
        </div>
        <p className="text-xs text-muted-foreground truncate min-w-0" title={cert.issuedBy}>
          {cert.issuedBy}
        </p>
        <div className="min-w-0">
          <CertPartDays cert={cert} pct={pct} />
        </div>
        <div className="flex flex-wrap gap-1 min-w-0 overflow-hidden">
          {cert.usage.map((u) => (
            <span
              key={u}
              className="text-[10px] font-mono px-1.5 py-0.5 rounded bg-muted text-muted-foreground border"
            >
              {u}
            </span>
          ))}
        </div>
        <span
          className={cn(
            "text-[11px] font-mono px-2 py-0.5 rounded border whitespace-nowrap shrink-0 justify-self-end",
            cfg.badge,
          )}
        >
          {cfg.label}
        </span>
      </div>
      {expanded && (
        <div className="px-10 pb-4 grid grid-cols-2 sm:grid-cols-4 gap-4 text-xs border-t border-border/50 pt-3">
          <div>
            <p className="text-muted-foreground mb-1">Key size</p>
            <p className="font-mono font-medium">{cert.keySize} bit</p>
          </div>
          <CertPartDetailDates cert={cert} />
          <CertPartDetailSans cert={cert} />
          <CertPartDetailTrusted cert={cert} />
        </div>
      )}
    </div>
  )
}

function CertRow({
  cert,
  server,
  expanded,
  onToggle,
}: {
  cert: CertificateDto
  server?: Server
  expanded: boolean
  onToggle: () => void
}) {
  const cfg = STATUS_CONFIG[cert.status]
  const pct = daysLeftBar(cert.daysLeft)

  return (
    <CertListRow
      cert={cert}
      cfg={cfg}
      pct={pct}
      server={server}
      expanded={expanded}
      onToggle={onToggle}
    />
  )
}

function CertPartAlertExpired({ expired }: { expired: CertificateDto[] }) {
  return (
    <div className="flex items-start gap-3 rounded-lg bg-red-500/5 border border-red-500/20 px-4 py-3 text-sm">
      <AlertCircleIcon className="size-5 text-red-500 shrink-0 mt-0.5" />
      <div>
        <p className="font-medium text-red-600 dark:text-red-400">
          {expired.length} {expired.length === 1 ? "истёкший сертификат" : "истёкших сертификата"}
        </p>
        <p className="text-muted-foreground text-xs mt-0.5">
          {expired.map((c) => c.name).join(", ")} — требуют обновления
        </p>
      </div>
    </div>
  )
}

function CertPartAlertExpiring({ expiring }: { expiring: CertificateDto[] }) {
  return (
    <div className="flex items-start gap-3 rounded-lg bg-amber-500/5 border border-amber-500/20 px-4 py-3 text-sm">
      <AlertTriangleIcon className="size-5 text-amber-500 shrink-0 mt-0.5" />
      <div>
        <p className="font-medium text-amber-600 dark:text-amber-400">
          {expiring.length} {expiring.length === 1 ? "сертификат истекает" : "сертификата истекают"} в течение 30 дней
        </p>
        <p className="text-muted-foreground text-xs mt-0.5">
          {expiring.map((c) => `${c.name} (${c.daysLeft}д)`).join(", ")}
        </p>
      </div>
    </div>
  )
}

function CertPartKpi({
  displayCerts,
  expiring,
  expired,
}: {
  displayCerts: CertificateDto[]
  expiring: CertificateDto[]
  expired: CertificateDto[]
}) {
  return (
    <div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
      {[
        {
          label: "Всего",
          value: displayCerts.length,
          icon: <ShieldCheckIcon className="size-4 text-muted-foreground" />,
        },
        {
          label: "Действующих",
          value: displayCerts.filter((c) => c.status === "valid").length,
          icon: <BadgeCheckIcon className="size-4 text-emerald-500" />,
        },
        {
          label: "Истекают",
          value: expiring.length,
          icon: <AlertTriangleIcon className="size-4 text-amber-500" />,
        },
        {
          label: "Истёкших",
          value: expired.length,
          icon: <AlertCircleIcon className="size-4 text-red-500" />,
        },
      ].map((s) => (
        <Card key={s.label}>
          <CardContent className="px-5 py-4 flex items-start justify-between">
            <div>
              <p className="text-sm text-muted-foreground">{s.label}</p>
              <p className="text-2xl font-semibold tabular-nums mt-0.5">{s.value}</p>
            </div>
            <div className="mt-0.5">{s.icon}</div>
          </CardContent>
        </Card>
      ))}
    </div>
  )
}

function CertPartAcmeSettings({
  acmeDirectoryUrl,
  setAcmeDirectoryUrl,
  acmeZoneId,
  setAcmeZoneId,
  acmeTokenDraft,
  setAcmeTokenDraft,
  acmeTokenConfigured,
  acmeSaveBusy,
  onTest,
  onSave,
}: {
  acmeDirectoryUrl: string
  setAcmeDirectoryUrl: (v: string) => void
  acmeZoneId: string
  setAcmeZoneId: (v: string) => void
  acmeTokenDraft: string
  setAcmeTokenDraft: (v: string) => void
  acmeTokenConfigured: boolean
  acmeSaveBusy: boolean
  onTest: () => void
  onSave: () => void
}) {
  return (
    <Card>
      <CardContent className="px-5 py-4 flex flex-col gap-3">
        <p className="text-sm font-medium">ACME · Cloudflare DNS-01</p>
        <p className="text-xs text-muted-foreground">
          Публичные Let&apos;s Encrypt для зон в Cloudflare выпускаются на backend и импортируются на RouterOS 7.22+.
        </p>
        <form
          className="grid gap-3 md:grid-cols-2"
          autoComplete="off"
          onSubmit={(event) => event.preventDefault()}
        >
          <div className="flex flex-col gap-1.5">
            <label className="text-sm font-medium">ACME directory URL</label>
            <Input
              autoComplete="off"
              name="acme-directory-url"
              value={acmeDirectoryUrl}
              onChange={(e) => setAcmeDirectoryUrl(e.target.value)}
            />
          </div>
          <div className="flex flex-col gap-1.5">
            <label className="text-sm font-medium">Cloudflare zone id (опционально)</label>
            <Input
              autoComplete="off"
              name="cloudflare-zone-id"
              value={acmeZoneId}
              onChange={(e) => setAcmeZoneId(e.target.value)}
              placeholder="Авто по домену"
            />
          </div>
          <div className="flex flex-col gap-1.5 md:col-span-2">
            <label className="text-sm font-medium">Cloudflare API token</label>
            <Input
              type="password"
              autoComplete="new-password"
              name="cloudflare-api-token"
              value={acmeTokenDraft}
              onChange={(e) => setAcmeTokenDraft(e.target.value)}
              placeholder={
                acmeTokenConfigured
                  ? "Токен сохранён — введите новый для замены"
                  : "API token с правом DNS"
              }
            />
          </div>
        </form>
        <div className="flex flex-wrap gap-2">
          <Button variant="outline" size="sm" disabled={acmeSaveBusy} onClick={onTest}>
            Проверить Cloudflare
          </Button>
          <Button size="sm" disabled={acmeSaveBusy} onClick={onSave}>
            Сохранить настройки
          </Button>
        </div>
      </CardContent>
    </Card>
  )
}

function CertPartTableToolbar({
  search,
  setSearch,
  statusFilter,
  setStatusFilter,
  filteredCount,
}: {
  search: string
  setSearch: (v: string) => void
  statusFilter: CertStatus | "all"
  setStatusFilter: (v: CertStatus | "all") => void
  filteredCount: number
}) {
  return (
    <div className="flex items-center gap-3 px-4 py-3 border-b flex-wrap">
      <div className="flex items-center gap-2 h-8 px-3 border border-input rounded-md bg-background min-w-[240px]">
        <SearchIcon className="size-3.5 text-muted-foreground shrink-0" />
        <input
          className="flex-1 bg-transparent outline-none placeholder:text-muted-foreground text-sm"
          placeholder="Поиск по имени, CN, эмитенту…"
          value={search}
          onChange={(e) => setSearch(e.target.value)}
        />
      </div>
      <div className="flex items-center gap-1 rounded-md border border-border bg-muted/40 p-0.5">
        {(["all", "valid", "expired", "revoked"] as const).map((s) => (
          <button
            key={s}
            type="button"
            onClick={() => setStatusFilter(s)}
            className={cn(
              "px-3 py-1 text-xs rounded whitespace-nowrap transition-colors",
              statusFilter === s
                ? "bg-background text-foreground shadow-sm"
                : "text-muted-foreground hover:text-foreground",
            )}
          >
            {s === "all"
              ? "Все"
              : s === "valid"
                ? "Действующие"
                : s === "expired"
                  ? "Истёкшие"
                  : "Отозванные"}
          </button>
        ))}
      </div>
      <span className="text-sm text-muted-foreground ml-auto">{filteredCount} сертификатов</span>
    </div>
  )
}

function CertPartTableHeaderDates() {
  return (
    <div className="flex items-center gap-1">
      <CalendarIcon className="size-3" />
      Срок
    </div>
  )
}

function CertPartTableHeaderUsage() {
  return (
    <div className="flex items-center gap-1">
      <KeyRoundIcon className="size-3" />
      Использование
    </div>
  )
}

function CertPartTableHeader() {
  return (
    <div
      className={cn(
        CERT_TABLE_GRID_CLASS,
        "px-4 py-2 border-b text-[10px] font-semibold uppercase tracking-widest text-muted-foreground bg-muted/20",
      )}
    >
      <span />
      <span>Имя / CN</span>
      <span>Сервер</span>
      <span>Выпущен</span>
      <CertPartTableHeaderDates />
      <CertPartTableHeaderUsage />
      <span>Статус</span>
    </div>
  )
}

function CertPartReference() {
  return (
    <Card>
      <CardContent className="px-5 py-4">
        <p className="text-xs font-medium text-muted-foreground mb-1">
          RouterOS 7.22+ · публичные LE для Cloudflare через backend DNS-01, не через /certificate add-acme на устройстве.
        </p>
        <p className="text-xs font-medium text-muted-foreground mb-3">RouterOS 7 · /certificate — справка CLI</p>
        <div className="grid grid-cols-1 sm:grid-cols-3 gap-4 text-xs font-mono">
          {[
            {
              title: "Создать CA",
              lines: [
                "/certificate add \\",
                "  name=my-ca \\",
                "  common-name=MyCA \\",
                "  key-size=4096 \\",
                "  days-valid=3650 \\",
                "  key-usage=key-cert-sign,crl-sign",
                "/certificate sign my-ca",
              ],
            },
            {
              title: "Импорт LE",
              lines: [
                "/certificate import \\",
                "  file-name=router.crt \\",
                "  name=router-cert \\",
                "  trusted=yes \\",
                "  trust-store=www,api",
              ],
            },
            {
              title: "Статус",
              lines: ["/certificate print detail", "/certificate export-certificate router-cert"],
            },
          ].map((b) => (
            <div key={b.title}>
              <p className="font-sans font-semibold text-foreground/80 mb-1.5 text-[11px] uppercase tracking-wide">
                {b.title}
              </p>
              <pre className="bg-zinc-950 rounded-md p-2.5 text-zinc-300 text-[11px] leading-relaxed overflow-x-auto whitespace-pre">
                {b.lines.join("\n")}
              </pre>
            </div>
          ))}
        </div>
      </CardContent>
    </Card>
  )
}

function CertPartIssueForm({
  serverList,
  issueServerId,
  setIssueServerId,
  issueCertName,
  setIssueCertName,
  issueCommonName,
  setIssueCommonName,
  issueSans,
  setIssueSans,
  issueTrustWww,
  setIssueTrustWww,
  issueTrustApi,
  setIssueTrustApi,
}: {
  serverList: Server[]
  issueServerId: string
  setIssueServerId: (v: string) => void
  issueCertName: string
  setIssueCertName: (v: string) => void
  issueCommonName: string
  setIssueCommonName: (v: string) => void
  issueSans: string
  setIssueSans: (v: string) => void
  issueTrustWww: boolean
  setIssueTrustWww: (v: boolean) => void
  issueTrustApi: boolean
  setIssueTrustApi: (v: boolean) => void
}) {
  return (
    <div className="flex flex-col gap-5">
      <div className="flex flex-col gap-4">
        <SectionTitle>Основные</SectionTitle>
        <Field label="Сервер" required hint="RouterOS 7.22+, куда импортируется сертификат">
          <select
            value={issueServerId}
            onChange={(e) => setIssueServerId(e.target.value)}
            className="h-8 w-full rounded-lg border border-input bg-background px-2.5 text-sm text-foreground outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50"
          >
            <option value="" disabled>
              Выбрать сервер…
            </option>
            {serverList.map((s) => (
              <option key={s.id} value={s.id}>
                {s.name} ({s.site})
              </option>
            ))}
          </select>
        </Field>
        <Field label="Имя сертификата на роутере" required hint="Имя объекта /certificate на устройстве">
          <Input
            className="font-mono"
            value={issueCertName}
            onChange={(e) => setIssueCertName(e.target.value)}
            placeholder="router-le"
          />
        </Field>
      </div>

      <div className="flex flex-col gap-4">
        <SectionTitle>Домены</SectionTitle>
        <Field label="Common Name" required hint="Основное имя в сертификате">
          <Input
            className="font-mono"
            value={issueCommonName}
            onChange={(e) => setIssueCommonName(e.target.value)}
            placeholder="vpn.example.com"
          />
        </Field>
        <Field label="SAN" hint="По одному имени в строке">
          <textarea
            className="min-h-24 w-full rounded-lg border border-input bg-background px-2.5 py-2 text-sm font-mono text-foreground outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50"
            value={issueSans}
            onChange={(e) => setIssueSans(e.target.value)}
            placeholder="www.example.com"
          />
        </Field>
        <div className="rounded-lg border border-border bg-muted/20 px-4 py-3 text-xs text-muted-foreground">
          <p className="font-medium text-foreground mb-1">Let&apos;s Encrypt · DNS-01 (Cloudflare)</p>
          <p>TXT-запись создаётся в Cloudflare, сертификат импортируется на выбранный RouterOS.</p>
        </div>
      </div>

      <div className="flex flex-col gap-4">
        <SectionTitle>Импорт на RouterOS</SectionTitle>
        <div className="flex items-center justify-between">
          <div>
            <p className="text-sm font-medium">Trust store · www</p>
            <p className="text-xs text-muted-foreground">Веб-интерфейс и HTTPS-сервисы</p>
          </div>
          <Toggle checked={issueTrustWww} onChange={setIssueTrustWww} />
        </div>
        <div className="flex items-center justify-between">
          <div>
            <p className="text-sm font-medium">Trust store · api</p>
            <p className="text-xs text-muted-foreground">REST API и управление</p>
          </div>
          <Toggle checked={issueTrustApi} onChange={setIssueTrustApi} />
        </div>
      </div>
    </div>
  )
}

export default function CertificatesPage() {
  const { mode, backendUrl, prefsHydrated, backendStatus } = useDataSource()
  const isLive = prefsHydrated && mode === "live"
  const liveReady = isLive && backendStatus === true

  const [search, setSearch] = useState("")
  const [statusFilter, setStatusFilter] = useState<CertStatus | "all">("all")
  const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set())
  const [certificates, setCertificates] = useState<CertificateDto[]>([])
  const [loadState, setLoadState] = useState<"idle" | "loading" | "error">("idle")
  const [loadError, setLoadError] = useState<string | null>(null)
  const [serverList, setServerList] = useState<Server[]>([])

  const [issueOpen, setIssueOpen] = useState(false)
  const [issueBusy, setIssueBusy] = useState(false)
  const [issueServerId, setIssueServerId] = useState("")
  const [issueCertName, setIssueCertName] = useState("")
  const [issueCommonName, setIssueCommonName] = useState("")
  const [issueSans, setIssueSans] = useState("")
  const [issueTrustWww, setIssueTrustWww] = useState(true)
  const [issueTrustApi, setIssueTrustApi] = useState(true)

  const [acmeDirectoryUrl, setAcmeDirectoryUrl] = useState(
    "https://acme-v02.api.letsencrypt.org/directory",
  )
  const [acmeZoneId, setAcmeZoneId] = useState("")
  const [acmeTokenDraft, setAcmeTokenDraft] = useState("")
  const [acmeTokenConfigured, setAcmeTokenConfigured] = useState(false)
  const [acmeSaveBusy, setAcmeSaveBusy] = useState(false)

  const displayCerts = useMemo(() => {
    if (!prefsHydrated) return []
    if (isLive) return certificates
    return routerCertificates.map(mockToDto)
  }, [prefsHydrated, isLive, certificates])

  const serverById = useMemo(() => {
    const map = new Map<string, Server>()
    for (const s of isLive ? serverList : mockServers) map.set(s.id, s)
    return map
  }, [isLive, serverList])

  const loadLive = useCallback(
    async (silent = false) => {
      if (!isLive) return
      if (!silent) setLoadState("loading")
      setLoadError(null)
      try {
        const [certRes, serversRes] = await Promise.all([
          listCertificates(backendUrl),
          listServers(backendUrl),
        ])
        setCertificates(certRes.certificates)
        setServerList(serversRes.map(toFrontendServer))
        if (certRes.failures.length > 0 && certRes.certificates.length === 0) {
          setLoadError(
            certRes.failures.map((f) => `${f.serverName ?? f.serverId}: ${f.error}`).join("; "),
          )
        } else if (certRes.failures.length > 0) {
          toast.warning(`Часть серверов недоступна: ${certRes.failures.length}`)
        }
        setLoadState("idle")
      } catch (e) {
        setCertificates([])
        setLoadError(e instanceof Error ? e.message : "Не удалось загрузить сертификаты")
        setLoadState("error")
      }
    },
    [backendUrl, isLive],
  )

  const loadAcmeSettings = useCallback(async () => {
    if (!liveReady) return
    try {
      const s = await getAcmeSettings(backendUrl)
      setAcmeDirectoryUrl(s.directoryUrl)
      setAcmeZoneId(s.defaultZoneId ?? "")
      setAcmeTokenConfigured(s.tokenConfigured)
    } catch {
      /* ignore */
    }
  }, [backendUrl, liveReady])

  useEffect(() => {
    if (!isLive) {
      queueMicrotask(() => {
        setCertificates([])
        setServerList([])
        setLoadState("idle")
        setLoadError(null)
      })
      return
    }
    queueMicrotask(() => {
      void loadLive()
      void loadAcmeSettings()
    })
  }, [isLive, loadLive, loadAcmeSettings])

  const expiring = useMemo(
    () => displayCerts.filter((c) => c.status === "valid" && c.daysLeft >= 0 && c.daysLeft <= 30),
    [displayCerts],
  )
  const expired = useMemo(() => displayCerts.filter((c) => c.status === "expired"), [displayCerts])

  const filtered = useMemo(() => {
    return displayCerts.filter((c) => {
      if (statusFilter !== "all" && c.status !== statusFilter) return false
      if (!search) return true
      const q = search.toLowerCase()
      return (
        c.name.toLowerCase().includes(q) ||
        c.commonName.toLowerCase().includes(q) ||
        c.issuedBy.toLowerCase().includes(q) ||
        c.sans.some((s) => s.includes(q))
      )
    })
  }, [displayCerts, search, statusFilter])

  function toggleExpand(id: string) {
    setExpandedIds((prev) => {
      const next = new Set(prev)
      if (next.has(id)) next.delete(id)
      else next.add(id)
      return next
    })
  }

  async function handleRefresh() {
    if (!liveReady) return
    try {
      const res = await refreshCertificates(backendUrl)
      setCertificates(res.certificates)
      toast.success("Список сертификатов обновлён")
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "Ошибка обновления")
    }
  }

  async function pollIssueJob(jobId: string) {
    for (let i = 0; i < 120; i++) {
      await new Promise((r) => setTimeout(r, 2000))
      const job = await getCertificateIssueJob(backendUrl, jobId)
      if (job.status === "done") {
        toast.success("Сертификат выпущен и импортирован на роутер")
        setIssueOpen(false)
        await loadLive(true)
        return
      }
      if (job.status === "failed") {
        throw new Error(job.error ?? "Выпуск не удался")
      }
    }
    throw new Error("Таймаут ожидания выпуска сертификата")
  }

  async function handleIssue() {
    if (!liveReady) return
    const domains = [
      issueCommonName.trim(),
      ...issueSans.split(/[\n,;]+/).map((s) => s.trim()),
    ].filter(Boolean)
    if (!issueServerId || !issueCertName.trim() || domains.length === 0) {
      toast.error("Укажите сервер, имя сертификата и домены")
      return
    }
    setIssueBusy(true)
    try {
      const trustStore: Array<"www" | "api"> = []
      if (issueTrustWww) trustStore.push("www")
      if (issueTrustApi) trustStore.push("api")
      const { jobId } = await createCertificateIssueJob(backendUrl, {
        serverId: issueServerId,
        certName: issueCertName.trim(),
        domainNames: domains,
        trustStore,
      })
      toast.message("Выпуск сертификата запущен…")
      await pollIssueJob(jobId)
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "Ошибка выпуска")
    } finally {
      setIssueBusy(false)
    }
  }

  async function handleSaveAcmeSettings() {
    if (!liveReady) return
    setAcmeSaveBusy(true)
    try {
      const saved = await putAcmeSettings(backendUrl, {
        directoryUrl: acmeDirectoryUrl.trim(),
        defaultZoneId: acmeZoneId.trim() || null,
        cloudflareApiToken: acmeTokenDraft.trim() ? acmeTokenDraft.trim() : undefined,
      })
      setAcmeTokenConfigured(saved.tokenConfigured)
      setAcmeTokenDraft("")
      toast.success("Настройки ACME сохранены")
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "Не удалось сохранить настройки")
    } finally {
      setAcmeSaveBusy(false)
    }
  }

  async function handleTestAcme() {
    if (!liveReady) return
    try {
      const res = await testAcmeSettings(backendUrl, {
        cloudflareApiToken: acmeTokenDraft.trim() || undefined,
      })
      if (res.ok) toast.success(res.message ?? "Cloudflare API доступен")
      else toast.error(res.message ?? "Проверка не прошла")
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "Проверка Cloudflare не удалась")
    }
  }

  return (
    <div className="flex flex-col h-full">
      <PageHeader
        crumbs={[{ label: "Управление" }, { label: "Сертификаты" }]}
        actions={
          <>
            <Button
              variant="outline"
              size="sm"
              disabled={!liveReady || loadState === "loading"}
              onClick={() => {
                void handleRefresh()
              }}
            >
              <RefreshCwIcon className={cn("size-4", loadState === "loading" && "animate-spin")} />
              Обновить
            </Button>
            <Button size="sm" disabled={!liveReady || issueBusy} onClick={() => setIssueOpen(true)}>
              <PlusIcon className="size-4" />
              Выпустить сертификат
            </Button>
          </>
        }
      />

      <div className="flex-1 overflow-y-auto p-6">
        <div className="flex flex-col gap-5">
          {isLive && backendStatus === false && (
            <div className="rounded-lg border border-amber-500/30 bg-amber-500/5 px-4 py-3 text-sm text-amber-700 dark:text-amber-300">
              Backend недоступен — live-операции отключены.
            </div>
          )}
          {loadError && isLive && (
            <div className="rounded-lg border border-destructive/30 bg-destructive/5 px-4 py-3 text-sm text-destructive">
              {loadError}
            </div>
          )}

          {(expiring.length > 0 || expired.length > 0) && (
            <div className="flex flex-col gap-2">
              {expired.length > 0 && <CertPartAlertExpired expired={expired} />}
              {expiring.length > 0 && <CertPartAlertExpiring expiring={expiring} />}
            </div>
          )}

          <CertPartKpi displayCerts={displayCerts} expiring={expiring} expired={expired} />

          {liveReady && (
            <CertPartAcmeSettings
              acmeDirectoryUrl={acmeDirectoryUrl}
              setAcmeDirectoryUrl={setAcmeDirectoryUrl}
              acmeZoneId={acmeZoneId}
              setAcmeZoneId={setAcmeZoneId}
              acmeTokenDraft={acmeTokenDraft}
              setAcmeTokenDraft={setAcmeTokenDraft}
              acmeTokenConfigured={acmeTokenConfigured}
              acmeSaveBusy={acmeSaveBusy}
              onTest={() => {
                void handleTestAcme()
              }}
              onSave={() => {
                void handleSaveAcmeSettings()
              }}
            />
          )}

          <Card>
            <CertPartTableToolbar
              search={search}
              setSearch={setSearch}
              statusFilter={statusFilter}
              setStatusFilter={setStatusFilter}
              filteredCount={filtered.length}
            />
            <div className="overflow-x-auto">
              <div className="min-w-[48rem]">
                <CertPartTableHeader />
                {prefsHydrated && isLive && loadState === "loading" && displayCerts.length === 0 ? (
                  <div className="py-16 text-center text-sm text-muted-foreground">Загрузка сертификатов…</div>
                ) : filtered.length === 0 ? (
                  <div className="flex flex-col items-center justify-center py-16 text-center text-muted-foreground">
                    <ShieldCheckIcon className="size-10 mb-3 opacity-20" />
                    <p className="text-sm font-medium">Сертификаты не найдены</p>
                  </div>
                ) : (
                  filtered.map((cert) => (
                    <CertRow
                      key={cert.id}
                      cert={cert}
                      server={serverById.get(cert.serverId)}
                      expanded={expandedIds.has(cert.id)}
                      onToggle={() => toggleExpand(cert.id)}
                    />
                  ))
                )}
              </div>
            </div>
          </Card>

          <CertPartReference />
        </div>
      </div>

      <Sheet open={issueOpen} onOpenChange={setIssueOpen}>
        <SheetContent side="right" className="w-full sm:max-w-lg flex flex-col gap-0 p-0">
          <SheetHeader className="px-6 pt-6 pb-4 border-b shrink-0">
            <SheetTitle>Выпуск сертификата</SheetTitle>
            <SheetDescription>
              Let&apos;s Encrypt через DNS-01 (Cloudflare) и импорт на выбранный RouterOS.
            </SheetDescription>
          </SheetHeader>

          <div className="flex-1 overflow-y-auto px-6 py-5">
            <CertPartIssueForm
              serverList={serverList}
              issueServerId={issueServerId}
              setIssueServerId={setIssueServerId}
              issueCertName={issueCertName}
              setIssueCertName={setIssueCertName}
              issueCommonName={issueCommonName}
              setIssueCommonName={setIssueCommonName}
              issueSans={issueSans}
              setIssueSans={setIssueSans}
              issueTrustWww={issueTrustWww}
              setIssueTrustWww={setIssueTrustWww}
              issueTrustApi={issueTrustApi}
              setIssueTrustApi={setIssueTrustApi}
            />
          </div>

          <SheetFooter className="px-6 py-4 border-t shrink-0 flex-row gap-2">
            <SheetClose render={<Button variant="outline" className="flex-1" disabled={issueBusy} />}>
              Отмена
            </SheetClose>
            <Button
              className="flex-1"
              disabled={!liveReady || issueBusy}
              onClick={() => {
                void handleIssue()
              }}
            >
              {issueBusy ? "Выпуск…" : "Выпустить"}
            </Button>
          </SheetFooter>
        </SheetContent>
      </Sheet>
    </div>
  )
}
