import { useCallback, useEffect, useMemo, useState } from 'react';
import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Button } from '@/components/ui/button';
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import {
  ShieldCheck,
  ExternalLink,
  ChevronLeft,
  ChevronRight,
  RefreshCw,
  Download,
  Loader2,
  Check,
} from 'lucide-react';
import { apiFetch } from '@/lib/api';
import { toast } from '@/components/ui/toast-store';
import { cn } from '@/lib/utils';
import type {
  VulnerabilityScan,
  VulnerabilityDetail,
  VulnSeverity,
} from '@/types/security';

interface VulnerabilityScanSheetProps {
  scanId: number | null;
  onClose: () => void;
  onRescan?: (imageRef: string) => void;
  canGenerateSbom?: boolean;
}

type SeverityFilter = 'ALL' | VulnSeverity;

const PAGE_SIZE = 25;

const SEVERITY_CLASSES: Record<VulnSeverity, string> = {
  CRITICAL: 'text-destructive border-destructive/40 bg-destructive/10',
  HIGH: 'text-warning border-warning/40 bg-warning/10',
  MEDIUM: 'text-info border-info/40 bg-info/10',
  LOW: 'text-muted-foreground border-border bg-muted/30',
  UNKNOWN: 'text-muted-foreground border-border bg-muted/20',
};

function SeverityChip({ severity }: { severity: VulnSeverity }) {
  return (
    <span
      className={cn(
        'inline-flex items-center gap-1 rounded border px-1.5 py-0.5 text-[10px] font-mono tabular-nums uppercase tracking-wide',
        SEVERITY_CLASSES[severity],
      )}
    >
      {severity}
    </span>
  );
}

