"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import {
  Alert,
  Button,
  Card,
  Descriptions,
  Space,
  Statistic,
  Table,
  Tabs,
  Tag,
  Tooltip,
  Typography,
  message,
} from "antd";
import type { ColumnsType, TablePaginationConfig } from "antd/es/table";
import { ArrowLeftOutlined, ReloadOutlined, SyncOutlined } from "@ant-design/icons";
import dayjs from "dayjs";
import Link from "next/link";
import { useParams } from "next/navigation";

import { PageStateNotice } from "@/components/common/page-state-notice";
import {
  fetchScanBatch,
  fetchScanCallbackReceipts,
  fetchScanObservations,
  fetchScanTargets,
  syncScanBatch,
} from "@/lib/api/scans";
import { useAuth } from "@/lib/hooks/use-auth";
import type {
  ScanBatch,
  ScanCallbackReceipt,
  ScanObservation,
  ScanTarget,
} from "@/types/scans";

const { Title, Paragraph, Text } = Typography;

const MANAGE_PERMISSION = "scan:manage_batches";

const statusColors: Record<string, string> = {
  draft: "default",
  submitting: "processing",
  queued: "blue",
  running: "geekblue",
  completed: "green",
  failed: "red",
  canceled: "default",
  sync_failed: "volcano",
};

const targetStatusColors: Record<string, string> = {
  pending: "default",
  accepted: "green",
  rejected: "red",
};

const resultColors: Record<string, string> = {
  confirmed_open: "red",
  confirmed_closed: "green",
  unknown_or_filtered: "gold",
  skipped: "default",
};

function formatDate(value?: string | null) {
  return value ? dayjs(value).format("YYYY-MM-DD HH:mm") : "-";
}

function formatNumber(value?: number | null) {
  return typeof value === "number" ? value.toLocaleString() : "0";
}

function statusTag(value?: string | null) {
  const status = value || "unknown";
  return <Tag color={statusColors[status] || targetStatusColors[status] || resultColors[status] || "default"}>{status.replaceAll("_", " ").toUpperCase()}</Tag>;
}

