import { useState } from 'react'
import { Pencil, Plus, Trash2 } from 'lucide-react'
import { toast } from 'sonner'

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from '@evobgp/ui/components/alert-dialog'
import { Button } from '@evobgp/ui/components/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@evobgp/ui/components/card'
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@evobgp/ui/components/table'

import { QueryState } from '@/components/query-state'
import { TableSkeleton } from '@/components/skeletons'
import { ModuleAsEntryDialog } from '@/components/modules/module-as-entry-dialog'
import { ModuleCdnSourceDialog } from '@/components/modules/module-cdn-source-dialog'
import { ModuleDomainEntryDialog } from '@/components/modules/module-domain-entry-dialog'
import { ModuleIpRangeEntryDialog } from '@/components/modules/module-ip-range-entry-dialog'
import { ApiError, apiMutate } from '@/lib/api-client'
import { communityLabel } from '@/lib/modules/helpers'
import { formatDateTime } from '@/lib/modules/display'
import type {
  AsEntry,
  BgpCommunity,
  CdnSource,
  DomainEntry,
  IpRangeEntry,
  ModuleRow,
} from '@/types/api'

interface ModuleEntriesSectionProps {
  moduleId: string
  mod: ModuleRow
  items: Record<string, unknown>[]
  communities: BgpCommunity[]
  isLoading: boolean
  isError: boolean
  error: Error | null
  onRetry: () => void
  onChanged: () => void | Promise<void>
}

type DeleteTarget =
  | { kind: 'domain'; entry: DomainEntry }
  | { kind: 'ip-range'; entry: IpRangeEntry }
  | { kind: 'cdn'; entry: CdnSource }
  | { kind: 'as'; entry: AsEntry }

const CARD_META: Record<
  ModuleRow['type'],
  { title: string; description: string; emptyTitle: string; emptyDescription: string }
> = {
  DOMAINS: {
    title: 'Домены',
    description: 'FQDN для резолвинга через DoH.',
    emptyTitle: 'Нет доменов',
    emptyDescription: 'Добавьте FQDN для резолвинга.',
  },
  IP_RANGES: {
    title: 'IP-диапазоны',
    description: 'Статические CIDR для анонса.',
    emptyTitle: 'Нет диапазонов',
    emptyDescription: 'Добавьте CIDR.',
  },
  CDN_CIDRS: {
    title: 'CDN-источники',
    description: 'URL источников для скачивания списков CIDR.',
    emptyTitle: 'Нет источников',
    emptyDescription: 'Добавьте CDN-источник.',
  },
  AS_PREFIXES: {
    title: 'AS-записи',
    description: 'ASN для получения префиксов через RIPEstat.',
    emptyTitle: 'Нет записей',
    emptyDescription: 'Добавьте ASN.',
  },
}

