import { useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  Alert,
  Badge,
  Box,
  Button,
  FileButton,
  Group,
  Loader,
  Paper,
  Progress,
  Stack,
  Text,
  Textarea,
  ThemeIcon,
  Tooltip,
} from "@mantine/core";
import {
  AlertCircle,
  CheckCircle2,
  Download,
  Eye,
  FileCheck2,
  FileText,
  MessageSquareWarning,
  Upload,
} from "lucide-react";
import toast from "react-hot-toast";
import type { Freight } from "@edr/types";
import { isViewable } from "@edr/ui-common";

import { SectionCard } from "./SectionCard";
import { bookingsService } from "@/services/bookings.service";
import {
  downloadBookingFile,
  fetchViewableFile,
} from "@/services/files.service";
import { useFileViewer } from "@/hooks/useFileViewer";

export interface ClearanceReviewSectionProps {
  bookingId: string;
  /** Called after any review/finalize mutation so the parent can refetch. */
  onChanged?: () => void;
  /** Hide the inline progress summary (e.g. when the parent renders its own). */
  hideSummary?: boolean;
  /** Lock approve actions after document review phase completes. */
  approvalsLocked?: boolean;
  /** Block new queries after pre-clearance finalization. */
  queriesLocked?: boolean;
  /** Read-only audit view — no approve/query actions. */
  readOnly?: boolean;
  /**
   * GENERAL customs bookings use the phased milestone workflow (same as
   * ONE_TIME contracts): hide the legacy output-documents upload block and the
   * finalize button — declaration/duty/transit run in the phased action panel.
   */
  phasedCustoms?: boolean;
}

const STATUS_META: Record<
  Freight.DocumentReviewStatus,
  { label: string; color: string }
> = {
  APPROVED: { label: "Approved", color: "edr-green" },
  QUERIED: { label: "Queried", color: "red" },
  PENDING: { label: "Pending", color: "gray" },
};

/**
 * Staff-facing clearance document review: approve / query each customer
 * document, upload customs output documents (customs bookings only) and
 * finalize once every required document is approved. Shared by the Global
 * Logistics clearance detail page (customs) and the Marketing booking detail
 * (non-customs) — the only difference is the output-docs block, which renders
 * only when the booking has a customs output set.
 */