export function VulnerabilityScanSheet({
  scanId,
  onClose,
  onRescan,
  canGenerateSbom = false,
}: VulnerabilityScanSheetProps) {
  const [scan, setScan] = useState<VulnerabilityScan | null>(null);
  const [details, setDetails] = useState<VulnerabilityDetail[]>([]);
  const [loading, setLoading] = useState(false);
  const [severityFilter, setSeverityFilter] = useState<SeverityFilter>('ALL');
  const [page, setPage] = useState(0);
  const [downloadingSbom, setDownloadingSbom] = useState(false);

  const load = useCallback(async () => {
    if (scanId == null) return;
    setLoading(true);
    try {
      const [scanRes, detailsRes] = await Promise.all([
        apiFetch(`/security/scans/${scanId}`),
        apiFetch(`/security/scans/${scanId}/vulnerabilities?limit=500`),
      ]);
      if (!scanRes.ok) throw new Error('Failed to fetch scan');
      if (!detailsRes.ok) throw new Error('Failed to fetch vulnerabilities');
      const scanData = await scanRes.json();
      const detailsData = await detailsRes.json();
      setScan(scanData);
      setDetails(Array.isArray(detailsData.items) ? detailsData.items : []);
      setPage(0);
    } catch (err) {
      toast.error((err as Error)?.message || 'Failed to load scan');
    } finally {
      setLoading(false);
    }
  }, [scanId]);

  useEffect(() => {
    if (scanId != null) load();
    else {
      setScan(null);
      setDetails([]);
      setSeverityFilter('ALL');
      setPage(0);
    }
  }, [scanId, load]);

  const filtered = useMemo(() => {
    if (severityFilter === 'ALL') return details;
    return details.filter((d) => d.severity === severityFilter);
  }, [details, severityFilter]);

  const totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
  const safePage = Math.min(page, totalPages - 1);
  const pageItems = filtered.slice(safePage * PAGE_SIZE, (safePage + 1) * PAGE_SIZE);
  const needsPagination = filtered.length > PAGE_SIZE;

  const downloadSbom = useCallback(
    async (format: 'spdx-json' | 'cyclonedx') => {
      if (!scan) return;
      setDownloadingSbom(true);
      try {
        const res = await apiFetch('/security/sbom', {
          method: 'POST',
          body: JSON.stringify({ imageRef: scan.image_ref, format }),
        });
        if (!res.ok) {
          const body = await res.json().catch(() => ({}));
          throw new Error(body?.error || 'Failed to generate SBOM');
        }
        const blob = await res.blob();
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `${scan.image_ref.replace(/[^a-z0-9]+/gi, '_')}-sbom-${format}.json`;
        document.body.appendChild(a);
        a.click();
        a.remove();
        URL.revokeObjectURL(url);
        toast.success('SBOM downloaded');
      } catch (err) {
        toast.error((err as Error)?.message || 'SBOM generation failed');
      } finally {
        setDownloadingSbom(false);
      }
    },
    [scan],
  );

  const exportCsv = useCallback(() => {
    if (!scan || details.length === 0) return;
    const header = 'CVE,Package,Severity,Installed,Fixed,URL\n';
    const escape = (v: string) => `"${v.replace(/"/g, '""')}"`;
    const rows = details
      .map((d) =>
        [
          escape(d.vulnerability_id),
          escape(d.pkg_name),
          escape(d.severity),
          escape(d.installed_version),
          escape(d.fixed_version ?? ''),
          escape(d.primary_url ?? ''),
        ].join(','),
      )
      .join('\n');
    const blob = new Blob([header + rows], { type: 'text/csv;charset=utf-8' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `${scan.image_ref.replace(/[^a-z0-9]+/gi, '_')}-vulnerabilities.csv`;
    document.body.appendChild(a);
    a.click();
    a.remove();
    URL.revokeObjectURL(url);
  }, [scan, details]);

  return (
    <Sheet open={scanId != null} onOpenChange={(open) => !open && onClose()}>
      <SheetContent className="sm:max-w-2xl flex flex-col p-0">
        <SheetHeader className="p-6 pb-4 border-b">
          <SheetTitle className="flex items-center gap-2 pr-6">
            <ShieldCheck className="w-4 h-4 text-muted-foreground" strokeWidth={1.5} />
            <span className="font-mono text-sm truncate">
              {scan?.image_ref ?? 'Loading...'}
            </span>
          </SheetTitle>
        </SheetHeader>

        {loading && !scan && (
          <div className="flex items-center justify-center flex-1">
            <Loader2 className="w-6 h-6 animate-spin text-muted-foreground" strokeWidth={1.5} />
          </div>
        )}

        {scan && (
          <div className="flex flex-col flex-1 min-h-0">
            {/* Summary stats */}
            <div className="px-6 py-4 border-b space-y-3">
              <div className="flex flex-wrap gap-2">
                {scan.critical_count > 0 && (
                  <span className={cn('rounded border px-2 py-1 text-xs font-mono tabular-nums', SEVERITY_CLASSES.CRITICAL)}>
                    {scan.critical_count} CRITICAL
                  </span>
                )}
                {scan.high_count > 0 && (
                  <span className={cn('rounded border px-2 py-1 text-xs font-mono tabular-nums', SEVERITY_CLASSES.HIGH)}>
                    {scan.high_count} HIGH
                  </span>
                )}
                {scan.medium_count > 0 && (
                  <span className={cn('rounded border px-2 py-1 text-xs font-mono tabular-nums', SEVERITY_CLASSES.MEDIUM)}>
                    {scan.medium_count} MEDIUM
                  </span>
                )}
                {scan.low_count > 0 && (
                  <span className={cn('rounded border px-2 py-1 text-xs font-mono tabular-nums', SEVERITY_CLASSES.LOW)}>
                    {scan.low_count} LOW
                  </span>
                )}
                {scan.total_vulnerabilities === 0 && (
                  <span className="rounded border border-success/40 bg-success/10 text-success px-2 py-1 text-xs font-mono tabular-nums uppercase">
                    No vulnerabilities
                  </span>
                )}
              </div>

              <div className="grid grid-cols-2 md:grid-cols-4 gap-3 text-xs">
                <div>
                  <div className="text-stat-subtitle uppercase tracking-wide">Total</div>
                  <div className="font-mono tabular-nums text-stat-value">{scan.total_vulnerabilities}</div>
                </div>
                <div>
                  <div className="text-stat-subtitle uppercase tracking-wide">Fixable</div>
                  <div className="font-mono tabular-nums text-success">{scan.fixable_count}</div>
                </div>
                <div>
                  <div className="text-stat-subtitle uppercase tracking-wide">Triggered</div>
                  <div className="font-mono text-stat-value">{scan.triggered_by}</div>
                </div>
                <div>
                  <div className="text-stat-subtitle uppercase tracking-wide">Scanned</div>
                  <div className="font-mono text-stat-value">
                    {new Date(scan.scanned_at).toLocaleString()}
                  </div>
                </div>
              </div>

              <div className="flex flex-wrap items-center gap-2 pt-2">
                {onRescan && (
                  <Button
                    variant="outline"
                    size="sm"
                    onClick={() => onRescan(scan.image_ref)}
                    disabled={scan.status === 'in_progress'}
                  >
                    <RefreshCw className="w-3.5 h-3.5 mr-1.5" strokeWidth={1.5} />
                    Re-scan
                  </Button>
                )}
                {canGenerateSbom && (
                  <DropdownMenu>
                    <DropdownMenuTrigger asChild>
                      <Button variant="outline" size="sm" disabled={downloadingSbom}>
                        {downloadingSbom ? (
                          <Loader2 className="w-3.5 h-3.5 mr-1.5 animate-spin" strokeWidth={1.5} />
                        ) : (
                          <Download className="w-3.5 h-3.5 mr-1.5" strokeWidth={1.5} />
                        )}
                        SBOM
                      </Button>
                    </DropdownMenuTrigger>
                    <DropdownMenuContent align="end">
                      <DropdownMenuItem onClick={() => downloadSbom('spdx-json')}>
                        SPDX JSON
                      </DropdownMenuItem>
                      <DropdownMenuItem onClick={() => downloadSbom('cyclonedx')}>
                        CycloneDX
                      </DropdownMenuItem>
                    </DropdownMenuContent>
                  </DropdownMenu>
                )}
                <Button variant="outline" size="sm" onClick={exportCsv} disabled={details.length === 0}>
                  <Download className="w-3.5 h-3.5 mr-1.5" strokeWidth={1.5} />
                  CSV
                </Button>
              </div>
            </div>

            {/* Severity filter tabs */}
            <div className="px-6 pt-3 flex items-center gap-1 flex-wrap">
              {(['ALL', 'CRITICAL', 'HIGH', 'MEDIUM', 'LOW'] as SeverityFilter[]).map((s) => (
                <Button
                  key={s}
                  variant={severityFilter === s ? 'default' : 'ghost'}
                  size="sm"
                  className="h-7 text-xs px-2.5"
                  onClick={() => {
                    setSeverityFilter(s);
                    setPage(0);
                  }}
                >
                  {s}
                </Button>
              ))}
              {needsPagination && (
                <div className="flex items-center gap-1 ml-auto">
                  <Button
                    variant="ghost"
                    size="icon"
                    className="h-6 w-6"
                    onClick={() => setPage(Math.max(0, safePage - 1))}
                    disabled={safePage === 0}
                  >
                    <ChevronLeft className="w-4 h-4" strokeWidth={1.5} />
                  </Button>
                  <span className="text-xs font-mono tabular-nums text-stat-subtitle min-w-[3rem] text-center">
                    {safePage + 1} / {totalPages}
                  </span>
                  <Button
                    variant="ghost"
                    size="icon"
                    className="h-6 w-6"
                    onClick={() => setPage(Math.min(totalPages - 1, safePage + 1))}
                    disabled={safePage >= totalPages - 1}
                  >
                    <ChevronRight className="w-4 h-4" strokeWidth={1.5} />
                  </Button>
                </div>
              )}
            </div>

            <ScrollArea className="flex-1 min-h-0">
              <div className="px-6 py-3">
                {pageItems.length === 0 ? (
                  <div className="text-center text-sm text-muted-foreground py-12">
                    {details.length === 0
                      ? 'No vulnerabilities found.'
                      : 'No vulnerabilities match the selected filter.'}
                  </div>
                ) : (
                  <Table>
                    <TableHeader>
                      <TableRow>
                        <TableHead className="w-[180px]">CVE</TableHead>
                        <TableHead>Package</TableHead>
                        <TableHead className="w-[100px]">Severity</TableHead>
                        <TableHead className="w-[110px]">Installed</TableHead>
                        <TableHead className="w-[110px]">Fixed</TableHead>
                      </TableRow>
                    </TableHeader>
                    <TableBody>
                      {pageItems.map((d) => (
                        <TableRow key={d.id}>
                          <TableCell className="font-mono text-xs">
                            {d.primary_url ? (
                              <a
                                href={d.primary_url}
                                target="_blank"
                                rel="noreferrer noopener"
                                className="inline-flex items-center gap-1 hover:underline"
                              >
                                {d.vulnerability_id}
                                <ExternalLink className="w-3 h-3" strokeWidth={1.5} />
                              </a>
                            ) : (
                              d.vulnerability_id
                            )}
                          </TableCell>
                          <TableCell className="font-mono text-xs truncate max-w-[180px]" title={d.pkg_name}>
                            {d.pkg_name}
                          </TableCell>
                          <TableCell>
                            <SeverityChip severity={d.severity} />
                          </TableCell>
                          <TableCell className="font-mono text-xs">{d.installed_version}</TableCell>
                          <TableCell className="font-mono text-xs">
                            {d.fixed_version ? (
                              <span className="inline-flex items-center gap-1 text-success">
                                <Check className="w-3 h-3" strokeWidth={1.5} />
                                {d.fixed_version}
                              </span>
                            ) : (
                              <span className="text-muted-foreground">-</span>
                            )}
                          </TableCell>
                        </TableRow>
                      ))}
                    </TableBody>
                  </Table>
                )}
              </div>
            </ScrollArea>
          </div>
        )}
      </SheetContent>
    </Sheet>
  );
}

export { SeverityChip };
export type { VulnerabilityScanSheetProps };
