import {
  ActionIcon,
  Box,
  Button,
  Group,
  Modal,
  Stack,
  Text,
  TextInput,
} from "@mantine/core";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  AlertCircle,
  Download,
  Pencil,
  Send,
  Upload,
  X,
  XCircle,
} from "lucide-react";

import { useMemo, useRef, useState } from "react";
import { useNavigate } from "react-router-dom";

import { api } from "@/services/api";
import type { SubmitBookingResponse } from "@/services/bookings.service";
import type { Freight } from "@edr/types";

import { REQUIRED_DOC_FIELDS } from "./constants";
import { CardTitle, PageShell, SectionCard } from "./components/layout";
import { CountChip, DocRow, IconSquare } from "./components/Documents";
import { EstimateCard } from "./components/pricing";
import { HeaderButton, PageHeader } from "./components/PageHeader";
import {
  ActionRequiredBanner,
  MutationErrors,
  NoticeBanner,
} from "./components/Notices";
import { ScheduleCard } from "./components/ScheduleCard";
import { ShipmentDetailsCard } from "./components/ShipmentDetailsCard";
import { StatusHero } from "./components/StatusHero";
import { StepGhostButton, StepLine } from "./components/Steps";
import { SupportCard } from "./components/SupportCard";
import { BodyGrid } from "./components/layout";