export function ClearanceReviewSection({
  bookingId,
  onChanged,
  hideSummary,
  approvalsLocked = false,
  queriesLocked = false,
  readOnly = false,
  phasedCustoms = false,
}: ClearanceReviewSectionProps) {
  const qc = useQueryClient();
  const [queryNotes, setQueryNotes] = useState<Record<string, string>>({});
  const [openQuery, setOpenQuery] = useState<Record<string, boolean>>({});
  const [uploadingKey, setUploadingKey] = useState<string | null>(null);
  const { view, viewer } = useFileViewer();

  const { data: clearance, isLoading } = useQuery({
    queryKey: ["clearance", bookingId],
    queryFn: () => bookingsService.getClearance(bookingId),
  });

  const refresh = () => {
    qc.invalidateQueries({ queryKey: ["clearance", bookingId] });
    qc.invalidateQueries({ queryKey: ["clearance", "list"] });
    onChanged?.();
  };

  const reviewMutation = useMutation({
    mutationFn: (p: {
      fileKey: string;
      status: "APPROVED" | "QUERIED";
      note?: string;
    }) => bookingsService.reviewClearanceDocument(bookingId, p),
    onSuccess: (_d, p) => {
      toast.success(
        p.status === "APPROVED" ? "Document approved" : "Query sent to customer",
      );
      if (p.status === "QUERIED")
        setOpenQuery((o) => ({ ...o, [p.fileKey]: false }));
      refresh();
    },
    onError: () => toast.error("Could not update document"),
  });

  const outputMutation = useMutation({
    mutationFn: (files: Record<string, File>) =>
      bookingsService.uploadClearanceOutput(bookingId, files),
    onSuccess: () => {
      toast.success("Document uploaded");
      setUploadingKey(null);
      refresh();
    },
    onError: () => {
      toast.error("Upload failed");
      setUploadingKey(null);
    },
  });

  const finalizeMutation = useMutation({
    mutationFn: () => bookingsService.finalizeClearance(bookingId),
    onSuccess: () => {
      toast.success("Document approval finalized");
      refresh();
    },
    onError: (e) =>
      toast.error(
        e instanceof Error
          ? e.message
          : "Could not finalize document approval",
      ),
  });

  const customerDocs = useMemo(
    () => (clearance?.documents ?? []).filter((d) => d.uploadedBy === "customer"),
    [clearance],
  );
  const glDocs = useMemo(
    () => (clearance?.documents ?? []).filter((d) => d.uploadedBy === "gl"),
    [clearance],
  );

  const stats = useMemo(() => {
    const total = customerDocs.length;
    const approved = customerDocs.filter(
      (d) => d.reviewStatus === "APPROVED",
    ).length;
    const queried = customerDocs.filter(
      (d) => d.reviewStatus === "QUERIED",
    ).length;
    const pending = total - approved - queried;
    const pct = total === 0 ? 0 : Math.round((approved / total) * 100);
    return { total, approved, queried, pending, pct };
  }, [customerDocs]);

  const hasDocsAwaitingApproval = customerDocs.some(
    (d) => d.file && d.reviewStatus !== "APPROVED",
  );
  const effectiveApprovalsLocked = approvalsLocked && !hasDocsAwaitingApproval;

  if (isLoading || !clearance) {
    return (
      <Group justify="center" py="xl" gap={10}>
        <Loader size="sm" color="edr-green" />
        <Text c="dimmed">Loading clearance…</Text>
      </Group>
    );
  }

  return (
    <Stack gap="lg">
      <SectionCard
        icon={FileText}
        title="Customer documents"
        subtitle="Approve each document, or open a query to tell the customer what to fix."
        extra={
          <Text size="xs" c="dimmed" fw={600}>
            {stats.approved}/{stats.total} approved
          </Text>
        }
      >
        <Stack gap={12}>
          {!hideSummary && stats.total > 0 && (
            <Box>
              <Progress
                value={stats.pct}
                color="edr-green"
                radius="xl"
                size="sm"
                mb={6}
              />
              <Group gap="lg">
                <StatPill color="edr-green" label="Approved" value={stats.approved} />
                <StatPill color="red" label="Queried" value={stats.queried} />
                <StatPill color="gray" label="Pending" value={stats.pending} />
              </Group>
            </Box>
          )}
          {customerDocs.length === 0 ? (
            <Text size="sm" c="dimmed">
              No customer documents are required for this booking.
            </Text>
          ) : (
            customerDocs.map((doc) => (
              <DocReviewCard
                key={`${doc.settingCode}:${doc.fileKey}`}
                doc={doc}
                approvalsLocked={effectiveApprovalsLocked}
                queriesLocked={queriesLocked}
                readOnly={readOnly}
                note={queryNotes[doc.fileKey] ?? ""}
                queryOpen={openQuery[doc.fileKey] ?? false}
                onToggleQuery={(open) =>
                  setOpenQuery((o) => ({ ...o, [doc.fileKey]: open }))
                }
                onNote={(v) =>
                  setQueryNotes((n) => ({ ...n, [doc.fileKey]: v }))
                }
                onApprove={() =>
                  reviewMutation.mutate({
                    fileKey: doc.fileKey,
                    status: "APPROVED",
                  })
                }
                onQuery={() =>
                  reviewMutation.mutate({
                    fileKey: doc.fileKey,
                    status: "QUERIED",
                    note: queryNotes[doc.fileKey],
                  })
                }
                onView={view}
                busy={reviewMutation.isPending}
              />
            ))
          )}
        </Stack>
      </SectionCard>

      {clearance.outputCode && !phasedCustoms && (
        <SectionCard
          icon={Upload}
          title="Customs output documents"
          subtitle="Upload each document individually — changes save immediately."
          accent="edr-green"
        >
          <Stack gap={10}>
            {glDocs.map((doc) => {
              const isUploading =
                uploadingKey === doc.fileKey && outputMutation.isPending;
              return (
                <Group key={doc.fileKey} justify="space-between" wrap="nowrap">
                  <Group gap={8} wrap="nowrap" style={{ minWidth: 0 }}>
                    <FileText size={16} color="var(--mantine-color-edr-green-6)" />
                    <Text fz="13px" c="edr-text" truncate>
                      {doc.label}
                      {doc.required ? " *" : ""}
                    </Text>
                  </Group>
                  <Group gap={8} wrap="nowrap">
                    {doc.file ? (
                      <>
                        {isViewable({
                          name: doc.file.name,
                          url: "",
                        }) && (
                          <Tooltip label="View">
                            <Box
                              component="button"
                              type="button"
                              onClick={() =>
                                void fetchViewableFile(
                                  doc.file!.id,
                                  doc.file!.name,
                                ).then(view)
                              }
                              c="edr-green"
                              style={{
                                display: "flex",
                                background: "transparent",
                                border: "none",
                                cursor: "pointer",
                              }}
                            >
                              <Eye size={15} />
                            </Box>
                          </Tooltip>
                        )}
                        <Tooltip label="Download">
                          <Box
                            component="button"
                            type="button"
                            onClick={() =>
                              void downloadBookingFile(
                                doc.file!.id,
                                doc.file!.name,
                              )
                            }
                            c="edr-green"
                            style={{
                              display: "flex",
                              background: "transparent",
                              border: "none",
                              cursor: "pointer",
                            }}
                          >
                            <Download size={15} />
                          </Box>
                        </Tooltip>
                      </>
                    ) : (
                      <Text fz="12px" c="edr-muted">
                        Not uploaded
                      </Text>
                    )}
                    <FileButton
                      onChange={(f) => {
                        if (!f) return;
                        setUploadingKey(doc.fileKey);
                        outputMutation.mutate({ [doc.fileKey]: f });
                      }}
                      accept="application/pdf,image/*"
                      disabled={isUploading}
                    >
                      {(props) => (
                        <Button
                          {...props}
                          size="compact-xs"
                          variant="light"
                          color="edr-green"
                          leftSection={
                            isUploading ? (
                              <Loader size={12} color="edr-green" />
                            ) : (
                              <Upload size={13} />
                            )
                          }
                          loading={isUploading}
                        >
                          {doc.file ? "Replace" : "Upload"}
                        </Button>
                      )}
                    </FileButton>
                  </Group>
                </Group>
              );
            })}
          </Stack>
        </SectionCard>
      )}

      {!phasedCustoms && finalizeMutation.isError && (
        <Alert color="red" radius="md" icon={<AlertCircle size={16} />}>
          {finalizeMutation.error instanceof Error
            ? finalizeMutation.error.message
            : "Could not finalize document approval."}
        </Alert>
      )}

      {phasedCustoms ? (
        // Phased (GENERAL customs) — no legacy finalize; the milestone steps in
        // the action panel drive the workflow, same as ONE_TIME contracts.
        <Paper withBorder radius="md" p="md">
          <Group gap={8} wrap="nowrap" style={{ minWidth: 0 }}>
            <ThemeIcon
              variant="light"
              color={clearance.allApproved ? "edr-green" : "gray"}
              radius="md"
              size={28}
            >
              {clearance.allApproved ? (
                <CheckCircle2 size={15} />
              ) : (
                <FileCheck2 size={15} />
              )}
            </ThemeIcon>
            <Text fz="12.5px" c="dimmed">
              {clearance.allApproved
                ? "All required documents are approved. Continue declaration, duty, and transit in the action panel."
                : "Approve every required document to unlock the customs milestone steps."}
            </Text>
          </Group>
        </Paper>
      ) : clearance.status !== "DOCUMENTS_UNDER_REVIEW" ? (
        // Finalize is only valid from DOCUMENTS_UNDER_REVIEW (the API rejects
        // any other status with a 409) — once the booking moved on, show the
        // finalized state instead of a button that can only fail.
        <Paper withBorder radius="md" p="md">
          <Group gap={8} wrap="nowrap" style={{ minWidth: 0 }}>
            <ThemeIcon
              variant="light"
              color={clearance.allApproved ? "edr-green" : "gray"}
              radius="md"
              size={28}
            >
              {clearance.allApproved ? (
                <CheckCircle2 size={15} />
              ) : (
                <FileCheck2 size={15} />
              )}
            </ThemeIcon>
            <Text fz="12.5px" c="dimmed">
              {clearance.allApproved
                ? "Clearance has been finalized. The customer can now pick a shipment day and proceed to operation."
                : "Finalization unlocks once the customer submits their documents and every required document is approved."}
            </Text>
          </Group>
        </Paper>
      ) : (
        <Paper withBorder radius="md" p="md">
          <Group justify="space-between" wrap="nowrap">
            <Group gap={8} wrap="nowrap" style={{ minWidth: 0 }}>
              <ThemeIcon
                variant="light"
                color={clearance.allApproved ? "edr-green" : "gray"}
                radius="md"
                size={28}
              >
                <FileCheck2 size={15} />
              </ThemeIcon>
              <Text fz="12.5px" c="dimmed">
                {clearance.allApproved
                  ? "All required documents are approved — you can finalize."
                  : "Approve every required document to unlock finalization."}
              </Text>
            </Group>
            <Button
              color="edr-green"
              radius="md"
              leftSection={<CheckCircle2 size={16} />}
              disabled={!clearance.allApproved}
              loading={finalizeMutation.isPending}
              onClick={() => finalizeMutation.mutate()}
            >
              Finalize document approval
            </Button>
          </Group>
        </Paper>
      )}
      {viewer}
    </Stack>
  );
}

