import {
  ActionIcon,
  Alert,
  Badge,
  Button,
  Checkbox,
  Divider,
  Group,
  Loader,
  MultiSelect,
  NumberInput,
  Select,
  SimpleGrid,
  Stack,
  Text,
  TextInput,
} from "@mantine/core";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { Freight } from "@edr/types";
import { CheckCircle2, Clock, Download, Pencil, Plus, Trash2, Truck, Upload } from "lucide-react";
import { useState } from "react";
import toast from "react-hot-toast";

import { api } from "@/services/api";
import { customerTrucksService } from "@/services/customer-trucks.service";

import { CardTitle, SectionCard } from "./layout";
import { BulkTruckUploadModal } from "./BulkTruckUploadModal";
import { generateTruckAssignmentTemplate } from "@/utils/truck-assignment-template";

const TRUCK_TYPES = ["Flatbed", "Container Chassis", "Lowboy", "Box Truck", "Tipper"];

// Waybill-style selectable copies (indexes 1-8 in the API catalog). The 2 gate
// copies (Port Operations, Gate Security & Carrier) are always printed.
const FREIGHT_ORDER_COPIES = [
  { index: 1, label: "Original 1 (for Issuing Carrier)" },
  { index: 2, label: "Original 2 (for Consignee)" },
  { index: 3, label: "Original 3 (for Shipper)" },
  { index: 4, label: "Copy 4 (Delivery Receipt)" },
  { index: 5, label: "Copy 5 (Extra Copy)" },
  { index: 6, label: "Copy 6 (Extra Copy)" },
  { index: 7, label: "Copy 7 (Extra Copy)" },
  { index: 8, label: "Copy 8 (for Agent)" },
];

const downloadBlob = (blob: Blob, filename: string) => {
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = filename;
  document.body.appendChild(link);
  link.click();
  link.remove();
  URL.revokeObjectURL(url);
};

const errorMessage = (error: unknown, fallback: string) => {
  const data = (error as { response?: { data?: { message?: string | string[] } } })?.response?.data;
  if (Array.isArray(data?.message)) return data.message.join(", ");
  if (data?.message) return data.message;
  return error instanceof Error ? error.message : fallback;
};