export function DraftBookingView({
  booking,
  onBookingUpdated,
}: {
  booking: Freight.IBooking;
  onBookingUpdated: () => void;
}) {
  const navigate = useNavigate();
  const queryClient = useQueryClient();
  const fileInputRefs = useRef<Record<string, HTMLInputElement | null>>({});
  const documentsRef = useRef<HTMLDivElement>(null);

  const [selectedFiles, setSelectedFiles] = useState<
    Record<string, File | null>
  >({});
  const [cancelDialogOpen, setCancelDialogOpen] = useState(false);
  const [cancelReason, setCancelReason] = useState("");
  const [docError, setDocError] = useState("");
  const [priceChangeModal, setPriceChangeModal] =
    useState<SubmitBookingResponse | null>(null);

  const anyFileSelected = Object.values(selectedFiles).some(Boolean);
  const uploadedCodes = useMemo(
    () => new Set(booking.files?.map((f) => f.code) ?? []),
    [booking.files],
  );
  const uploadedCount = REQUIRED_DOC_FIELDS.filter((d) =>
    uploadedCodes.has(d.key),
  ).length;
  const allDocsUploaded = uploadedCount === REQUIRED_DOC_FIELDS.length;

  const { data: generatedPricing } = useQuery(
    api.bookings.generatePrice.queryOptions({
      input: { id: booking.id },
      enabled:
        (booking.status === "DRAFT" || booking.status === "CHANGES_REQUESTED") &&
        !booking.pricingBreakdown,
    }),
  );
  const pricing = (booking.pricingBreakdown ??
    generatedPricing ??
    null) as Freight.PricingBreakdown | null;

  const uploadMutation = useMutation({
    mutationFn: async (files: Record<string, File | File[] | null>) => {
      if (booking.status === "CHANGES_REQUESTED") {
        const result = await api.bookings.update.call({
          id: booking.id,
          dto: {},
          documents: files,
        });
        return result.booking;
      }
      return api.bookings.uploadDocuments.call({ id: booking.id, files });
    },
    onSuccess: () => {
      setSelectedFiles({});
      setDocError("");
      onBookingUpdated();
    },
  });

  const submitMutation = useMutation({
    mutationFn: () => api.bookings.submit.call({ id: booking.id }),
    onSuccess: (result) => {
      if (result.priceChanged) {
        setPriceChangeModal(result);
        return;
      }
      onBookingUpdated();
      queryClient.invalidateQueries({ queryKey: api.bookings.list.queryKey() });
    },
  });

  const confirmSubmitMutation = useMutation({
    mutationFn: () => api.bookings.confirmSubmit.call({ id: booking.id }),
    onSuccess: () => {
      setPriceChangeModal(null);
      onBookingUpdated();
      queryClient.invalidateQueries({ queryKey: api.bookings.list.queryKey() });
    },
  });

  const cancelMutation = useMutation({
    mutationFn: (reason: string) =>
      api.bookings.cancel.call({ id: booking.id, reason }),
    onSuccess: () => {
      setCancelDialogOpen(false);
      onBookingUpdated();
    },
  });

  function handleFileSelect(key: string, file: File | null) {
    setSelectedFiles((prev) => ({ ...prev, [key]: file }));
  }

  function handleUploadAll() {
    const filesToUpload: Record<string, File | null> = {};
    for (const doc of REQUIRED_DOC_FIELDS) {
      if (selectedFiles[doc.key])
        filesToUpload[doc.key] = selectedFiles[doc.key]!;
    }
    if (Object.keys(filesToUpload).length === 0) return;
    uploadMutation.mutate(filesToUpload);
  }

  function handleSubmitRequest() {
    const missing = REQUIRED_DOC_FIELDS.filter(
      (doc) => !uploadedCodes.has(doc.key),
    );
    if (missing.length > 0) {
      setDocError("Please upload all required documents before submitting.");
      documentsRef.current?.scrollIntoView({ behavior: "smooth" });
      return;
    }
    submitMutation.mutate();
  }

  const completeStep = allDocsUploaded ? 3 : 2;

  return (
    <PageShell>
      <PageHeader
        booking={booking}
        actions={
          <HeaderButton
            dark
            icon={<Pencil size={16} />}
            label="Continue editing"
            onClick={() => navigate(`/bookings/${booking.id}/edit`)}
          />
        }
        menuActions={{
          onCancel: () => setCancelDialogOpen(true),
          onSupport: () => navigate("/support"),
        }}
      />

      <MutationErrors
        mutations={[
          uploadMutation,
          submitMutation,
          confirmSubmitMutation,
          cancelMutation,
        ]}
      />

      <StatusHero booking={booking}>
        {booking.status === "CHANGES_REQUESTED" &&
        booking.latestChangeRequestNote ? (
          <ActionRequiredBanner
            title="Review the requested changes, then resubmit."
            onAction={() =>
              navigate(`/bookings/${booking.id}/edit?section=documents`)
            }
          >
            {booking.latestChangeRequestNote}
          </ActionRequiredBanner>
        ) : undefined}
      </StatusHero>

      <BodyGrid
        left={
          <>
            {/* Complete your booking */}
            <SectionCard>
              <Group justify="space-between" align="center" mb="md">
                <CardTitle>Complete your booking</CardTitle>
                <Text fz="12.5px" fw={600} c="#9AA8B5">
                  Step {completeStep} of 3
                </Text>
              </Group>
              <Stack gap={4}>
                <StepLine index={1} done title="Cargo & route details" />
                <StepLine
                  index={2}
                  active={!allDocsUploaded}
                  done={allDocsUploaded}
                  title={
                    allDocsUploaded
                      ? "Required documents"
                      : "Upload required documents"
                  }
                  desc={`${uploadedCount} of ${REQUIRED_DOC_FIELDS.length} uploaded.`}
                  action={
                    <StepGhostButton
                      icon={<Upload size={16} color="#334155" />}
                      onClick={() =>
                        documentsRef.current?.scrollIntoView({
                          behavior: "smooth",
                        })
                      }
                    >
                      Add documents
                    </StepGhostButton>
                  }
                />
                <StepLine
                  index={3}
                  active={allDocsUploaded}
                  title="Review & submit"
                  desc="Send your booking to EDR staff."
                />
              </Stack>
              <Button
                fullWidth
                mt="lg"
                radius={10}
                color="#0C1A2B"
                leftSection={<Send size={16} />}
                onClick={handleSubmitRequest}
                disabled={submitMutation.isPending}
                loading={submitMutation.isPending}
                styles={{
                  root: { height: 46 },
                  label: { fontSize: 14, fontWeight: 800 },
                }}
              >
                {submitMutation.isPending ? "Submitting…" : "Submit for review"}
              </Button>
            </SectionCard>

            <ShipmentDetailsCard booking={booking} />

            {/* Documents (uploadable) */}
            <SectionCard ref={documentsRef}>
              <Group justify="space-between" align="center" mb="md">
                <Group gap={10} align="center">
                  <CardTitle>Documents</CardTitle>
                  <CountChip
                    uploaded={uploadedCount}
                    total={REQUIRED_DOC_FIELDS.length}
                  />
                </Group>
              </Group>

              {docError && (
                <NoticeBanner
                  tone="red"
                  icon={<AlertCircle size={16} />}
                  className="mb-3"
                >
                  {docError}
                </NoticeBanner>
              )}

              <Box>
                {REQUIRED_DOC_FIELDS.map((doc, i) => {
                  const isUploaded = uploadedCodes.has(doc.key);
                  const selected = selectedFiles[doc.key];
                  const file = booking.files?.find((f) => f.code === doc.key);
                  const allowReplace =
                    !isUploaded || booking.status === "CHANGES_REQUESTED";
                  return (
                    <DocRow
                      key={doc.key}
                      last={i === REQUIRED_DOC_FIELDS.length - 1}
                      title={doc.label}
                      meta={
                        isUploaded
                          ? (file?.name ?? "Uploaded")
                          : selected
                            ? selected.name
                            : "Not added yet"
                      }
                      status={
                        isUploaded ? "verified" : selected ? "ready" : "missing"
                      }
                      action={
                        isUploaded && !allowReplace ? (
                          <IconSquare
                            href={file?.signedUrl ?? file?.url}
                            icon={<Download size={16} />}
                          />
                        ) : (
                          <>
                            {isUploaded && (
                              <IconSquare
                                href={file?.signedUrl ?? file?.url}
                                icon={<Download size={16} />}
                              />
                            )}
                            <input
                              ref={(el) => {
                                fileInputRefs.current[doc.key] = el;
                              }}
                              type="file"
                              accept=".pdf,.jpg,.jpeg,.png"
                              style={{ display: "none" }}
                              onChange={(e) =>
                                handleFileSelect(
                                  doc.key,
                                  e.target.files?.[0] ?? null,
                                )
                              }
                            />
                            <Group gap={6} wrap="nowrap">
                              <Button
                                variant="white"
                                radius={9}
                                leftSection={<Upload size={16} color="#334155" />}
                                onClick={() =>
                                  fileInputRefs.current[doc.key]?.click()
                                }
                                styles={{
                                  root: {
                                    height: 34,
                                    paddingInline: 13,
                                    border: "1.5px solid #CBD5E1",
                                  },
                                  label: {
                                    fontSize: 12.5,
                                    fontWeight: 700,
                                    color: "#334155",
                                  },
                                }}
                              >
                                {selected ? "Change" : isUploaded ? "Replace" : "Add"}
                              </Button>
                              {selected && (
                                <ActionIcon
                                  variant="default"
                                  radius={8}
                                  w={34}
                                  h={34}
                                  onClick={() => handleFileSelect(doc.key, null)}
                                  style={{ color: "#C0392B" }}
                                >
                                  <X size={15} />
                                </ActionIcon>
                              )}
                            </Group>
                          </>
                        )
                      }
                    />
                  );
                })}
              </Box>

              {anyFileSelected && (
                <Button
                  mt="md"
                  radius={10}
                  color="edr-green"
                  leftSection={
                    uploadMutation.isPending ? undefined : <Upload size={16} />
                  }
                  onClick={handleUploadAll}
                  disabled={uploadMutation.isPending}
                  loading={uploadMutation.isPending}
                  styles={{ root: { height: 44 }, label: { fontWeight: 700 } }}
                >
                  {uploadMutation.isPending
                    ? "Uploading…"
                    : "Upload selected documents"}
                </Button>
              )}
            </SectionCard>
          </>
        }
        right={
          <>
            <EstimateCard
              pricing={pricing}
              title="Estimated Cost"
              chip="Not invoiced"
            />
            <ScheduleCard booking={booking} title="Schedule & Service" />
            <SupportCard onCancel={() => setCancelDialogOpen(true)} />
          </>
        }
      />

      <Modal
        opened={priceChangeModal !== null}
        onClose={() => setPriceChangeModal(null)}
        title={<Text fw={700}>Price has changed</Text>}
        radius="lg"
        centered
      >
        {priceChangeModal && (
          <Stack gap="md">
            <Text size="sm" c="dimmed">
              {priceChangeModal.message ??
                "The booking price has been updated. Confirm to submit with the new total."}
            </Text>
            {priceChangeModal.previousTotalAmount !== undefined && (
              <Group justify="space-between">
                <Text size="sm" c="dimmed">
                  Previous total
                </Text>
                <Text size="sm" td="line-through">
                  {priceChangeModal.previousTotalAmount.toLocaleString()}{" "}
                  {priceChangeModal.currency}
                </Text>
              </Group>
            )}
            <Group justify="space-between">
              <Text fw={700}>New total</Text>
              <Text fw={800} c="edr-green">
                {priceChangeModal.totalAmount.toLocaleString()}{" "}
                {priceChangeModal.currency}
              </Text>
            </Group>
            {priceChangeModal.lineItems && priceChangeModal.lineItems.length > 0 && (
              <Stack gap={4}>
                {priceChangeModal.lineItems.map((item) => (
                  <Group key={item.code} justify="space-between">
                    <Text size="sm" c="dimmed">
                      {item.description}
                    </Text>
                    <Text size="sm" fw={600}>
                      {item.amount.toLocaleString()} {item.currency}
                    </Text>
                  </Group>
                ))}
              </Stack>
            )}
            <Group justify="flex-end" gap="sm">
              <Button
                variant="default"
                radius="md"
                onClick={() => setPriceChangeModal(null)}
              >
                Review later
              </Button>
              <Button
                color="edr-green"
                radius="md"
                loading={confirmSubmitMutation.isPending}
                onClick={() => confirmSubmitMutation.mutate()}
              >
                Confirm & submit
              </Button>
            </Group>
          </Stack>
        )}
      </Modal>

      <Modal
        opened={cancelDialogOpen}
        onClose={() => setCancelDialogOpen(false)}
        title={<Text fw={700}>Cancel booking</Text>}
        radius="lg"
        centered
      >
        <Stack gap="md">
          <Text size="sm" c="dimmed">
            Are you sure you want to cancel <strong>{booking.reference}</strong>
            ? This action cannot be undone.
          </Text>
          <TextInput
            label="Reason for cancellation (optional)"
            placeholder="e.g. Change of plans, duplicate booking…"
            value={cancelReason}
            onChange={(e) => setCancelReason(e.currentTarget.value)}
            radius="md"
            data-autofocus
          />
          <Group justify="flex-end" gap="sm">
            <Button
              variant="default"
              radius="md"
              onClick={() => setCancelDialogOpen(false)}
            >
              Keep booking
            </Button>
            <Button
              color="red"
              radius="md"
              onClick={() =>
                cancelMutation.mutate(
                  cancelReason.trim() || "Cancelled by customer",
                )
              }
              disabled={cancelMutation.isPending}
              loading={cancelMutation.isPending}
              leftSection={
                !cancelMutation.isPending ? <XCircle size={15} /> : undefined
              }
            >
              Yes, cancel
            </Button>
          </Group>
        </Stack>
      </Modal>
    </PageShell>
  );
}