export function ModuleEntriesSection({
  moduleId,
  mod,
  items,
  communities,
  isLoading,
  isError,
  error,
  onRetry,
  onChanged,
}: ModuleEntriesSectionProps) {
  const meta = CARD_META[mod.type]
  const [dialogOpen, setDialogOpen] = useState(false)
  const [deleteTarget, setDeleteTarget] = useState<DeleteTarget | null>(null)
  const [deleting, setDeleting] = useState(false)

  const [editDomain, setEditDomain] = useState<DomainEntry | null>(null)
  const [editIpRange, setEditIpRange] = useState<IpRangeEntry | null>(null)
  const [editCdn, setEditCdn] = useState<CdnSource | null>(null)
  const [editAs, setEditAs] = useState<AsEntry | null>(null)

  function openCreate() {
    setEditDomain(null)
    setEditIpRange(null)
    setEditCdn(null)
    setEditAs(null)
    setDialogOpen(true)
  }

  function closeDialog() {
    setDialogOpen(false)
    setEditDomain(null)
    setEditIpRange(null)
    setEditCdn(null)
    setEditAs(null)
  }

  async function confirmDelete() {
    if (!deleteTarget) return
    setDeleting(true)
    try {
      const { kind, entry } = deleteTarget
      const pathByKind = {
        domain: `/v1/modules/${moduleId}/domain-entries/${entry.id}`,
        'ip-range': `/v1/modules/${moduleId}/ip-range-entries/${entry.id}`,
        cdn: `/v1/modules/${moduleId}/cdn-sources/${entry.id}`,
        as: `/v1/modules/${moduleId}/as-entries/${entry.id}`,
      } as const
      await apiMutate(pathByKind[kind], 'DELETE', undefined, { idempotent: false })
      toast.success('Удалено')
      setDeleteTarget(null)
      await onChanged()
    } catch (e) {
      toast.error(e instanceof ApiError ? e.message : String(e))
    } finally {
      setDeleting(false)
    }
  }

  return (
    <>
      <Card>
        <CardHeader className="flex flex-col gap-3 border-b py-3 sm:flex-row sm:items-center sm:justify-between">
          <div className="min-w-0 flex-1">
            <CardTitle className="text-base">{meta.title}</CardTitle>
            <CardDescription>{meta.description}</CardDescription>
          </div>
          <div className="flex shrink-0 flex-wrap items-center justify-end gap-2 self-start sm:self-auto">
            <Button size="sm" onClick={openCreate}>
              <Plus />
              Добавить
            </Button>
          </div>
        </CardHeader>
        <CardContent className="p-0">
          <QueryState
            data={items}
            isLoading={isLoading}
            isError={isError}
            error={error}
            empty={items.length === 0}
            emptyTitle={meta.emptyTitle}
            emptyDescription={meta.emptyDescription}
            skeleton={<TableSkeleton rows={5} cols={3} />}
            onRetry={onRetry}
          >
            {(rows) => (
              <EntriesTable
                mod={mod}
                rows={rows}
                communities={communities}
                onEdit={(target) => {
                  if (target.kind === 'domain') setEditDomain(target.entry)
                  if (target.kind === 'ip-range') setEditIpRange(target.entry)
                  if (target.kind === 'cdn') setEditCdn(target.entry)
                  if (target.kind === 'as') setEditAs(target.entry)
                  setDialogOpen(true)
                }}
                onDelete={setDeleteTarget}
              />
            )}
          </QueryState>
        </CardContent>
      </Card>

      {mod.type === 'DOMAINS' ? (
        <ModuleDomainEntryDialog
          open={dialogOpen}
          moduleId={moduleId}
          edit={editDomain}
          communities={communities}
          onOpenChange={(open) => (open ? setDialogOpen(true) : closeDialog())}
          onSaved={onChanged}
        />
      ) : null}
      {mod.type === 'IP_RANGES' ? (
        <ModuleIpRangeEntryDialog
          open={dialogOpen}
          moduleId={moduleId}
          edit={editIpRange}
          communities={communities}
          onOpenChange={(open) => (open ? setDialogOpen(true) : closeDialog())}
          onSaved={onChanged}
        />
      ) : null}
      {mod.type === 'CDN_CIDRS' ? (
        <ModuleCdnSourceDialog
          open={dialogOpen}
          moduleId={moduleId}
          edit={editCdn}
          communities={communities}
          onOpenChange={(open) => (open ? setDialogOpen(true) : closeDialog())}
          onSaved={onChanged}
        />
      ) : null}
      {mod.type === 'AS_PREFIXES' ? (
        <ModuleAsEntryDialog
          open={dialogOpen}
          moduleId={moduleId}
          edit={editAs}
          communities={communities}
          onOpenChange={(open) => (open ? setDialogOpen(true) : closeDialog())}
          onSaved={onChanged}
        />
      ) : null}

      <AlertDialog open={deleteTarget !== null} onOpenChange={(open) => !open && setDeleteTarget(null)}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>Удалить запись?</AlertDialogTitle>
            <AlertDialogDescription>{deleteDescription(deleteTarget)}</AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel disabled={deleting}>Отмена</AlertDialogCancel>
            <AlertDialogAction
              variant="destructive"
              disabled={deleting}
              onClick={() => void confirmDelete()}
            >
              {deleting ? 'Удаление…' : 'Удалить'}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </>
  )
}

function deleteDescription(target: DeleteTarget | null): string {
  if (!target) return ''
  switch (target.kind) {
    case 'domain':
      return target.entry.fqdn
    case 'ip-range':
      return target.entry.prefix
    case 'cdn':
      return target.entry.url
    case 'as':
      return `AS${target.entry.asn}`
  }
}

