import { useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  Alert,
  Button,
  Group,
  Modal,
  NumberInput,
  Select,
  Stack,
  Switch,
  Text,
} from "@mantine/core";
import { AlertCircle, CalendarDays, PackagePlus } from "lucide-react";

import { api } from "@/services/api";
import type { Freight } from "@edr/types";
import { formatQuantity, GREEN, INK } from "./contract-ui";

interface PlaceOrderDialogProps {
  opened: boolean;
  onClose: () => void;
  contract: Freight.IBooking;
  pool: Freight.ContractQuantityLine[];
  onPlaced: () => void;
}

/**
 * Place a drawdown order against an ACTIVE general contract. The customer picks
 * a shipment day (constrained to days with a departure on the contract's route)
 * and a quantity per pool line, validated against the remaining quantity.
 */
export function PlaceOrderDialog({
  opened,
  onClose,
  contract,
  pool,
  onPlaced,
}: PlaceOrderDialogProps) {
  const queryClient = useQueryClient();
  const isContainer = contract.freightType === "CONTAINER";

  const [scheduledDate, setScheduledDate] = useState<string | null>(null);
  const [quantities, setQuantities] = useState<Record<string, number | "">>({});
  const [routeLineId, setRouteLineId] = useState<string | null>(null);
  // Per-order hazardous / reefer counts, entered once when the toggle is on.
  const [hazardousOn, setHazardousOn] = useState(false);
  const [hazardousQty, setHazardousQty] = useState<number | "">("");
  const [reeferOn, setReeferOn] = useState(false);
  const [reeferQty, setReeferQty] = useState<number | "">("");

  // Multi-route contracts expose route lines; single-route contracts return [].
  const { data: routeLines = [] } = useQuery({
    ...api.bookingOrders.routes.queryOptions({
      input: { contractBookingId: contract.id },
    }),
    enabled: opened,
  });
  const isMultiRoute = routeLines.length > 0;
  const selectedRoute = routeLines.find((r) => r.routeLineId === routeLineId);

  // The route the order ships on drives both the available-days query and the
  // remaining-quantity check: the chosen route line for multi-route contracts,
  // else the contract's own origin/destination.
  const originYardId = isMultiRoute
    ? selectedRoute?.originYardId
    : contract.originYard?.id;
  const destinationYardId = isMultiRoute
    ? selectedRoute?.destinationYardId
    : contract.destinationYard?.id;

  const { data: availableDays, isLoading: daysLoading } = useQuery({
    ...api.bookings.getAvailableDays.queryOptions({
      input: { originYardId, destinationYardId },
    }),
    enabled: opened && !!originYardId && !!destinationYardId,
  });

  const dayOptions = useMemo(
    () =>
      (availableDays ?? []).map((d) => ({
        value: d,
        label: new Date(d).toLocaleDateString(undefined, {
          weekday: "short",
          year: "numeric",
          month: "short",
          day: "numeric",
        }),
      })),
    [availableDays],
  );

  const lineKey = (line: Freight.ContractQuantityLine) =>
    line.containerTypeId ?? "__bulk__";

  const createMutation = useMutation({
    ...api.bookingOrders.create.mutationOptions(),
    onSuccess: () => {
      queryClient.invalidateQueries({
        queryKey: api.bookingOrders.listByContract.queryKey({
          contractBookingId: contract.id,
        }),
      });
      queryClient.invalidateQueries({
        queryKey: api.bookingOrders.pool.queryKey({
          contractBookingId: contract.id,
        }),
      });
      queryClient.invalidateQueries({
        queryKey: api.bookingOrders.routes.queryKey({
          contractBookingId: contract.id,
        }),
      });
      queryClient.invalidateQueries({
        queryKey: api.bookings.get.queryKey({ id: contract.id }),
      });
      reset();
      onPlaced();
    },
  });

  function reset() {
    setScheduledDate(null);
    setQuantities({});
    setRouteLineId(null);
    setHazardousOn(false);
    setHazardousQty("");
    setReeferOn(false);
    setReeferQty("");
  }

  // Total quantity across the order; haz/reefer counts cannot exceed it.
  const orderTotalQty = isMultiRoute
    ? typeof quantities["__route__"] === "number"
      ? (quantities["__route__"] as number)
      : 0
    : pool.reduce((sum, l) => {
        const raw = quantities[lineKey(l)];
        return sum + (typeof raw === "number" ? raw : 0);
      }, 0);

  const hazValue = hazardousOn && typeof hazardousQty === "number" ? hazardousQty : 0;
  const reeferValue = reeferOn && typeof reeferQty === "number" ? reeferQty : 0;
  const hazReeferValid =
    (!hazardousOn || (hazValue > 0 && hazValue <= orderTotalQty)) &&
    (!reeferOn || (reeferValue > 0 && reeferValue <= orderTotalQty));

  function handleClose() {
    if (createMutation.isPending) return;
    reset();
    onClose();
  }

  function handleSubmit() {
    if (!scheduledDate) return;

    if (isMultiRoute) {
      if (!selectedRoute) return;
      const raw = quantities["__route__"];
      const qty = typeof raw === "number" ? raw : 0;
      if (qty <= 0) return;
      if (!hazReeferValid) return;
      createMutation.mutate({
        contractBookingId: contract.id,
        routeLineId: selectedRoute.routeLineId,
        scheduledDate: new Date(scheduledDate).toISOString(),
        lines: [
          {
            containerTypeId: isContainer
              ? (selectedRoute.containerTypeId ?? null)
              : null,
            quantity: qty,
            hazardousQuantity: hazValue,
            reeferQuantity: reeferValue,
          },
        ],
      });
      return;
    }

    const lines: Freight.CreateBookingOrderLineDto[] = pool
      .map((line) => {
        const raw = quantities[lineKey(line)];
        const qty = typeof raw === "number" ? raw : 0;
        return {
          containerTypeId: isContainer ? line.containerTypeId : null,
          quantity: qty,
        };
      })
      .filter((l) => l.quantity > 0);

    if (lines.length === 0) return;
    if (!hazReeferValid) return;

    // Haz/reefer are entered once per order; attach the counts to the first line.
    lines[0] = {
      ...lines[0],
      hazardousQuantity: hazValue,
      reeferQuantity: reeferValue,
    };

    createMutation.mutate({
      contractBookingId: contract.id,
      scheduledDate: new Date(scheduledDate).toISOString(),
      lines,
    });
  }

  const orderableLines = pool.filter((l) => l.remainingQuantity > 0);
  const routeQtyRaw = quantities["__route__"];
  const hasQuantity = isMultiRoute
    ? typeof routeQtyRaw === "number" && routeQtyRaw > 0
    : pool.some((l) => {
        const raw = quantities[lineKey(l)];
        return typeof raw === "number" && raw > 0;
      });
  const canSubmit =
    !!scheduledDate &&
    hasQuantity &&
    hazReeferValid &&
    (!isMultiRoute || !!selectedRoute) &&
    !createMutation.isPending;

  const routeOptions = routeLines.map((r) => ({
    value: r.routeLineId,
    label: `${r.originYardName ?? r.originYardId} → ${r.destinationYardName ?? r.destinationYardId} · ${formatQuantity(
      r.remainingQuantity,
      null,
      isContainer,
    )} remaining`,
  }));

  return (
    <Modal
      opened={opened}
      onClose={handleClose}
      title={
        <Group gap={8}>
          <PackagePlus size={18} color={GREEN} />
          <Text fw={700} style={{ color: INK }}>
            Place an order
          </Text>
        </Group>
      }
      radius="lg"
      centered
      size="md"
    >
      <Stack gap="md">
        <Text size="sm" c="dimmed">
          Draw down from contract <strong>{contract.reference}</strong>. Cargo
          and service are inherited — pick {isMultiRoute ? "a route, " : ""}a
          shipment date and quantity.
        </Text>

        {isMultiRoute && (
          <Select
            label="Route"
            placeholder="Select a contracted route"
            data={routeOptions}
            value={routeLineId}
            onChange={(v) => {
              setRouteLineId(v);
              setScheduledDate(null);
              setQuantities({});
            }}
            radius="md"
            comboboxProps={{ withinPortal: true }}
            styles={{ input: { height: 44 } }}
          />
        )}

        <Select
          label="Shipment date"
          placeholder={daysLoading ? "Loading available days…" : "Select a day"}
          data={dayOptions}
          value={scheduledDate}
          onChange={setScheduledDate}
          disabled={daysLoading || (isMultiRoute && !selectedRoute)}
          radius="md"
          leftSection={<CalendarDays size={16} />}
          nothingFoundMessage="No departures on this route"
          searchable
          comboboxProps={{ withinPortal: true }}
          styles={{ input: { height: 44 } }}
        />

        {isMultiRoute ? (
          <Stack gap="sm">
            <Text fz={13} fw={600} style={{ color: INK }}>
              Quantity
            </Text>
            {!selectedRoute ? (
              <Text fz={13} c="dimmed">
                Select a route to draw down from.
              </Text>
            ) : selectedRoute.remainingQuantity <= 0 ? (
              <Alert color="gray" radius="md" icon={<AlertCircle size={16} />}>
                This route is fully drawn down — no quantity remains.
              </Alert>
            ) : (
              <Group justify="space-between" wrap="nowrap" gap="md">
                <div style={{ flex: 1 }}>
                  <Text fz={14} fw={600} style={{ color: INK }}>
                    {selectedRoute.containerTypeName ??
                      (isContainer ? "Containers" : "Tons")}
                  </Text>
                  <Text fz={12} c="dimmed">
                    {formatQuantity(
                      selectedRoute.remainingQuantity,
                      null,
                      isContainer,
                    )}{" "}
                    remaining
                  </Text>
                </div>
                <NumberInput
                  value={quantities["__route__"] ?? ""}
                  onChange={(v) =>
                    setQuantities({ __route__: v === "" ? "" : Number(v) })
                  }
                  min={0}
                  max={selectedRoute.remainingQuantity}
                  step={isContainer ? 1 : 0.5}
                  clampBehavior="strict"
                  radius="md"
                  w={130}
                  placeholder="0"
                />
              </Group>
            )}
          </Stack>
        ) : (
        <Stack gap="sm">
          <Text fz={13} fw={600} style={{ color: INK }}>
            Quantity
          </Text>
          {orderableLines.length === 0 && (
            <Alert color="gray" radius="md" icon={<AlertCircle size={16} />}>
              This contract is fully drawn down — no quantity remains.
            </Alert>
          )}
          {orderableLines.map((line) => {
            const key = lineKey(line);
            const label = isContainer
              ? (line.containerTypeName ?? "Containers")
              : line.unitOfMeasure === "PER_ITEM"
                ? "Items"
                : "Tons";
            return (
              <Group key={key} justify="space-between" wrap="nowrap" gap="md">
                <div style={{ flex: 1 }}>
                  <Text fz={14} fw={600} style={{ color: INK }}>
                    {label}
                  </Text>
                  <Text fz={12} c="dimmed">
                    {formatQuantity(
                      line.remainingQuantity,
                      line.unitOfMeasure,
                      isContainer,
                    )}{" "}
                    remaining
                  </Text>
                </div>
                <NumberInput
                  value={quantities[key] ?? ""}
                  onChange={(v) =>
                    setQuantities((prev) => ({
                      ...prev,
                      [key]: v === "" ? "" : Number(v),
                    }))
                  }
                  min={0}
                  max={line.remainingQuantity}
                  step={isContainer || line.unitOfMeasure === "PER_ITEM" ? 1 : 0.5}
                  clampBehavior="strict"
                  radius="md"
                  w={130}
                  placeholder="0"
                />
              </Group>
            );
          })}
        </Stack>
        )}

        <Stack gap="sm">
          <Text fz={13} fw={600} style={{ color: INK }}>
            Cargo handling
          </Text>
          <Group justify="space-between" wrap="nowrap" gap="md">
            <Switch
              label="Hazardous cargo"
              checked={hazardousOn}
              onChange={(e) => {
                setHazardousOn(e.currentTarget.checked);
                if (!e.currentTarget.checked) setHazardousQty("");
              }}
              color="edr-green"
            />
            {hazardousOn && (
              <NumberInput
                value={hazardousQty}
                onChange={(v) => setHazardousQty(v === "" ? "" : Number(v))}
                min={0}
                max={orderTotalQty || undefined}
                step={isContainer ? 1 : 0.5}
                clampBehavior="strict"
                radius="md"
                w={130}
                placeholder="How many"
              />
            )}
          </Group>
          <Group justify="space-between" wrap="nowrap" gap="md">
            <Switch
              label="Refrigerated (reefer)"
              checked={reeferOn}
              onChange={(e) => {
                setReeferOn(e.currentTarget.checked);
                if (!e.currentTarget.checked) setReeferQty("");
              }}
              color="edr-green"
            />
            {reeferOn && (
              <NumberInput
                value={reeferQty}
                onChange={(v) => setReeferQty(v === "" ? "" : Number(v))}
                min={0}
                max={orderTotalQty || undefined}
                step={isContainer ? 1 : 0.5}
                clampBehavior="strict"
                radius="md"
                w={130}
                placeholder="How many"
              />
            )}
          </Group>
          {(hazardousOn || reeferOn) && (
            <Text fz={12} c="dimmed">
              Hazardous/reefer quantity cannot exceed the order total
              {orderTotalQty > 0 ? ` (${orderTotalQty})` : ""}. These add the
              relevant surcharge to this order's price.
            </Text>
          )}
        </Stack>

        {createMutation.isError && (
          <Alert color="red" radius="md" icon={<AlertCircle size={16} />}>
            {createMutation.error instanceof Error
              ? createMutation.error.message
              : "Failed to place the order. Please try again."}
          </Alert>
        )}

        <Group justify="flex-end" gap="sm" mt="xs">
          <Button
            variant="default"
            radius="md"
            onClick={handleClose}
            disabled={createMutation.isPending}
          >
            Cancel
          </Button>
          <Button
            color="edr-green"
            radius="md"
            leftSection={<PackagePlus size={16} />}
            onClick={handleSubmit}
            disabled={!canSubmit}
            loading={createMutation.isPending}
          >
            Place order
          </Button>
        </Group>
      </Stack>
    </Modal>
  );
}