export default function ScanBatchDetailPage() {
  const params = useParams<{ id: string }>();
  const batchId = params.id;
  const { hasPermission } = useAuth();
  const canManage = hasPermission(MANAGE_PERMISSION);

  const [batch, setBatch] = useState<ScanBatch | null>(null);
  const [batchLoading, setBatchLoading] = useState(false);
  const [batchError, setBatchError] = useState<string | null>(null);
  const [syncing, setSyncing] = useState(false);

  const [targets, setTargets] = useState<ScanTarget[]>([]);
  const [targetTotal, setTargetTotal] = useState(0);
  const [targetPagination, setTargetPagination] = useState<TablePaginationConfig>({ current: 1, pageSize: 20 });
  const [targetsLoading, setTargetsLoading] = useState(false);

  const [observations, setObservations] = useState<ScanObservation[]>([]);
  const [observationTotal, setObservationTotal] = useState(0);
  const [observationPagination, setObservationPagination] = useState<TablePaginationConfig>({ current: 1, pageSize: 20 });
  const [observationsLoading, setObservationsLoading] = useState(false);

  const [rejectedTargets, setRejectedTargets] = useState<ScanTarget[]>([]);
  const [rejectedTotal, setRejectedTotal] = useState(0);
  const [rejectedPagination, setRejectedPagination] = useState<TablePaginationConfig>({ current: 1, pageSize: 20 });
  const [rejectedLoading, setRejectedLoading] = useState(false);

  const [receipts, setReceipts] = useState<ScanCallbackReceipt[]>([]);
  const [receiptTotal, setReceiptTotal] = useState(0);
  const [receiptPagination, setReceiptPagination] = useState<TablePaginationConfig>({ current: 1, pageSize: 20 });
  const [receiptsLoading, setReceiptsLoading] = useState(false);

  const loadBatch = useCallback(async () => {
    setBatchLoading(true);
    try {
      setBatch(await fetchScanBatch(batchId));
      setBatchError(null);
    } catch (error) {
      console.error("Failed to load scan batch", error);
      setBatch(null);
      setBatchError("This scan batch could not be loaded.");
    } finally {
      setBatchLoading(false);
    }
  }, [batchId]);

  const loadTargets = useCallback(
    async (page: number, pageSize: number) => {
      setTargetsLoading(true);
      try {
        const payload = await fetchScanTargets(batchId, { page, page_size: pageSize });
        setTargets(payload.items ?? []);
        setTargetTotal(payload.total ?? 0);
      } catch (error) {
        console.error("Failed to load scan targets", error);
        setTargets([]);
        setTargetTotal(0);
      } finally {
        setTargetsLoading(false);
      }
    },
    [batchId],
  );

  const loadObservations = useCallback(
    async (page: number, pageSize: number) => {
      setObservationsLoading(true);
      try {
        const payload = await fetchScanObservations(batchId, { page, page_size: pageSize });
        setObservations(payload.items ?? []);
        setObservationTotal(payload.total ?? 0);
      } catch (error) {
        console.error("Failed to load scan observations", error);
        setObservations([]);
        setObservationTotal(0);
      } finally {
        setObservationsLoading(false);
      }
    },
    [batchId],
  );

  const loadRejected = useCallback(
    async (page: number, pageSize: number) => {
      setRejectedLoading(true);
      try {
        const payload = await fetchScanTargets(batchId, {
          page,
          page_size: pageSize,
          target_status: "rejected",
        });
        setRejectedTargets(payload.items ?? []);
        setRejectedTotal(payload.total ?? 0);
      } catch (error) {
        console.error("Failed to load rejected scan targets", error);
        setRejectedTargets([]);
        setRejectedTotal(0);
      } finally {
        setRejectedLoading(false);
      }
    },
    [batchId],
  );

  const loadReceipts = useCallback(
    async (page: number, pageSize: number) => {
      setReceiptsLoading(true);
      try {
        const payload = await fetchScanCallbackReceipts(batchId, { page, page_size: pageSize });
        setReceipts(payload.items ?? []);
        setReceiptTotal(payload.total ?? 0);
      } catch (error) {
        console.error("Failed to load callback receipts", error);
        setReceipts([]);
        setReceiptTotal(0);
      } finally {
        setReceiptsLoading(false);
      }
    },
    [batchId],
  );

  useEffect(() => {
    void loadBatch();
  }, [loadBatch]);

  useEffect(() => {
    void loadTargets(targetPagination.current ?? 1, targetPagination.pageSize ?? 20);
  }, [loadTargets, targetPagination]);

  useEffect(() => {
    void loadObservations(observationPagination.current ?? 1, observationPagination.pageSize ?? 20);
  }, [loadObservations, observationPagination]);

  useEffect(() => {
    void loadRejected(rejectedPagination.current ?? 1, rejectedPagination.pageSize ?? 20);
  }, [loadRejected, rejectedPagination]);

  useEffect(() => {
    void loadReceipts(receiptPagination.current ?? 1, receiptPagination.pageSize ?? 20);
  }, [loadReceipts, receiptPagination]);

  const refreshAll = useCallback(() => {
    void loadBatch();
    void loadTargets(targetPagination.current ?? 1, targetPagination.pageSize ?? 20);
    void loadObservations(observationPagination.current ?? 1, observationPagination.pageSize ?? 20);
    void loadRejected(rejectedPagination.current ?? 1, rejectedPagination.pageSize ?? 20);
    void loadReceipts(receiptPagination.current ?? 1, receiptPagination.pageSize ?? 20);
  }, [
    loadBatch,
    loadObservations,
    loadReceipts,
    loadRejected,
    loadTargets,
    observationPagination,
    receiptPagination,
    rejectedPagination,
    targetPagination,
  ]);

  const handleSync = useCallback(async () => {
    if (!canManage) return;
    setSyncing(true);
    try {
      await syncScanBatch(batchId);
      message.success("Scan batch sync requested");
      refreshAll();
    } catch (error) {
      console.error("Failed to sync scan batch", error);
      message.error("Failed to sync scan batch");
    } finally {
      setSyncing(false);
    }
  }, [batchId, canManage, refreshAll]);

  const targetColumns: ColumnsType<ScanTarget> = useMemo(
    () => [
      {
        title: "Endpoint",
        key: "endpoint",
        width: 220,
        render: (_, record) => (
          <Space direction="vertical" size={2}>
            <Text strong>{record.public_ip}:{record.port}</Text>
            <Text type="secondary" style={{ fontSize: 12 }}>{record.transport?.toUpperCase() || "TCP"}</Text>
          </Space>
        ),
      },
      {
        title: "Status",
        dataIndex: "target_status",
        width: 130,
        render: statusTag,
      },
      {
        title: "Asset",
        key: "asset",
        width: 180,
        render: (_, record) => (
          <Space direction="vertical" size={2}>
            <Text>{record.caasm_asset_id ? `Asset #${record.caasm_asset_id}` : "-"}</Text>
            <Text type="secondary" style={{ fontSize: 12 }}>{record.resource_type || record.cloud_provider || "-"}</Text>
          </Space>
        ),
      },
      {
        title: "Owner / env",
        key: "owner",
        width: 180,
        render: (_, record) => (
          <Space direction="vertical" size={2}>
            <Text>{record.owner || "No owner"}</Text>
            <Text type="secondary" style={{ fontSize: 12 }}>{record.environment || "-"}</Text>
          </Space>
        ),
      },
      {
        title: "Scanner target",
        dataIndex: "scanner_target_id",
        width: 220,
        render: (value: string | null | undefined) => value || "-",
      },
    ],
    [],
  );

  const observationColumns: ColumnsType<ScanObservation> = useMemo(
    () => [
      {
        title: "Result",
        dataIndex: "result",
        width: 160,
        render: statusTag,
      },
      {
        title: "Endpoint",
        key: "endpoint",
        width: 210,
        render: (_, record) => <Text strong>{record.public_ip}:{record.port}/{record.transport || "tcp"}</Text>,
      },
      {
        title: "Evidence",
        key: "evidence",
        width: 360,
        render: (_, record) => (
          <Space direction="vertical" size={3}>
            <Text>
              {record.result === "unknown_or_filtered"
                ? "Inconclusive scanner result. CAASM facts are unchanged."
                : record.evidence_summary || "Scanner observation recorded."}
            </Text>
            <Text type="secondary" style={{ fontSize: 12 }}>
              Source {record.scanner_source_ip || "-"} · {record.connect_duration_ms != null ? `${record.connect_duration_ms} ms` : "duration -"} · job {record.scanner_job_id || "-"}
            </Text>
          </Space>
        ),
      },
      {
        title: "Asset context",
        key: "context",
        width: 220,
        render: (_, record) => (
          <Space direction="vertical" size={2}>
            <Text>{record.asset_name || (record.caasm_asset_id ? `Asset #${record.caasm_asset_id}` : "-")}</Text>
            <Text type="secondary" style={{ fontSize: 12 }}>{record.owner || "No owner"} / {record.environment || "-"}</Text>
          </Space>
        ),
      },
      {
        title: "Observed",
        dataIndex: "observed_at",
        width: 170,
        render: formatDate,
      },
    ],
    [],
  );

  const receiptColumns: ColumnsType<ScanCallbackReceipt> = useMemo(
    () => [
      {
        title: "Status",
        dataIndex: "status",
        width: 140,
        render: statusTag,
      },
      {
        title: "Idempotency",
        dataIndex: "idempotency_key",
        width: 260,
        render: (value: string | null | undefined) => value || "-",
      },
      {
        title: "Observations",
        dataIndex: "observation_count",
        width: 130,
        render: formatNumber,
      },
      {
        title: "Error",
        dataIndex: "error_message",
        width: 300,
        render: (value: string | null | undefined) => (
          <Tooltip title={value || ""}>
            <Text ellipsis style={{ maxWidth: 280, display: "block" }}>{value || "-"}</Text>
          </Tooltip>
        ),
      },
      {
        title: "Received",
        dataIndex: "received_at",
        width: 170,
        render: formatDate,
      },
      {
        title: "Processed",
        dataIndex: "processed_at",
        width: 170,
        render: formatDate,
      },
    ],
    [],
  );

  if (batchError && !batchLoading) {
    return (
      <PageStateNotice
        tone="error"
        title="Scan batch unavailable"
        description={batchError}
        actions={
          <Space wrap>
            <Button icon={<ReloadOutlined />} onClick={() => void loadBatch()}>
              Retry
            </Button>
            <Button href="/dashboard/scans/port-exposure">Back to Port Exposure</Button>
          </Space>
        }
      />
    );
  }

  return (
    <Space direction="vertical" size={20} style={{ width: "100%" }}>
      <Space align="start" style={{ justifyContent: "space-between", width: "100%" }} wrap>
        <div>
          <Link href="/dashboard/scans/port-exposure">
            <Space size={6}>
              <ArrowLeftOutlined />
              <span>Port Exposure</span>
            </Space>
          </Link>
          <Title level={3} style={{ marginBottom: 4, marginTop: 8 }}>
            {batch?.request_id || `Scan batch #${batchId}`}
          </Title>
          <Paragraph type="secondary" style={{ marginBottom: 0 }}>
            Batch details preserve scanner observations separately from CAASM inventory facts.
          </Paragraph>
        </div>
        <Space wrap>
          <Button icon={<ReloadOutlined />} onClick={refreshAll}>
            Refresh
          </Button>
          <Button icon={<SyncOutlined />} disabled={!canManage} loading={syncing} onClick={() => void handleSync()}>
            Sync results
          </Button>
        </Space>
      </Space>

      <div style={{ display: "grid", gap: 16, gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))" }}>
        <Card loading={batchLoading}>
          <Statistic title="Accepted targets" value={batch?.accepted_targets ?? 0} />
        </Card>
        <Card loading={batchLoading}>
          <Statistic title="Rejected targets" value={batch?.rejected_targets ?? 0} />
        </Card>
        <Card loading={batchLoading}>
          <Statistic title="Confirmed open" value={batch?.result_counts?.confirmed_open ?? 0} />
        </Card>
        <Card loading={batchLoading}>
          <Statistic title="Needs rescan" value={batch?.result_counts?.unknown_or_filtered ?? 0} />
        </Card>
      </div>

      <Card loading={batchLoading}>
        <Descriptions bordered column={{ xs: 1, md: 2, xl: 3 }} size="small">
          <Descriptions.Item label="Status">{batch ? statusTag(batch.status) : "-"}</Descriptions.Item>
          <Descriptions.Item label="Scanner batch">{batch?.scanner_batch_id || "-"}</Descriptions.Item>
          <Descriptions.Item label="Scanner source IP">{batch?.scanner_source_ip || "-"}</Descriptions.Item>
          <Descriptions.Item label="Submitted">{formatDate(batch?.submitted_at)}</Descriptions.Item>
          <Descriptions.Item label="Completed">{formatDate(batch?.completed_at)}</Descriptions.Item>
          <Descriptions.Item label="Last synced">{formatDate(batch?.last_synced_at)}</Descriptions.Item>
        </Descriptions>
      </Card>

      <Alert
        type="info"
        showIcon
        message="Inconclusive observations do not change CAASM"
        description="unknown_or_filtered rows mean the scanner could not establish a conclusion from its public egress point. CAASM port inventory remains the source of inventory facts."
      />

      <Tabs
        defaultActiveKey="targets"
        items={[
          {
            key: "targets",
            label: "Targets",
            children: (
              <Table
                rowKey="id"
                dataSource={targets}
                columns={targetColumns}
                loading={targetsLoading}
                pagination={{ ...targetPagination, total: targetTotal }}
                onChange={(pager) => setTargetPagination(pager)}
                locale={{ emptyText: <PageStateNotice tone="empty" compact title="No targets" description="No target snapshots are available for this batch." /> }}
                scroll={{ x: 980 }}
              />
            ),
          },
          {
            key: "observations",
            label: "Observations",
            children: (
              <Table
                rowKey="id"
                dataSource={observations}
                columns={observationColumns}
                loading={observationsLoading}
                pagination={{ ...observationPagination, total: observationTotal }}
                onChange={(pager) => setObservationPagination(pager)}
                locale={{ emptyText: <PageStateNotice tone="empty" compact title="No observations" description="Scanner observations will appear here after callback delivery or manual sync." /> }}
                scroll={{ x: 1100 }}
              />
            ),
          },
          {
            key: "rejected",
            label: "Rejected",
            children: (
              <Table
                rowKey="id"
                dataSource={rejectedTargets}
                columns={[
                  ...targetColumns,
                  {
                    title: "Reject reason",
                    key: "reject",
                    width: 300,
                    render: (_, record) => (
                      <Space direction="vertical" size={2}>
                        <Text>{record.reject_reason || "-"}</Text>
                        <Text type="secondary" style={{ fontSize: 12 }}>{record.reject_detail || "-"}</Text>
                      </Space>
                    ),
                  },
                ]}
                loading={rejectedLoading}
                pagination={{ ...rejectedPagination, total: rejectedTotal }}
                onChange={(pager) => setRejectedPagination(pager)}
                locale={{ emptyText: <PageStateNotice tone="empty" compact title="No rejected targets" description="Private, invalid, duplicate, or scanner-rejected targets are listed here when present." /> }}
                scroll={{ x: 1280 }}
              />
            ),
          },
          {
            key: "callbacks",
            label: "Callback Logs",
            children: (
              <Table
                rowKey="id"
                dataSource={receipts}
                columns={receiptColumns}
                loading={receiptsLoading}
                pagination={{ ...receiptPagination, total: receiptTotal }}
                onChange={(pager) => setReceiptPagination(pager)}
                locale={{ emptyText: <PageStateNotice tone="empty" compact title="No callback receipts" description="Callback delivery records will appear here when the scanner posts results." /> }}
                scroll={{ x: 1080 }}
              />
            ),
          },
        ]}
      />
    </Space>
  );
}