function EntriesTable({
  mod,
  rows,
  communities,
  onEdit,
  onDelete,
}: {
  mod: ModuleRow
  rows: Record<string, unknown>[]
  communities: BgpCommunity[]
  onEdit: (target: DeleteTarget) => void
  onDelete: (target: DeleteTarget) => void
}) {
  if (mod.type === 'DOMAINS') {
    const entries = rows as unknown as DomainEntry[]
    return (
      <Table>
        <TableHeader>
          <TableRow>
            <TableHead>FQDN</TableHead>
            <TableHead>Community</TableHead>
            <TableHead className="w-20" />
          </TableRow>
        </TableHeader>
        <TableBody>
          {entries.map((entry) => (
            <TableRow key={entry.id}>
              <TableCell className="font-mono text-sm">{entry.fqdn}</TableCell>
              <TableCell className="text-sm text-muted-foreground">
                {communityLabel(entry.community_id, communities)}
              </TableCell>
              <TableCell>
                <RowActions
                  onEdit={() => onEdit({ kind: 'domain', entry })}
                  onDelete={() => onDelete({ kind: 'domain', entry })}
                />
              </TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    )
  }

  if (mod.type === 'IP_RANGES') {
    const entries = rows as unknown as IpRangeEntry[]
    return (
      <Table>
        <TableHeader>
          <TableRow>
            <TableHead>Префикс (CIDR)</TableHead>
            <TableHead>Community</TableHead>
            <TableHead className="w-20" />
          </TableRow>
        </TableHeader>
        <TableBody>
          {entries.map((entry) => (
            <TableRow key={entry.id}>
              <TableCell className="font-mono text-sm">{entry.prefix}</TableCell>
              <TableCell className="text-sm text-muted-foreground">
                {communityLabel(entry.community_id, communities)}
              </TableCell>
              <TableCell>
                <RowActions
                  onEdit={() => onEdit({ kind: 'ip-range', entry })}
                  onDelete={() => onDelete({ kind: 'ip-range', entry })}
                />
              </TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    )
  }

  if (mod.type === 'CDN_CIDRS') {
    const entries = rows as unknown as CdnSource[]
    return (
      <Table>
        <TableHeader>
          <TableRow>
            <TableHead>URL</TableHead>
            <TableHead>Тип</TableHead>
            <TableHead>Community</TableHead>
            <TableHead>Обновлено</TableHead>
            <TableHead className="w-20" />
          </TableRow>
        </TableHeader>
        <TableBody>
          {entries.map((entry) => (
            <TableRow key={entry.id}>
              <TableCell className="max-w-xs truncate font-mono text-xs">{entry.url}</TableCell>
              <TableCell className="text-sm">{entry.source_kind}</TableCell>
              <TableCell className="text-sm text-muted-foreground">
                {communityLabel(entry.community_id, communities)}
              </TableCell>
              <TableCell className="text-xs text-muted-foreground">
                {formatDateTime(entry.last_refreshed_at)}
              </TableCell>
              <TableCell>
                <RowActions
                  onEdit={() => onEdit({ kind: 'cdn', entry })}
                  onDelete={() => onDelete({ kind: 'cdn', entry })}
                />
              </TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    )
  }

  const entries = rows as unknown as AsEntry[]
  return (
    <Table>
      <TableHeader>
        <TableRow>
          <TableHead>ASN</TableHead>
          <TableHead>Имя</TableHead>
          <TableHead>Префиксов</TableHead>
          <TableHead>Community</TableHead>
          <TableHead className="w-20" />
        </TableRow>
      </TableHeader>
      <TableBody>
        {entries.map((entry) => (
          <TableRow key={entry.id}>
            <TableCell className="font-mono text-sm">{entry.asn}</TableCell>
            <TableCell className="text-sm">{entry.asn_name ?? '—'}</TableCell>
            <TableCell className="font-mono text-sm">{entry.prefix_count ?? '—'}</TableCell>
            <TableCell className="text-sm text-muted-foreground">
              {communityLabel(entry.community_id, communities)}
            </TableCell>
            <TableCell>
              <RowActions
                onEdit={() => onEdit({ kind: 'as', entry })}
                onDelete={() => onDelete({ kind: 'as', entry })}
              />
            </TableCell>
          </TableRow>
        ))}
      </TableBody>
    </Table>
  )
}

function RowActions({ onEdit, onDelete }: { onEdit: () => void; onDelete: () => void }) {
  return (
    <div className="flex justify-end gap-1">
      <Button variant="ghost" size="icon-sm" onClick={onEdit} aria-label="Редактировать">
        <Pencil className="size-3.5" />
      </Button>
      <Button
        variant="ghost"
        size="icon-sm"
        className="text-destructive"
        onClick={onDelete}
        aria-label="Удалить"
      >
        <Trash2 className="size-3.5" />
      </Button>
    </div>
  )
}