export function CustomerTruckAssignmentCard({
  booking,
  onAssigned,
}: {
  booking: Freight.IBooking;
  onAssigned: () => void;
}) {
  const queryClient = useQueryClient();
  const trucksKey = ["customer-trucks", booking.id];

  const { data: trucks = [], isLoading } = useQuery({
    queryKey: trucksKey,
    queryFn: () => customerTrucksService.list(booking.id),
  });

  const [plateNumber, setPlateNumber] = useState("");
  const [driverName, setDriverName] = useState("");
  const [truckType, setTruckType] = useState("");
  const [containers, setContainers] = useState<string[]>([]);
  const [plannedTons, setPlannedTons] = useState<number | "">("");
  const [plannedQty, setPlannedQty] = useState<number | "">("");
  const [editingId, setEditingId] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [bulkModalOpen, setBulkModalOpen] = useState(false);

  // Container numbers on the booking that aren't already loaded onto a truck.
  const assignedNumbers = new Set(
    trucks.flatMap((t) => (t.containers ?? []).map((c) => c.containerNumber)),
  );
  // When editing a truck, its own containers stay selectable.
  const editingOwn = new Set(
    (trucks.find((t) => t.id === editingId)?.containers ?? []).map((c) => c.containerNumber),
  );
  const availableContainers = (booking.containerNumbers ?? []).filter(
    (n) => !assignedNumbers.has(n) || editingOwn.has(n),
  );
  // Containers on the booking not yet assigned to any truck (independent of edit).
  const pendingAssignmentCount = (booking.containerNumbers ?? []).filter(
    (n) => !assignedNumbers.has(n),
  ).length;

  // Both import and export specify the containers each truck carries.
  const resetForm = () => {
    setPlateNumber("");
    setDriverName("");
    setTruckType("");
    setContainers([]);
    setPlannedTons("");
    setPlannedQty("");
    setEditingId(null);
    setError(null);
  };

  const startEdit = (t: Freight.ICustomerTruck) => {
    const planned = t as Freight.ICustomerTruck & {
      plannedTons?: number | string | null;
      plannedQuantity?: number | null;
    };
    setPlateNumber(t.plateNumber ?? "");
    setDriverName(t.driverName ?? "");
    setTruckType(t.truckType ?? "");
    setContainers((t.containers ?? []).map((c) => c.containerNumber));
    setPlannedTons(planned.plannedTons != null ? Number(planned.plannedTons) : "");
    setPlannedQty(planned.plannedQuantity != null ? Number(planned.plannedQuantity) : "");
    setEditingId(t.id);
    setError(null);
  };

  // Bulk bookings have no containers — the truck hauls loose tonnage (weighed on
  // departure), so the container picker and its validation are skipped.
  const isBulk = String(booking.freightType) === "BULK";

  const addMutation = useMutation({
    mutationFn: () => {
      const payload = {
        truckPlateNumber: plateNumber.trim().toUpperCase(),
        driverName: driverName.trim(),
        truckType: truckType.trim(),
        containerNumbers: isBulk ? [] : containers,
        ...(isBulk
          ? {
              plannedTons: plannedTons === "" ? undefined : Number(plannedTons),
              plannedQuantity: plannedQty === "" ? undefined : Number(plannedQty),
            }
          : {}),
      };
      return editingId
        ? customerTrucksService.update(booking.id, editingId, payload)
        : customerTrucksService.add(booking.id, payload);
    },
    onSuccess: (list) => {
      queryClient.setQueryData(trucksKey, list);
      toast.success(editingId ? "Truck updated" : "Truck added");
      resetForm();
      onAssigned();
    },
    onError: (e) => setError(errorMessage(e, editingId ? "Could not update truck" : "Could not add truck")),
  });

  const removeMutation = useMutation({
    mutationFn: (assignmentId: string) => customerTrucksService.remove(booking.id, assignmentId),
    onSuccess: (list) => {
      queryClient.setQueryData(trucksKey, list);
      onAssigned();
    },
    onError: (e) => toast.error(errorMessage(e, "Could not remove truck")),
  });

  const downloadMutation = useMutation(api.bookings.downloadCustomerTruckFreightOrder.mutationOptions());
  const [selectedCopies, setSelectedCopies] = useState<number[]>(
    FREIGHT_ORDER_COPIES.map((c) => c.index),
  );
  const downloadFreightOrder = async () => {
    const blob = await downloadMutation.mutateAsync({ id: booking.id, copies: selectedCopies });
    downloadBlob(blob, `freight-order-${booking.reference}.pdf`);
  };

  const submitAdd = () => {
    if (!plateNumber.trim() || !driverName.trim() || !truckType.trim()) {
      setError("Plate number, driver name and truck type are required.");
      return;
    }
    if (!isBulk && (containers.length < 1 || containers.length > 2)) {
      setError("Select 1 or 2 container numbers for this truck.");
      return;
    }
    if (isBulk && plannedTons === "") {
      setError("Enter the tonnes this truck will haul.");
      return;
    }
    setError(null);
    addMutation.mutate();
  };

  return (
    <SectionCard>
      <Stack gap="md">
        <Group justify="space-between" align="center">
          <Group gap={10}>
            <Truck size={18} color="#0a9f6a" />
            <CardTitle>External Truck Assignment</CardTitle>
          </Group>
          <Group gap={12}>
            <Group gap="sm">
              <Button
                size="xs"
                variant="default"
                leftSection={<Download size={14} />}
                onClick={() => generateTruckAssignmentTemplate("truck-assignments.xlsx")}
              >
                Download Template
              </Button>
              <Button
                size="xs"
                variant="light"
                leftSection={<Upload size={14} />}
                onClick={() => setBulkModalOpen(true)}
              >
                Bulk Upload
              </Button>
            </Group>
            {pendingAssignmentCount > 0 && (
              <Text size="sm" fw={600} c="#b45309">
                {pendingAssignmentCount} container{pendingAssignmentCount !== 1 ? "s" : ""} pending assignment
              </Text>
            )}
            {trucks.length > 0 && (
              <Text size="sm" fw={700} c="#0a9f6a">
                {trucks.length} truck{trucks.length !== 1 ? "s" : ""}
              </Text>
            )}
          </Group>
        </Group>

        {/* Assigned trucks */}
        {isLoading ? (
          <Group justify="center" py="sm">
            <Loader size="sm" />
          </Group>
        ) : (
          trucks.map((t) => (
            <Group
              key={t.id}
              justify="space-between"
              align="flex-start"
              wrap="nowrap"
              style={{ border: "1px solid #EEF2F6", borderRadius: 12, padding: "12px 14px" }}
            >
              <Stack gap={4} style={{ minWidth: 0 }}>
                <Group gap={8} wrap="nowrap">
                  <Text fz="14px" fw={700} c="#10202F">
                    {t.plateNumber}
                  </Text>
                  {t.arrivedAt ? (
                    <Badge color="green" variant="light" leftSection={<CheckCircle2 size={12} />}>
                      Arrived
                    </Badge>
                  ) : (
                    <Badge color="orange" variant="light" leftSection={<Clock size={12} />}>
                      Awaiting arrival
                    </Badge>
                  )}
                </Group>
                <Text fz="12.5px" c="#6B7C8E">
                  {t.driverName} · {t.truckType}
                </Text>
                <Group gap={6}>
                  {(t.containers ?? []).map((c) => (
                    <Badge key={c.id} variant="outline" color="gray">
                      {c.containerNumber}
                    </Badge>
                  ))}
                </Group>
              </Stack>
              {!t.arrivedAt && (
                <Group gap={4} wrap="nowrap">
                  <ActionIcon
                    variant="subtle"
                    color="blue"
                    aria-label="Edit truck"
                    onClick={() => startEdit(t)}
                  >
                    <Pencil size={16} />
                  </ActionIcon>
                  <ActionIcon
                    variant="subtle"
                    color="red"
                    aria-label="Remove truck"
                    onClick={() => removeMutation.mutate(t.id)}
                    loading={removeMutation.isPending}
                  >
                    <Trash2 size={16} />
                  </ActionIcon>
                </Group>
              )}
            </Group>
          ))
        )}

        {error && (
          <Alert color="red" variant="light">
            {error}
          </Alert>
        )}

        {/* Add-truck form. Container bookings assign 1–2 containers per truck;
            bulk bookings just register the truck (no container picker). */}
        {isBulk || availableContainers.length > 0 ? (
          <>
            <Divider label={editingId ? "Edit truck" : "Add a truck"} labelPosition="center" />
            <SimpleGrid cols={{ base: 1, sm: 2 }} spacing="sm">
              <TextInput
                label="Truck Plate Number"
                required
                value={plateNumber}
                onChange={(e) => setPlateNumber(e.currentTarget.value.toUpperCase())}
              />
              <TextInput
                label="Driver Name"
                required
                value={driverName}
                onChange={(e) => setDriverName(e.currentTarget.value)}
              />
              <Select
                label="Truck Type"
                required
                data={TRUCK_TYPES}
                value={truckType || null}
                onChange={(value) => setTruckType(value ?? "")}
              />
              {!isBulk && (
                <MultiSelect
                  label="Containers to load"
                  description="20ft: up to 2 per truck · 40ft: 1 per truck"
                  required
                  placeholder="Select container numbers"
                  data={availableContainers}
                  value={containers}
                  onChange={setContainers}
                  maxValues={2}
                  searchable
                  nothingFoundMessage="No unassigned containers"
                />
              )}
              {isBulk && (
                <NumberInput
                  label="Tonnes to load"
                  description={(() => {
                    const total = Number(booking.cargoTotalWeightVgm) || 0;
                    const assigned = trucks
                      .filter((t) => t.id !== editingId)
                      .reduce((s, t) => {
                        const x = t as Freight.ICustomerTruck & {
                          netWeightTons?: number | string | null;
                          plannedTons?: number | string | null;
                        };
                        return s + (Number(x.netWeightTons ?? x.plannedTons) || 0);
                      }, 0);
                    const remaining = Math.max(0, Math.round((total - assigned) * 1000) / 1000);
                    return total > 0
                      ? `${assigned} t of ${total} t already on trucks · ${remaining} t remaining`
                      : "Tonnage this truck hauls";
                  })()}
                  required
                  min={0}
                  value={plannedTons}
                  onChange={(v) => setPlannedTons(v === "" ? "" : Number(v))}
                />
              )}
              {isBulk && (
                <NumberInput
                  label="Items quantity (pcs)"
                  description="Optional piece count on this truck"
                  min={0}
                  value={plannedQty}
                  onChange={(v) => setPlannedQty(v === "" ? "" : Number(v))}
                />
              )}
            </SimpleGrid>
            <Group justify="flex-end">
              {editingId && (
                <Button variant="default" onClick={resetForm} disabled={addMutation.isPending}>
                  Cancel
                </Button>
              )}
              <Button
                leftSection={editingId ? <Pencil size={16} /> : <Plus size={16} />}
                color="edr-green"
                onClick={submitAdd}
                loading={addMutation.isPending}
              >
                {editingId ? "Save changes" : "Add truck"}
              </Button>
            </Group>
          </>
        ) : (
          trucks.length > 0 && (
            <Text fz="12.5px" c="#9AA8B5">
              All containers on this booking have been assigned to a truck.
            </Text>
          )
        )}

        {trucks.length > 0 && (
          <Stack gap="xs">
            <Text fz="13px" fw={600}>Copies</Text>
            <Group gap="xs">
              <Button
                size="compact-xs"
                variant="default"
                onClick={() => setSelectedCopies(FREIGHT_ORDER_COPIES.map((c) => c.index))}
              >
                8 copies
              </Button>
              <Button size="compact-xs" variant="default" onClick={() => setSelectedCopies([])}>
                clear selection
              </Button>
            </Group>
            <SimpleGrid cols={2} spacing={6} verticalSpacing={6}>
              {FREIGHT_ORDER_COPIES.map((c) => (
                <Checkbox
                  key={c.index}
                  size="xs"
                  label={c.label}
                  checked={selectedCopies.includes(c.index)}
                  onChange={(e) =>
                    setSelectedCopies((prev) =>
                      e.currentTarget.checked
                        ? [...prev, c.index].sort((a, b) => a - b)
                        : prev.filter((i) => i !== c.index),
                    )
                  }
                />
              ))}
            </SimpleGrid>
            <Group justify="space-between" align="center">
              <Text fz="11.5px" c="#9AA8B5">
                Port Operations and Gate Security copies are always included.
              </Text>
              <Button
                variant="light"
                leftSection={<Download size={16} />}
                color="edr-green"
                onClick={downloadFreightOrder}
                loading={downloadMutation.isPending}
              >
                Generate Freight Order Copies
              </Button>
            </Group>
          </Stack>
        )}
      </Stack>

      <BulkTruckUploadModal
        opened={bulkModalOpen}
        onClose={() => setBulkModalOpen(false)}
        bookingId={booking.id}
        onSuccess={() => {
          queryClient.invalidateQueries({ queryKey: trucksKey });
          onAssigned();
        }}
      />
    </SectionCard>
  );
}