function StatPill({
  color,
  label,
  value,
}: {
  color: string;
  label: string;
  value: number;
}) {
  return (
    <Group gap={6} wrap="nowrap">
      <Box
        style={{
          width: 8,
          height: 8,
          borderRadius: 999,
          background: `var(--mantine-color-${color}-6)`,
        }}
      />
      <Text fz="12.5px" c="edr-text" fw={600}>
        {value}
      </Text>
      <Text fz="12.5px" c="dimmed">
        {label}
      </Text>
    </Group>
  );
}

function DocReviewCard({
  doc,
  approvalsLocked,
  queriesLocked,
  readOnly,
  note,
  queryOpen,
  onToggleQuery,
  onNote,
  onApprove,
  onQuery,
  onView,
  busy,
}: {
  doc: Freight.ClearanceDocument;
  approvalsLocked: boolean;
  queriesLocked: boolean;
  readOnly: boolean;
  note: string;
  queryOpen: boolean;
  onToggleQuery: (open: boolean) => void;
  onNote: (v: string) => void;
  onApprove: () => void;
  onQuery: () => void;
  onView: (file: { name: string; url: string }) => void;
  busy: boolean;
}) {
  const status = doc.reviewStatus ?? "PENDING";
  const meta = STATUS_META[status];
  const hasFile = !!doc.file;
  const isApproved = status === "APPROVED";

  return (
    <Paper
      withBorder
      radius="md"
      p="md"
      style={{
        borderColor:
          status === "QUERIED"
            ? "var(--mantine-color-red-2)"
            : status === "APPROVED"
              ? "var(--mantine-color-edr-green-2)"
              : "var(--mantine-color-edr-border-6)",
      }}
    >
      <Group justify="space-between" align="flex-start" wrap="nowrap">
        <Group gap={12} wrap="nowrap" style={{ minWidth: 0 }}>
          <ThemeIcon
            variant="light"
            color={hasFile ? "edr-green" : "gray"}
            radius="md"
            size={40}
          >
            <FileText size={19} />
          </ThemeIcon>
          <Box style={{ minWidth: 0 }}>
            <Text fz="14px" fw={700} c="edr-text" truncate>
              {doc.label}
              {doc.required ? " *" : ""}
            </Text>
            <Text fz="12px" c="edr-muted" truncate>
              {hasFile ? doc.file!.name : "Not uploaded by customer"}
            </Text>
          </Box>
        </Group>

        <Group gap={8} wrap="nowrap">
          <Badge variant="light" color={meta.color} radius="sm">
            {meta.label}
          </Badge>
          {hasFile &&
            isViewable({
              name: doc.file!.name,
              url: "",
            }) && (
              <Tooltip label="Preview document">
                <Button
                  size="compact-xs"
                  variant="default"
                  radius="md"
                  leftSection={<Eye size={13} />}
                  onClick={() =>
                    void fetchViewableFile(doc.file!.id, doc.file!.name).then(
                      onView,
                    )
                  }
                >
                  View
                </Button>
              </Tooltip>
            )}
        </Group>
      </Group>

      {status === "QUERIED" && doc.note && (
        <Alert
          mt="sm"
          color="red"
          variant="light"
          radius="md"
          icon={<MessageSquareWarning size={15} />}
          p="xs"
        >
          <Text fz="12.5px" c="red.9">
            {doc.note}
          </Text>
        </Alert>
      )}

      {hasFile && !readOnly && (
        <Box mt="sm">
          {!queryOpen ? (
            <Group justify="flex-end" gap={8}>
              {!queriesLocked && (
                <Button
                  size="compact-sm"
                  variant="light"
                  color="red"
                  radius="md"
                  leftSection={<MessageSquareWarning size={14} />}
                  disabled={busy}
                  onClick={() => onToggleQuery(true)}
                >
                  Open query
                </Button>
              )}
              {!isApproved && !approvalsLocked && (
                <Button
                  size="compact-sm"
                  color="edr-green"
                  radius="md"
                  leftSection={<CheckCircle2 size={14} />}
                  disabled={busy}
                  onClick={onApprove}
                >
                  Approve
                </Button>
              )}
            </Group>
          ) : (
            <Box
              p="sm"
              style={{
                borderRadius: 12,
                background: "var(--mantine-color-red-0)",
                border: "1px solid var(--mantine-color-red-2)",
              }}
            >
              <Group gap={6} mb={6}>
                <MessageSquareWarning
                  size={14}
                  color="var(--mantine-color-red-7)"
                />
                <Text fz="12.5px" fw={700} c="red.8">
                  Describe the problem for the customer
                </Text>
              </Group>
              <Textarea
                placeholder="e.g. The commercial invoice is missing the HS code and the totals don't match the packing list."
                value={note}
                onChange={(e) => onNote(e.currentTarget.value)}
                autosize
                minRows={2}
                radius="md"
                size="sm"
                autoFocus
              />
              <Group justify="flex-end" gap={8} mt={8}>
                <Button
                  size="compact-sm"
                  variant="subtle"
                  color="gray"
                  radius="md"
                  disabled={busy}
                  onClick={() => onToggleQuery(false)}
                >
                  Cancel
                </Button>
                <Button
                  size="compact-sm"
                  color="red"
                  radius="md"
                  leftSection={<MessageSquareWarning size={14} />}
                  loading={busy}
                  disabled={!note.trim()}
                  onClick={onQuery}
                >
                  Send query to customer
                </Button>
              </Group>
            </Box>
          )}
        </Box>
      )}
    </Paper>
  );
}
