import { useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  Alert,
  Box,
  Button,
  Center,
  Group,
  Loader,
  Paper,
  Stack,
  Text,
} from "@mantine/core";
import {
  AlertCircle,
  CheckCircle2,
  Clock,
  Download,
  Eye,
  Upload,
} from "lucide-react";

import { isViewable } from "@edr/ui-common";
import { api } from "@/services/api";
import { fetchViewableFile, downloadStoredFile } from "@/services/files.service";
import {
  ClearanceAdHocUploadSection,
  type AdHocDoc,
} from "@/components/contracts/ClearanceAdHocUploadSection";
import { ClearanceDocumentUploadCard } from "@/components/contracts/ClearanceDocumentUploadCard";
import { ClearanceUploadedDocumentsPanel } from "@/components/contracts/ClearanceUploadedDocumentsPanel";
import { useFileViewer } from "@/hooks/useFileViewer";
import { IconSquare } from "@/pages/bookings/BookingDetailPage/components/Documents";

const BORDER = "#E6ECF2";

export interface ContractClearancePanelProps {
  contractId: string;
  tradeDirection?: string;
  /** Show the loading state without the surrounding Paper (e.g. inside a modal). */
  bare?: boolean;
  /** Called after a successful document submission (e.g. to close the host modal). */
  onSubmitted?: () => void;
}

/**
 * The clearance document workspace for a contract: shows the customer-input doc
 * grid + GL output docs, lets the customer upload / re-upload (only queried docs
 * after first submission), and surfaces query notes. Rendered both on the
 * standalone clearance page and inside the contract action modal. See
 * docs/new-doc.md §8.3.
 */
export function ContractClearancePanel({
  contractId,
  tradeDirection = "IMPORT",
  bare,
  onSubmitted,
}: ContractClearancePanelProps) {
  const queryClient = useQueryClient();
  const [pending, setPending] = useState<Record<string, File>>({});
  const [adHoc, setAdHoc] = useState<AdHocDoc[]>([]);
  const { view, viewer } = useFileViewer();

  const clearanceQuery = useQuery(
    api.contracts.getClearance.queryOptions({
      input: { id: contractId },
      enabled: !!contractId,
    }),
  );
  const clearance = clearanceQuery.data;

  const uploadMutation = useMutation({
    ...api.contracts.uploadClearanceDocuments.mutationOptions(),
    onSuccess: () => {
      setPending({});
      setAdHoc([]);
      queryClient.invalidateQueries({
        queryKey: api.contracts.getClearance.queryKey({ id: contractId }),
      });
      queryClient.invalidateQueries({
        queryKey: api.contracts.get.queryKey({ id: contractId }),
      });
      // Submitting moves the contract to CLEARANCE_UNDER_REVIEW — refresh every
      // contracts-list query (prefix key) so the /contracts table row and its
      // action button update without a page reload.
      queryClient.invalidateQueries({
        queryKey: api.contracts.list.queryKey(),
      });
      onSubmitted?.();
    },
  });

  const customerDocs = useMemo(() => {
    const docs = (clearance?.documents ?? []).filter(
      (d) => d.uploadedBy === "customer",
    );
    // Surface queried documents (the ones needing correction) first.
    const rank = (s: string | null) =>
      s === "QUERIED" ? 0 : s === "APPROVED" ? 2 : 1;
    return [...docs].sort(
      (a, b) => rank(a.reviewStatus) - rank(b.reviewStatus),
    );
  }, [clearance]);

  const queriedCount = useMemo(
    () => customerDocs.filter((d) => d.reviewStatus === "QUERIED").length,
    [customerDocs],
  );
  const glDocs = useMemo(
    () => (clearance?.documents ?? []).filter((d) => d.uploadedBy !== "customer"),
    [clearance],
  );

  const status = clearance?.clearanceStatus ?? "AWAITING_DOCUMENTS";
  const isUnderReview = status === "DOCUMENTS_UNDER_REVIEW";
  const isReady =
    status === "CLEARANCE_READY_FOR_BOOKING" ||
    status === "SELF_CLEARED" ||
    status === "ACTIVE_SHIPMENT_IN_PROGRESS";
  const canUpload = status === "AWAITING_DOCUMENTS" || isUnderReview;
  const isInitialUpload = status === "AWAITING_DOCUMENTS";

  const customsPath = clearance?.includesCustoms ?? true;
  const reviewer = customsPath ? "Global Logistics" : "the Operations team";

  const missingRequired = useMemo(
    () => customerDocs.filter((d) => d.required && !d.file && !pending[d.fileKey]),
    [customerDocs, pending],
  );

  const hasStagedFiles =
    Object.keys(pending).length > 0 || adHoc.some((r) => r.file);

  const canSubmit = isInitialUpload
    ? hasStagedFiles && missingRequired.length === 0
    : hasStagedFiles;

  const stagePending = (fileKey: string, file: File | null) =>
    setPending((p) => {
      if (file) return { ...p, [fileKey]: file };
      const next = { ...p };
      delete next[fileKey];
      return next;
    });

  const submitDocuments = () => {
    const files: Record<string, File | null> = { ...pending };
    adHoc.forEach((row, i) => {
      if (row.file) files[`custom_${Date.now()}_${i}`] = row.file;
    });
    if (Object.keys(files).length === 0) return;
    uploadMutation.mutate({ id: contractId, files });
  };

  if (clearanceQuery.isLoading) {
    return (
      <Center mih={bare ? 200 : 400} p="xl">
        <Loader color="edr-green" />
      </Center>
    );
  }

  const body = (
    <Stack gap={0}>
      {queriedCount > 0 && (
        <Alert
          color="red"
          radius="md"
          icon={<AlertCircle size={18} />}
          mb="md"
          title={`${queriedCount} document${queriedCount > 1 ? "s" : ""} need correction`}
        >
          Re-upload the highlighted document{queriedCount > 1 ? "s" : ""} below to
          continue. The reviewer's note explains what to fix.
        </Alert>
      )}
      {isReady ? (
        <Alert color="teal" radius="md" icon={<CheckCircle2 size={18} />} mb="md">
          {customsPath
            ? "Your clearance documents are approved. Global Logistics will create your booking on your behalf — you will be notified when payment is due."
            : "Your clearance documents are approved. You can now create a shipment booking under this contract."}
        </Alert>
      ) : isUnderReview ? (
        <Alert color="blue" radius="md" icon={<Clock size={18} />} mb="md">
          {reviewer.charAt(0).toUpperCase() + reviewer.slice(1)} is reviewing
          your documents. Only re-upload the documents flagged with a query
          below — approved documents stay as they are.
        </Alert>
      ) : (
        <Alert color="yellow" radius="md" icon={<AlertCircle size={18} />} mb="md">
          {customsPath
            ? "Upload every required clearance document (marked *) below to start the review. Global Logistics will clear your shipment and create the booking for you."
            : "This service does not include EDR customs clearance — clear the cargo yourself and upload every required clearance document (marked *) below. The Operations team will review them before you can book a shipment."}
        </Alert>
      )}

      {isInitialUpload && missingRequired.length > 0 && (
        <Alert color="yellow" variant="light" radius="md" mb="md" p="xs">
          <Text fz="12px" c="#9A5B00">
            Still required: {missingRequired.map((d) => d.label).join(", ")}
          </Text>
        </Alert>
      )}

      {/* Required customer documents */}
      <Stack gap="md">
        <Box>
          <Text fz={13} fw={700} c="#10202F">
            Your clearance documents
          </Text>
          <Text fz={12} c="dimmed" mt={4}>
            Upload each required document below. Items marked * are mandatory.
          </Text>
        </Box>
        {customerDocs.map((doc) => (
          <ClearanceDocumentUploadCard
            key={doc.fileKey}
            label={doc.label}
            required={doc.required}
            reviewStatus={doc.reviewStatus}
            note={doc.note}
            uploadedFile={doc.file}
            stagedFile={pending[doc.fileKey] ?? null}
            canUpload={canUpload}
            onStageFile={
              canUpload && doc.reviewStatus !== "APPROVED"
                ? (file) => stagePending(doc.fileKey, file)
                : undefined
            }
            onPreview={view}
          />
        ))}
        {customerDocs.length === 0 && (
          <Text fz="sm" c="dimmed">
            No clearance documents are configured for this contract yet.
          </Text>
        )}
      </Stack>

      {/* GL output documents (read-only). */}
      {glDocs.length > 0 && (
        <>
          <Text fz="12.5px" fw={700} c="#10202F" mt="lg" mb={8}>
            Customs output documents
          </Text>
          <Stack gap={8}>
            {glDocs.map((doc) => (
              <Group
                key={doc.fileKey}
                justify="space-between"
                wrap="nowrap"
                className="rounded-xl"
                style={{ border: `1px solid ${BORDER}`, padding: 10 }}
              >
                <Text fz="13px" c="#10202F" truncate>
                  {doc.label}
                </Text>
                {doc.file ? (
                  <Group gap={8} wrap="nowrap">
                    {isViewable({
                      name: doc.file.name,
                      url: "",
                    }) && (
                      <IconSquare
                        icon={<Eye size={15} />}
                        onClick={() =>
                          void fetchViewableFile(
                            doc.file!.id,
                            doc.file!.name,
                          ).then(view)
                        }
                      />
                    )}
                    <IconSquare
                      icon={<Download size={15} />}
                      onClick={() =>
                        void downloadStoredFile(doc.file!.id, doc.file!.name)
                      }
                    />
                  </Group>
                ) : (
                  <Text fz="12px" c="#9AA8B5">
                    Pending
                  </Text>
                )}
              </Group>
            ))}
          </Stack>
        </>
      )}

      <Box mt="lg">
        <ClearanceUploadedDocumentsPanel
          embedded
          tradeDirection={tradeDirection}
          files={clearance?.workflowFiles ?? []}
          title="Customs workflow documents"
          onView={(f) => view(f)}
          onDownload={({ id, name }) => void downloadStoredFile(id, name)}
        />
      </Box>

      {canUpload ? (
        <ClearanceAdHocUploadSection
          rows={adHoc}
          onAdd={() => setAdHoc((r) => [...r, { name: "", file: null }])}
          onRemove={(i) => setAdHoc((rows) => rows.filter((_, j) => j !== i))}
          onNameChange={(i, name) =>
            setAdHoc((rows) => rows.map((r, j) => (j === i ? { ...r, name } : r)))
          }
          onFileChange={(i, file) =>
            setAdHoc((rows) => rows.map((r, j) => (j === i ? { ...r, file } : r)))
          }
          onPreview={view}
        />
      ) : null}

      {uploadMutation.isError && (
        <Alert color="red" radius="md" icon={<AlertCircle size={16} />} mt="md">
          {uploadMutation.error instanceof Error
            ? uploadMutation.error.message
            : "Upload failed. Please try again."}
        </Alert>
      )}

      {canUpload && (
        <Group justify="flex-end" mt="xl">
          <Button
            color="edr-green"
            radius="md"
            size="md"
            leftSection={<Upload size={16} />}
            disabled={!canSubmit}
            loading={uploadMutation.isPending}
            onClick={submitDocuments}
          >
            {isInitialUpload ? "Submit documents" : "Re-upload documents"}
          </Button>
        </Group>
      )}

      {viewer}
    </Stack>
  );

  if (bare) return body;

  return (
    <Paper withBorder radius={20} p="lg" style={{ borderColor: BORDER }}>
      {body}
    </Paper>
  );
}

export default ContractClearancePanel;
