import { Fragment, useEffect, useMemo, useState } from 'react';
import {
  Alert,
  Badge,
  Button,
  Checkbox,
  Group,
  Loader,
  Modal,
  NumberInput,
  Select,
  Stack,
  Table,
  Tabs,
  Text,
  Textarea,
  TextInput,
} from '@mantine/core';
import { ChevronDown, ChevronRight, ClipboardCheck, Info, PackageSearch, Train, Truck } from 'lucide-react';

import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';

import { api } from '@/services/api';
import { QUERY_KEYS } from '@/constants/QUERY_KEYS';
import { useToast } from '@/hooks/use-toast';
import { firstMileService } from '@/services/first-mile.service';
import type {
  EligibleBooking,
  ImportTrain,
  ImportTrainItem,
  ImportUnloadedItem,
  ReadyToLoadRow,
  ReceiveInventoryPayload,
  TruckEntrancePayload,
} from '@/types/warehouse';
import { BookingSelect } from './BookingSelect';
import { InspectionReportModal } from './InspectionReportModal';
import { InventoryWorkbench } from './InventoryWorkbench';
import { extractErrorMessage, formatDate, formatNumber } from './options';

interface ReceiveInventoryModalProps {
  opened: boolean;
  onClose: () => void;
  /** When supplied the modal locks to a single booking (legacy single-receive). */
  bookingId?: string;
  bookingLabel?: string;
  onReceived?: () => void;
}

interface Location {
  warehouseId: string;
  yardId: string;
  zoneId: string;
}

interface TruckEntranceFormState {
  ownerName: string;
  consigneeDetails: string;
  edrDigitalBookingId: string;
  tin: string;
  customerPhone: string;
  truckPlateNumber: string;
  trailerPlateNumber: string;
  assignedEquipmentNumber: string;
  customsSealNumber: string;
  declarationNumber: string;
  incoterms: string;
  hsCodes: string;
  itemCode: string;
  itemDescription: string;
  packagingType: string;
  unitCount: number | '';
  grossWeightKg: number | '';
  netWeightKg: number | '';
  volumeDimensions: string;
  conditionAtReceipt: string;
  damagedRejectedQuantity: number | '';
  warehouseCodeLocation: string;
  driverName: string;
  driverPhone: string;
  driverLicenseNumber: string;
  truckType: string;
  entranceTareWeightKg: number | '';
  exitTareWeightKg: number | '';
  driverSignatoryName: string;
  warehouseManagerName: string;
}

interface LockedTruckEntranceFields {
  ownerName?: boolean;
  consigneeDetails?: boolean;
  tin?: boolean;
  edrDigitalBookingId?: boolean;
  customerPhone?: boolean;
  assignedEquipmentNumber?: boolean;
  itemDescription?: boolean;
  packagingType?: boolean;
  unitCount?: boolean;
  grossWeightKg?: boolean;
}

type PackagingFreightType = 'CONTAINER' | 'BULK' | 'MIXED';

const emptyTruckEntrance = (): TruckEntranceFormState => ({
  ownerName: '',
  consigneeDetails: '',
  edrDigitalBookingId: '',
  tin: '',
  customerPhone: '',
  truckPlateNumber: '',
  trailerPlateNumber: '',
  assignedEquipmentNumber: '',
  customsSealNumber: '',
  declarationNumber: '',
  incoterms: '',
  hsCodes: '',
  itemCode: '',
  itemDescription: '',
  packagingType: '',
  unitCount: '',
  grossWeightKg: '',
  netWeightKg: '',
  volumeDimensions: '',
  conditionAtReceipt: '',
  damagedRejectedQuantity: '',
  warehouseCodeLocation: '',
  driverName: '',
  driverPhone: '',
  driverLicenseNumber: '',
  truckType: '',
  entranceTareWeightKg: '',
  exitTareWeightKg: '',
  driverSignatoryName: '',
  warehouseManagerName: '',
});

const toTruckEntrancePayload = (form: TruckEntranceFormState): TruckEntrancePayload => ({
  truckPlateNumber: form.truckPlateNumber.trim(),
  trailerPlateNumber: form.trailerPlateNumber.trim() || undefined,
  customsSealNumber: form.customsSealNumber.trim() || undefined,
  declarationNumber: form.declarationNumber.trim() || undefined,
  incoterms: form.incoterms.trim() || undefined,
  hsCodes: form.hsCodes.trim() || undefined,
  itemCode: form.itemCode.trim() || undefined,
  netWeightKg: form.netWeightKg === '' ? undefined : Number(form.netWeightKg),
  volumeDimensions: form.volumeDimensions.trim() || undefined,
  conditionAtReceipt: form.conditionAtReceipt.trim() || undefined,
  damagedRejectedQuantity: form.damagedRejectedQuantity === '' ? undefined : Number(form.damagedRejectedQuantity),
  warehouseCodeLocation: form.warehouseCodeLocation.trim() || undefined,
  driverName: form.driverName.trim(),
  driverPhone: form.driverPhone.trim(),
  driverLicenseNumber: form.driverLicenseNumber.trim() || undefined,
  truckType: form.truckType.trim() || undefined,
  entranceTareWeightKg: Number(form.entranceTareWeightKg),
  exitTareWeightKg: form.exitTareWeightKg === '' ? undefined : Number(form.exitTareWeightKg),
  driverSignatoryName: form.driverSignatoryName.trim() || undefined,
  warehouseManagerName: form.warehouseManagerName.trim() || undefined,
});

const commonNonEmptyValue = (values: Array<string | null | undefined>) => {
  const unique = [...new Set(values.map((value) => value?.trim()).filter(Boolean))] as string[];
  return unique.length === 1 ? unique[0] : '';
};

const truckEntranceFromBookings = (bookings: EligibleBooking[]): {
  form: TruckEntranceFormState;
  lockedFields: LockedTruckEntranceFields;
  packagingFreightType: PackagingFreightType;
} => {
  const ownerName = commonNonEmptyValue(bookings.map((booking) => booking.customer));
  const tin = commonNonEmptyValue(bookings.map((booking) => booking.customerTin));
  const customerPhone = commonNonEmptyValue(bookings.map((booking) => booking.customerPhone));
  const consigneeDetails = commonNonEmptyValue(bookings.map((booking) => booking.customer));
  const assignedEquipmentNumber = commonNonEmptyValue(bookings.map((booking) => booking.containerNumber));
  const itemDescription = commonNonEmptyValue(bookings.map((booking) => booking.cargoDescription ?? booking.cargo));
  const packagingType = commonNonEmptyValue(bookings.map((booking) => booking.containerPackagingType));
  const edrDigitalBookingId =
    bookings.length === 1
      ? bookings[0]?.reference ?? bookings[0]?.id ?? ''
      : commonNonEmptyValue(bookings.map((booking) => booking.reference));
  const firstMileBooking = bookings.length === 1 ? bookings[0] : null;
  const unitCount =
    bookings.length === 1 && bookings[0]?.containerQuantity != null
      ? Number(bookings[0].containerQuantity)
      : '';
  const grossWeightKg =
    bookings.length === 1 && bookings[0]?.weight != null
      ? Number(bookings[0].weight)
      : '';
  const freightTypes = [...new Set(bookings.map((booking) => booking.freightType).filter(Boolean))];
  const packagingFreightType =
    freightTypes.length === 1 && freightTypes[0] === 'CONTAINER'
      ? 'CONTAINER'
      : freightTypes.length === 1 && freightTypes[0] === 'BULK'
        ? 'BULK'
        : 'MIXED';

  return {
    form: {
      ...emptyTruckEntrance(),
      ownerName,
      consigneeDetails,
      tin,
      customerPhone,
      edrDigitalBookingId,
      assignedEquipmentNumber,
      itemDescription,
      packagingType,
      unitCount,
      grossWeightKg,
      truckPlateNumber: firstMileBooking?.firstMileTruckPlateNumber ?? '',
      trailerPlateNumber: firstMileBooking?.firstMileTrailerPlateNumber ?? '',
      driverName: firstMileBooking?.firstMileDriverName ?? '',
      driverPhone: firstMileBooking?.firstMileDriverPhone ?? '',
      driverLicenseNumber: firstMileBooking?.firstMileDriverLicenseNumber ?? '',
      truckType: firstMileBooking?.firstMileTruckType ?? '',
    },
    lockedFields: {
      ownerName: Boolean(ownerName),
      consigneeDetails: Boolean(consigneeDetails),
      tin: Boolean(tin),
      edrDigitalBookingId: Boolean(edrDigitalBookingId),
      customerPhone: Boolean(customerPhone),
      assignedEquipmentNumber: Boolean(assignedEquipmentNumber),
      itemDescription: Boolean(itemDescription),
      packagingType: Boolean(packagingType),
      unitCount: unitCount !== '',
      grossWeightKg: grossWeightKg !== '',
    },
    packagingFreightType,
  };
};

const BULK_PACKAGING_TYPE_OPTIONS = [
  { value: 'BAG', label: 'Bag' },
  { value: 'SACK', label: 'Sack' },
  { value: 'BALE', label: 'Bale' },
  { value: 'CARTON', label: 'Carton' },
  { value: 'CRATE', label: 'Crate' },
  { value: 'DRUM', label: 'Drum' },
  { value: 'BARREL', label: 'Barrel' },
  { value: 'PALLET', label: 'Pallet' },
  { value: 'LOOSE_BULK', label: 'Loose bulk' },
  { value: 'OTHER', label: 'Other' },
];

const CONTAINER_PACKAGING_TYPE_OPTIONS = [
  { value: 'CONTAINER_20FT', label: '20 ft container' },
  { value: 'CONTAINER_40FT', label: '40 ft container' },
  { value: 'CONTAINER_45FT', label: '45 ft container' },
  { value: 'REEFER_CONTAINER', label: 'Reefer container' },
  { value: 'TANK_CONTAINER', label: 'Tank container' },
  { value: 'FLAT_RACK_CONTAINER', label: 'Flat rack container' },
  { value: 'OPEN_TOP_CONTAINER', label: 'Open top container' },
  { value: 'OTHER_CONTAINER', label: 'Other container' },
];

const packagingOptionsFor = (freightType: PackagingFreightType) =>
  freightType === 'CONTAINER'
    ? CONTAINER_PACKAGING_TYPE_OPTIONS
    : freightType === 'BULK'
      ? BULK_PACKAGING_TYPE_OPTIONS
      : [...CONTAINER_PACKAGING_TYPE_OPTIONS, ...BULK_PACKAGING_TYPE_OPTIONS];

function TruckEntranceFields({
  value,
  onChange,
  lockedFields,
  packagingFreightType = 'MIXED',
}: {
  value: TruckEntranceFormState;
  onChange: (next: TruckEntranceFormState) => void;
  lockedFields?: LockedTruckEntranceFields;
  packagingFreightType?: PackagingFreightType;
}) {
  const packagingOptions = packagingOptionsFor(packagingFreightType);
  const quantityLabel =
    packagingFreightType === 'CONTAINER'
      ? 'Container quantity'
      : packagingFreightType === 'BULK'
        ? 'Unit count'
        : 'Quantity';

  return (
    <Stack gap="sm">
      <Text size="sm" fw={600}>Customer and cargo ownership</Text>
      <Group grow>
        <TextInput
          label="Owner's name"
          value={value.ownerName}
          readOnly={lockedFields?.ownerName}
          onChange={(e) => onChange({ ...value, ownerName: e.currentTarget.value })}
        />
        <TextInput
          label="Consignee details"
          value={value.consigneeDetails}
          readOnly={lockedFields?.consigneeDetails}
          onChange={(e) => onChange({ ...value, consigneeDetails: e.currentTarget.value })}
        />
      </Group>
      <Group grow>
        <TextInput
          label="EDR digital booking ID"
          value={value.edrDigitalBookingId}
          readOnly={lockedFields?.edrDigitalBookingId}
          onChange={(e) => onChange({ ...value, edrDigitalBookingId: e.currentTarget.value })}
        />
        <TextInput
          label="TIN"
          value={value.tin}
          readOnly={lockedFields?.tin}
          onChange={(e) => onChange({ ...value, tin: e.currentTarget.value })}
        />
      </Group>
      <TextInput
        label="Customer phone"
        value={value.customerPhone}
        readOnly={lockedFields?.customerPhone}
        onChange={(e) => onChange({ ...value, customerPhone: e.currentTarget.value })}
      />

      <Text size="sm" fw={600} mt="xs">Transport and equipment tracking</Text>
      <Group grow>
        <TextInput
          label="Truck plate number"
          required
          value={value.truckPlateNumber}
          onChange={(e) => onChange({ ...value, truckPlateNumber: e.currentTarget.value })}
        />
        <TextInput
          label="Trailer plate number"
          value={value.trailerPlateNumber}
          onChange={(e) => onChange({ ...value, trailerPlateNumber: e.currentTarget.value })}
        />
      </Group>
      <Group grow>
        <TextInput
          label="Assigned wagon / container number"
          value={value.assignedEquipmentNumber}
          readOnly={lockedFields?.assignedEquipmentNumber}
          onChange={(e) => onChange({ ...value, assignedEquipmentNumber: e.currentTarget.value })}
        />
        <TextInput
          label="Customs seal number"
          value={value.customsSealNumber}
          onChange={(e) => onChange({ ...value, customsSealNumber: e.currentTarget.value })}
        />
      </Group>
      <Group grow>
        <TextInput
          label="Driver name"
          required
          value={value.driverName}
          onChange={(e) => onChange({ ...value, driverName: e.currentTarget.value })}
        />
        <TextInput
          label="Driver phone"
          required
          value={value.driverPhone}
          onChange={(e) => onChange({ ...value, driverPhone: e.currentTarget.value })}
        />
      </Group>
      <Group grow>
        <TextInput
          label="Driver license number"
          value={value.driverLicenseNumber}
          onChange={(e) => onChange({ ...value, driverLicenseNumber: e.currentTarget.value })}
        />
        <TextInput
          label="Truck type"
          value={value.truckType}
          onChange={(e) => onChange({ ...value, truckType: e.currentTarget.value })}
        />
      </Group>
      <Group grow>
        <NumberInput
          label="Entrance tare weight (kg)"
          required
          min={0}
          value={value.entranceTareWeightKg}
          onChange={(v) => onChange({ ...value, entranceTareWeightKg: v === '' ? '' : Number(v) })}
        />
        <NumberInput
          label="Exit tare weight (kg)"
          min={0}
          value={value.exitTareWeightKg}
          onChange={(v) => onChange({ ...value, exitTareWeightKg: v === '' ? '' : Number(v) })}
        />
      </Group>

      <Text size="sm" fw={600} mt="xs">Customs and compliance</Text>
      <Group grow>
        <TextInput
          label="Declaration / Bill of Entry number"
          value={value.declarationNumber}
          onChange={(e) => onChange({ ...value, declarationNumber: e.currentTarget.value })}
        />
        <TextInput
          label="Incoterms"
          value={value.incoterms}
          onChange={(e) => onChange({ ...value, incoterms: e.currentTarget.value })}
        />
      </Group>
      <TextInput
        label="HS codes"
        value={value.hsCodes}
        onChange={(e) => onChange({ ...value, hsCodes: e.currentTarget.value })}
      />

      <Text size="sm" fw={600} mt="xs">Physical cargo specifications</Text>
      <Group grow>
        <TextInput
          label="Item code"
          value={value.itemCode}
          onChange={(e) => onChange({ ...value, itemCode: e.currentTarget.value })}
        />
        <TextInput
          label="Item description"
          value={value.itemDescription}
          readOnly={lockedFields?.itemDescription}
          onChange={(e) => onChange({ ...value, itemDescription: e.currentTarget.value })}
        />
      </Group>
      <Group grow>
        <Select
          label="Packaging type"
          data={packagingOptions}
          clearable
          searchable
          readOnly={lockedFields?.packagingType}
          value={value.packagingType}
          onChange={(v) => onChange({ ...value, packagingType: v ?? '' })}
        />
        <NumberInput
          label={quantityLabel}
          min={0}
          value={value.unitCount}
          readOnly={lockedFields?.unitCount}
          onChange={(v) => onChange({ ...value, unitCount: v === '' ? '' : Number(v) })}
        />
      </Group>
      <Group grow>
        <NumberInput
          label="Gross weight (kg)"
          min={0}
          value={value.grossWeightKg}
          readOnly={lockedFields?.grossWeightKg}
          onChange={(v) => onChange({ ...value, grossWeightKg: v === '' ? '' : Number(v) })}
        />
        <NumberInput
          label="Net weight (kg)"
          min={0}
          value={value.netWeightKg}
          onChange={(v) => onChange({ ...value, netWeightKg: v === '' ? '' : Number(v) })}
        />
      </Group>
      <TextInput
        label="Volume / dimensions"
        value={value.volumeDimensions}
        onChange={(e) => onChange({ ...value, volumeDimensions: e.currentTarget.value })}
      />

      <Text size="sm" fw={600} mt="xs">Quality and inspection</Text>
      <Group grow>
        <TextInput
          label="Condition at receipt"
          value={value.conditionAtReceipt}
          onChange={(e) => onChange({ ...value, conditionAtReceipt: e.currentTarget.value })}
        />
        <NumberInput
          label="Damaged / rejected quantity"
          min={0}
          value={value.damagedRejectedQuantity}
          onChange={(v) => onChange({ ...value, damagedRejectedQuantity: v === '' ? '' : Number(v) })}
        />
      </Group>
      <TextInput
        label="Warehouse code and location"
        value={value.warehouseCodeLocation}
        onChange={(e) => onChange({ ...value, warehouseCodeLocation: e.currentTarget.value })}
      />
      <Group grow>
        <TextInput
          label="Driver signatory"
          value={value.driverSignatoryName}
          onChange={(e) => onChange({ ...value, driverSignatoryName: e.currentTarget.value })}
        />
        <TextInput
          label="EDR warehouse manager"
          value={value.warehouseManagerName}
          onChange={(e) => onChange({ ...value, warehouseManagerName: e.currentTarget.value })}
        />
      </Group>
    </Stack>
  );
}

/** Cascading Warehouse → Yard → Zone selectors (ACTIVE only). */
function LocationSelects({
  value,
  onChange,
}: {
  value: Location;
  onChange: (next: Location) => void;
}) {
  const warehousesQuery = useQuery(
    api.warehouses.list.queryOptions({ input: { filter: { status: 'ACTIVE' } } }),
  );
  const yardsQuery = useQuery(
    api.warehouses.listYards.queryOptions({
      input: { warehouseId: value.warehouseId ?? '' },
      enabled: Boolean(value.warehouseId),
    }),
  );
  const zonesQuery = useQuery(
    api.warehouses.listZones.queryOptions({
      input: { yardId: value.yardId ?? '' },
      enabled: Boolean(value.yardId),
    }),
  );

  const warehouseOptions = useMemo(
    () => (warehousesQuery.data ?? []).map((w) => ({ value: w.id, label: `${w.name} (${w.code})` })),
    [warehousesQuery.data],
  );
  const yardOptions = useMemo(
    () =>
      (yardsQuery.data ?? [])
        .filter((y) => y.status === 'ACTIVE')
        .map((y) => ({ value: y.id, label: `${y.name} (${y.code})` })),
    [yardsQuery.data],
  );
  const zoneOptions = useMemo(
    () =>
      (zonesQuery.data ?? [])
        .filter((z) => z.status === 'ACTIVE')
        .map((z) => ({ value: z.id, label: `${z.name} (${z.code})` })),
    [zonesQuery.data],
  );

  return (
    <Group grow align="flex-end">
      <Select
        label="Warehouse"
        placeholder={warehousesQuery.isLoading ? 'Loading…' : 'Select warehouse'}
        required
        searchable
        data={warehouseOptions}
        value={value.warehouseId || null}
        onChange={(v) => onChange({ warehouseId: v ?? '', yardId: '', zoneId: '' })}
      />
      <Select
        label="Yard"
        placeholder={!value.warehouseId ? 'Select warehouse first' : 'Select yard'}
        required
        searchable
        disabled={!value.warehouseId}
        data={yardOptions}
        value={value.yardId || null}
        onChange={(v) => onChange({ ...value, yardId: v ?? '', zoneId: '' })}
      />
      <Select
        label="Zone"
        placeholder={!value.yardId ? 'Select yard first' : 'Select zone'}
        required
        searchable
        disabled={!value.yardId}
        data={zoneOptions}
        value={value.zoneId || null}
        onChange={(v) => onChange({ ...value, zoneId: v ?? '' })}
      />
    </Group>
  );
}

/** One tab: eligible PAID bookings for a direction, with bulk receive (+ export load). */
function EligibleTab({
  direction,
  location,
  enabled,
  onChanged,
}: {
  direction: 'IMPORT' | 'EXPORT';
  location: Location;
  enabled: boolean;
  onChanged?: () => void;
}) {
  const { toast } = useToast();
  const qc = useQueryClient();
  const { data: allRows = [], isLoading } = useQuery(
    api.warehouses.eligibleBookings.queryOptions({ enabled }),
  );
  const rows = useMemo(() => allRows.filter((r) => r.direction === direction), [allRows, direction]);
  const bulkReceive = useMutation(api.warehouses.bulkReceive.mutationOptions());
  const loadPassed = useMutation(api.warehouses.loadPassedExport.mutationOptions());
  const requestFirstMile = useMutation({
    mutationFn: (reference: string) => firstMileService.accept(reference),
    onSuccess: () => {
      void qc.invalidateQueries({ queryKey: ['warehouse-inventory'] });
      void qc.invalidateQueries({ queryKey: QUERY_KEYS.FIRST_MILE.ROOT });
      toast({ title: 'First mile requested', description: 'Booking was added to the existing First Mile workflow.' });
    },
    onError: (error) => {
      toast({ variant: 'destructive', title: 'First mile request failed', description: extractErrorMessage(error) });
    },
  });
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [statusTab, setStatusTab] = useState('ALL');
  const [truckOpen, setTruckOpen] = useState(false);
  const [pendingReceiveIds, setPendingReceiveIds] = useState<string[]>([]);
  const [truckForm, setTruckForm] = useState<TruckEntranceFormState>(emptyTruckEntrance());
  const [lockedTruckFields, setLockedTruckFields] = useState<LockedTruckEntranceFields>({});
  const [packagingFreightType, setPackagingFreightType] = useState<PackagingFreightType>('MIXED');

  const locationReady = Boolean(location.warehouseId && location.yardId && location.zoneId);
  const canReceiveBooking = (row: EligibleBooking) =>
    !(direction === 'EXPORT' && row.hasFirstMile && row.firstMileStatus !== 'RECEIVED_TO_PORT');
  const statusOptions = useMemo(() => {
    const base = [{ value: 'ALL', label: 'All bookings' }];
    if (direction === 'EXPORT') {
      return [
        ...base,
        { value: 'DIRECT', label: 'Direct truck' },
        { value: 'FIRST_MILE', label: 'First mile' },
        { value: 'FIRST_MILE_READY', label: 'First mile arrived' },
        { value: 'AWAITING_FIRST_MILE', label: 'Awaiting first mile' },
      ];
    }
    return [
      ...base,
      { value: 'READY_TO_RECEIVE', label: 'Ready to receive' },
      { value: 'PAID', label: 'Paid' },
    ];
  }, [direction]);
  const statusFilteredRows = useMemo(
    () =>
      rows.filter((row) => {
        switch (statusTab) {
          case 'DIRECT':
            return !row.hasFirstMile;
          case 'FIRST_MILE':
            return row.hasFirstMile;
          case 'FIRST_MILE_READY':
            return row.hasFirstMile && row.firstMileStatus === 'RECEIVED_TO_PORT';
          case 'AWAITING_FIRST_MILE':
            return row.hasFirstMile && row.firstMileStatus !== 'RECEIVED_TO_PORT';
          case 'READY_TO_RECEIVE':
            return canReceiveBooking(row);
          case 'PAID':
            return row.paymentStatus === 'PAID';
          default:
            return true;
        }
      }),
    [rows, statusTab],
  );
  const statusCounts = useMemo(
    () =>
      Object.fromEntries(
        statusOptions.map((option) => [
          option.value,
          rows.filter((row) => {
            switch (option.value) {
              case 'DIRECT':
                return !row.hasFirstMile;
              case 'FIRST_MILE':
                return row.hasFirstMile;
              case 'FIRST_MILE_READY':
                return row.hasFirstMile && row.firstMileStatus === 'RECEIVED_TO_PORT';
              case 'AWAITING_FIRST_MILE':
                return row.hasFirstMile && row.firstMileStatus !== 'RECEIVED_TO_PORT';
              case 'READY_TO_RECEIVE':
                return canReceiveBooking(row);
              case 'PAID':
                return row.paymentStatus === 'PAID';
              default:
                return true;
            }
          }).length,
        ]),
      ),
    [rows, statusOptions],
  );
  const selectableRows = statusFilteredRows.filter(canReceiveBooking);
  const allSelected = selectableRows.length > 0 && selected.size === selectableRows.length;
  const someSelected = selected.size > 0 && !allSelected;
  const pendingReceiveRows = useMemo(
    () =>
      pendingReceiveIds
        .map((id) => rows.find((item) => item.id === id))
        .filter(Boolean) as EligibleBooking[],
    [pendingReceiveIds, rows],
  );
  const pendingHasFirstMile = pendingReceiveRows.some((row) => row.hasFirstMile);

  const toggleAll = () =>
    setSelected(allSelected ? new Set() : new Set(selectableRows.map((r) => r.id)));
  const toggleOne = (id: string) =>
    setSelected((prev) => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });

  const receiveBookings = async (bookingIds: string[], truckEntrance?: TruckEntrancePayload) => {
    try {
      const r = await bulkReceive.mutateAsync({
        direction,
        ...location,
        bookingIds,
        ...(truckEntrance ? { truckEntrance } : {}),
      });
      toast({
        title: `${r.receivedCount} received at ${direction === 'EXPORT' ? 'facility' : 'warehouse'}`,
        description: r.results.find((item) => item.grnNumber)?.grnNumber ?? (r.skippedCount ? `${r.skippedCount} skipped` : undefined),
      });
      setSelected(new Set());
      setTruckOpen(false);
      setPendingReceiveIds([]);
      setLockedTruckFields({});
      setPackagingFreightType('MIXED');
      onChanged?.();
    } catch (error) {
      toast({ variant: 'destructive', title: 'Receive failed', description: extractErrorMessage(error) });
    }
  };

  const openTruckReceive = (bookingIds: string[]) => {
    if (!locationReady) {
      toast({ variant: 'destructive', title: 'Select warehouse, yard and zone first' });
      return;
    }
    if (bookingIds.length === 0) {
      toast({ variant: 'destructive', title: 'Select at least one booking' });
      return;
    }
    const allowedIds = new Set(selectableRows.map((row) => row.id));
    const filteredIds = bookingIds.filter((id) => allowedIds.has(id));
    if (filteredIds.length === 0) {
      toast({ variant: 'destructive', title: 'No selected booking is ready to receive' });
      return;
    }
    const selectedRows = filteredIds
      .map((id) => rows.find((item) => item.id === id))
      .filter(Boolean) as EligibleBooking[];
    if (direction === 'IMPORT') {
      void receiveBookings(filteredIds);
      return;
    }
    const { form, lockedFields, packagingFreightType: nextPackagingFreightType } = truckEntranceFromBookings(selectedRows);
    setPendingReceiveIds(filteredIds);
    setTruckForm(form);
    setLockedTruckFields(lockedFields);
    setPackagingFreightType(nextPackagingFreightType);
    setTruckOpen(true);
  };

  const receive = async () => {
    if (!truckForm.truckPlateNumber.trim() || !truckForm.driverName.trim() || !truckForm.driverPhone.trim() || truckForm.entranceTareWeightKg === '') {
      toast({ variant: 'destructive', title: 'Truck, driver and entrance tare weight are required' });
      return;
    }
    await receiveBookings(pendingReceiveIds, toTruckEntrancePayload(truckForm));
  };

  const loadPassedExport = async () => {
    try {
      const r = await loadPassed.mutateAsync(undefined);
      toast({
        title: `${r.loadedCount} loaded`,
        description: r.skippedCount ? `${r.skippedCount} skipped — inspection not passed` : undefined,
      });
      onChanged?.();
    } catch (error) {
      toast({ variant: 'destructive', title: 'Load failed', description: extractErrorMessage(error) });
    }
  };

  return (
    <Stack gap="sm" mt="sm">
      <Tabs value={statusTab} onChange={(v) => setStatusTab(v ?? 'ALL')}>
        <Tabs.List>
          {statusOptions.map((option) => (
            <Tabs.Tab key={option.value} value={option.value}>
              {option.label} ({statusCounts[option.value] ?? 0})
            </Tabs.Tab>
          ))}
        </Tabs.List>
      </Tabs>

      <Group justify="space-between">
        <Text size="sm" c="dimmed">
          Selected: <b>{selected.size}</b> / {statusFilteredRows.length} eligible
        </Text>
        <Group gap="xs">
          {direction === 'EXPORT' && (
            <Button
              size="compact-sm"
              variant="light"
              color="teal"
              leftSection={<Truck size={14} />}
              loading={loadPassed.isPending}
              onClick={loadPassedExport}
            >
              Load Passed Export Items
            </Button>
          )}
          <Button
            size="compact-sm"
            variant="default"
            disabled={!locationReady || selectableRows.length === 0}
            loading={bulkReceive.isPending}
            onClick={() => openTruckReceive(selectableRows.map((r) => r.id))}
          >
            Receive All Eligible
          </Button>
          <Button
            size="compact-sm"
            disabled={!locationReady || selected.size === 0}
            loading={bulkReceive.isPending}
            onClick={() => openTruckReceive([...selected])}
          >
            Receive Selected
          </Button>
        </Group>
      </Group>

      {!locationReady && (
        <Alert icon={<Info size={16} />} color="orange" variant="light">
          <Text size="sm">Select a warehouse, yard and zone above before receiving.</Text>
        </Alert>
      )}

      {isLoading ? (
        <Group justify="center" py="lg">
          <Loader size="sm" />
        </Group>
      ) : statusFilteredRows.length === 0 ? (
        <Text c="dimmed" ta="center" py="lg" size="sm">
          No eligible PAID {direction.toLowerCase()} bookings to receive.
        </Text>
      ) : (
        <Table.ScrollContainer minWidth={1700}>
          <Table highlightOnHover verticalSpacing="xs" striped>
            <Table.Thead>
              <Table.Tr>
                <Table.Th w={40}>
                  <Checkbox
                    aria-label="Select all"
                    checked={allSelected}
                    indeterminate={someSelected}
                    onChange={toggleAll}
                  />
                </Table.Th>
                <Table.Th>Booking Ref</Table.Th>
                <Table.Th>Booking ID</Table.Th>
                <Table.Th>Customer ID</Table.Th>
                <Table.Th>Customer Name</Table.Th>
                <Table.Th>Origin</Table.Th>
                <Table.Th>Destination</Table.Th>
                <Table.Th>Route</Table.Th>
                <Table.Th>Container #</Table.Th>
                <Table.Th>Cargo Type</Table.Th>
                <Table.Th>Weight</Table.Th>
                <Table.Th>Payment</Table.Th>
                <Table.Th>Current Status</Table.Th>
                <Table.Th>Inspection</Table.Th>
                {direction === 'EXPORT' && <Table.Th>First Mile</Table.Th>}
                <Table.Th ta="right">Actions</Table.Th>
              </Table.Tr>
            </Table.Thead>
            <Table.Tbody>
              {statusFilteredRows.map((r) => {
                const canReceive = canReceiveBooking(r);
                return (
                <Table.Tr key={r.id}>
                  <Table.Td>
                    <Checkbox
                      aria-label={`Select ${r.reference}`}
                      checked={selected.has(r.id)}
                      disabled={!canReceive}
                      onChange={() => toggleOne(r.id)}
                    />
                  </Table.Td>
                  <Table.Td>
                    <Text size="sm" fw={600}>
                      {r.reference}
                    </Text>
                  </Table.Td>
                  <Table.Td>
                    <Text size="xs" c="dimmed">{r.id.slice(0, 8)}…</Text>
                  </Table.Td>
                  <Table.Td>
                    <Text size="xs" c="dimmed">{r.customerId ? `${r.customerId.slice(0, 8)}…` : '—'}</Text>
                  </Table.Td>
                  <Table.Td>{r.customer ?? '—'}</Table.Td>
                  <Table.Td>{r.origin ?? '—'}</Table.Td>
                  <Table.Td>{r.destination ?? '—'}</Table.Td>
                  <Table.Td>
                    {r.origin || r.destination ? `${r.origin ?? '?'} → ${r.destination ?? '?'}` : '—'}
                  </Table.Td>
                  <Table.Td>—</Table.Td>
                  <Table.Td>{r.cargo ?? '—'}</Table.Td>
                  <Table.Td>{formatNumber(Number(r.weight))}</Table.Td>
                  <Table.Td>
                    <Badge color="green" variant="light" size="sm">
                      {r.paymentStatus}
                    </Badge>
                  </Table.Td>
                  <Table.Td>
                    <Badge color="gray" variant="light" size="sm">
                      {r.status ?? '—'}
                    </Badge>
                  </Table.Td>
                  <Table.Td>—</Table.Td>
                  {direction === 'EXPORT' && (
                    <Table.Td>
                      {r.hasFirstMile ? (
                        <Stack gap={2}>
                          <Badge
                            color={r.firstMileStatus === 'RECEIVED_TO_PORT' ? 'green' : r.firstMileRequestId ? 'blue' : 'orange'}
                            variant="light"
                            size="sm"
                          >
                            {r.firstMileStatus ?? 'Request needed'}
                          </Badge>
                          <Text size="xs" c="dimmed">
                            {[r.firstMileTruckPlateNumber, r.firstMileTrailerPlateNumber].filter(Boolean).join(' / ') || 'Truck not assigned'}
                          </Text>
                        </Stack>
                      ) : (
                        <Badge color="gray" variant="light" size="sm">Direct arrival</Badge>
                      )}
                    </Table.Td>
                  )}
                  <Table.Td ta="right">
                    {direction === 'EXPORT' && r.hasFirstMile && !r.firstMileRequestId ? (
                      <Button
                        size="compact-xs"
                        variant="light"
                        color="orange"
                        loading={requestFirstMile.isPending}
                        onClick={() => requestFirstMile.mutate(r.reference)}
                      >
                        Request First Mile
                      </Button>
                    ) : (
                      <Button
                        size="compact-xs"
                        variant="light"
                        disabled={!locationReady || !canReceive}
                        loading={bulkReceive.isPending}
                        onClick={() => openTruckReceive([r.id])}
                      >
                        {canReceive ? 'Receive' : 'Await First Mile'}
                      </Button>
                    )}
                  </Table.Td>
                </Table.Tr>
                );
              })}
            </Table.Tbody>
          </Table>
        </Table.ScrollContainer>
      )}

      <Modal
        opened={truckOpen}
        onClose={() => setTruckOpen(false)}
        title="Export Truck Arrival / First Mile Receive Form"
        centered
        size="lg"
      >
        <Stack gap="md">
          <Alert icon={<Truck size={16} />} color={pendingHasFirstMile ? 'green' : 'blue'} variant="light">
            <Text size="sm">
              {pendingHasFirstMile
                ? 'Assigned first-mile truck and driver details are prefilled. Confirm or update the actual arrival details before GRN.'
                : 'Register the customer or third-party truck and driver before export receiving and GRN.'}
            </Text>
          </Alert>
          <TruckEntranceFields
            value={truckForm}
            onChange={setTruckForm}
            lockedFields={lockedTruckFields}
            packagingFreightType={packagingFreightType}
          />
          <Group justify="flex-end">
            <Button variant="default" onClick={() => setTruckOpen(false)} disabled={bulkReceive.isPending}>
              Cancel
            </Button>
            <Button leftSection={<Truck size={16} />} loading={bulkReceive.isPending} onClick={receive}>
              Register Arrival & Generate GRN
            </Button>
          </Group>
        </Stack>
      </Modal>
    </Stack>
  );
}

/** Export received items awaiting inspection before loading. */
function ExportReceivedTab({ enabled, onChanged }: { enabled: boolean; onChanged?: () => void }) {
  const { toast } = useToast();
  const { data: rows = [], isLoading } = useQuery(
    api.warehouses.receivedExport.queryOptions({ enabled }),
  );
  const inspectMutation = useMutation(
    api.warehouses.bulkMarkInspected.mutationOptions(),
  );
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [inspectId, setInspectId] = useState<string | null>(null);

  const pendingRows = rows.filter((r) => r.inspectionStatus !== 'PASSED');
  const allSelected = pendingRows.length > 0 && selected.size === pendingRows.length;
  const someSelected = selected.size > 0 && !allSelected;
  const toggleAll = () =>
    setSelected(allSelected ? new Set() : new Set(pendingRows.map((r) => r.id)));
  const toggleOne = (id: string) =>
    setSelected((prev) => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });

  const markInspected = async () => {
    if (selected.size === 0) {
      toast({ variant: 'destructive', title: 'Select at least one item' });
      return;
    }
    try {
      const r = await inspectMutation.mutateAsync({ inventoryIds: [...selected] });
      toast({
        title: `${r.inspectedCount} marked inspected`,
        description: r.skippedCount ? `${r.skippedCount} skipped` : undefined,
      });
      setSelected(new Set());
      onChanged?.();
    } catch (error) {
      toast({ variant: 'destructive', title: 'Mark inspected failed', description: extractErrorMessage(error) });
    }
  };

  return (
    <Stack gap="sm" mt="sm">
      <Group justify="space-between">
        <Text size="sm" c="dimmed">
          Selected: <b>{selected.size}</b> / {pendingRows.length} received
        </Text>
        <Button
          size="compact-sm"
          color="indigo"
          leftSection={<ClipboardCheck size={14} />}
          disabled={selected.size === 0}
          loading={inspectMutation.isPending}
          onClick={markInspected}
        >
          Mark Selected as Inspected
        </Button>
      </Group>

      {isLoading ? (
        <Group justify="center" py="lg">
          <Loader size="sm" />
        </Group>
      ) : rows.length === 0 ? (
        <Text c="dimmed" ta="center" py="lg" size="sm">
          No received export items awaiting inspection.
        </Text>
      ) : (
        <Table.ScrollContainer minWidth={1700}>
          <Table highlightOnHover verticalSpacing="xs" striped>
            <Table.Thead>
              <Table.Tr>
                <Table.Th w={40}>
                  <Checkbox
                    aria-label="Select all"
                    checked={allSelected}
                    indeterminate={someSelected}
                    onChange={toggleAll}
                  />
                </Table.Th>
                <Table.Th>Booking Ref</Table.Th>
                <Table.Th>Booking ID</Table.Th>
                <Table.Th>Customer ID</Table.Th>
                <Table.Th>Customer Name</Table.Th>
                <Table.Th>Container #</Table.Th>
                <Table.Th>Cargo Type</Table.Th>
                <Table.Th>Weight</Table.Th>
                <Table.Th>Route</Table.Th>
                <Table.Th>Inspection</Table.Th>
                <Table.Th>Status</Table.Th>
                <Table.Th ta="right">Actions</Table.Th>
              </Table.Tr>
            </Table.Thead>
            <Table.Tbody>
              {rows.map((r: ReadyToLoadRow) => {
                const selectable = r.inspectionStatus !== 'PASSED';
                return (
                  <Table.Tr key={r.id}>
                    <Table.Td>
                      <Checkbox
                        aria-label={`Select ${r.bookingReference ?? r.id}`}
                        checked={selected.has(r.id)}
                        disabled={!selectable}
                        onChange={() => toggleOne(r.id)}
                      />
                    </Table.Td>
                    <Table.Td>
                      <Text size="sm" fw={600}>{r.bookingReference ?? '—'}</Text>
                    </Table.Td>
                    <Table.Td>
                      <Text size="xs" c="dimmed">{r.bookingId ? `${r.bookingId.slice(0, 8)}…` : '—'}</Text>
                    </Table.Td>
                    <Table.Td>
                      <Text size="xs" c="dimmed">{r.customerId ? `${r.customerId.slice(0, 8)}…` : '—'}</Text>
                    </Table.Td>
                    <Table.Td>{r.customerName ?? '—'}</Table.Td>
                    <Table.Td>{r.containerNumber ?? '—'}</Table.Td>
                    <Table.Td>{r.cargoType ?? '—'}</Table.Td>
                    <Table.Td>{formatNumber(Number(r.weight))}</Table.Td>
                    <Table.Td>
                      {r.origin || r.destination ? `${r.origin ?? '?'} → ${r.destination ?? '?'}` : '—'}
                    </Table.Td>
                    <Table.Td>
                      <Badge color={r.inspectionStatus === 'PASSED' ? 'green' : 'orange'} variant="light" size="sm">
                        {r.inspectionStatus ?? 'PENDING'}
                      </Badge>
                    </Table.Td>
                    <Table.Td>
                      <Badge color="blue" variant="light" size="sm">
                        {r.status}
                      </Badge>
                    </Table.Td>
                    <Table.Td ta="right">
                      <Button size="compact-xs" variant="light" color="orange" onClick={() => setInspectId(r.id)}>
                        Inspect / Report
                      </Button>
                    </Table.Td>
                  </Table.Tr>
                );
              })}
            </Table.Tbody>
          </Table>
        </Table.ScrollContainer>
      )}

      <InspectionReportModal
        inventoryId={inspectId}
        opened={Boolean(inspectId)}
        onClose={() => setInspectId(null)}
      />
    </Stack>
  );
}

/** Export items that passed inspection and are queued to be loaded onto a train. */
function ReadyToLoadTab({ enabled, onChanged }: { enabled: boolean; onChanged?: () => void }) {
  const { toast } = useToast();
  const { data: rows = [], isLoading } = useQuery(
    api.warehouses.readyToLoadExport.queryOptions({ enabled }),
  );
  const loadPassed = useMutation(api.warehouses.loadPassedExport.mutationOptions());
  const [selected, setSelected] = useState<Set<string>>(new Set());

  const allSelected = rows.length > 0 && selected.size === rows.length;
  const someSelected = selected.size > 0 && !allSelected;
  const toggleAll = () => setSelected(allSelected ? new Set() : new Set(rows.map((r) => r.id)));
  const toggleOne = (id: string) =>
    setSelected((prev) => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });

  const autoLoad = async () => {
    try {
      const r = await loadPassed.mutateAsync(undefined);
      toast({
        title: `${r.loadedCount} items loaded`,
        description: r.skippedCount ? `${r.skippedCount} skipped` : undefined,
      });
      setSelected(new Set());
      onChanged?.();
    } catch (error) {
      toast({ variant: 'destructive', title: 'Load failed', description: extractErrorMessage(error) });
    }
  };

  return (
    <Stack gap="sm" mt="sm">
      <Group justify="space-between">
        <Text size="sm" c="dimmed">
          <b>{rows.length}</b> item{rows.length !== 1 ? 's' : ''} ready to load
        </Text>
        <Button
          size="compact-sm"
          variant="filled"
          color="teal"
          leftSection={<Truck size={14} />}
          loading={loadPassed.isPending}
          disabled={rows.length === 0}
          onClick={autoLoad}
        >
          Auto Load Ready Items
        </Button>
      </Group>

      {isLoading ? (
        <Group justify="center" py="lg">
          <Loader size="sm" />
        </Group>
      ) : rows.length === 0 ? (
        <Text c="dimmed" ta="center" py="lg" size="sm">
          No EXPORT items with inspection PASSED waiting to be loaded.
        </Text>
      ) : (
        <Table.ScrollContainer minWidth={1600}>
          <Table highlightOnHover verticalSpacing="xs" striped>
            <Table.Thead>
              <Table.Tr>
                <Table.Th w={40}>
                  <Checkbox
                    aria-label="Select all"
                    checked={allSelected}
                    indeterminate={someSelected}
                    onChange={toggleAll}
                  />
                </Table.Th>
                <Table.Th>Booking Ref</Table.Th>
                <Table.Th>Booking ID</Table.Th>
                <Table.Th>Customer ID</Table.Th>
                <Table.Th>Customer Name</Table.Th>
                <Table.Th>Container #</Table.Th>
                <Table.Th>Cargo Type</Table.Th>
                <Table.Th>Weight</Table.Th>
                <Table.Th>Route</Table.Th>
                <Table.Th>Inspection</Table.Th>
                <Table.Th>Status</Table.Th>
              </Table.Tr>
            </Table.Thead>
            <Table.Tbody>
              {rows.map((r: ReadyToLoadRow) => (
                <Table.Tr key={r.id}>
                  <Table.Td>
                    <Checkbox
                      aria-label={`Select ${r.bookingReference ?? r.id}`}
                      checked={selected.has(r.id)}
                      onChange={() => toggleOne(r.id)}
                    />
                  </Table.Td>
                  <Table.Td>
                    <Text size="sm" fw={600}>{r.bookingReference ?? '—'}</Text>
                  </Table.Td>
                  <Table.Td>
                    <Text size="xs" c="dimmed">{r.bookingId ? `${r.bookingId.slice(0, 8)}…` : '—'}</Text>
                  </Table.Td>
                  <Table.Td>
                    <Text size="xs" c="dimmed">{r.customerId ? `${r.customerId.slice(0, 8)}…` : '—'}</Text>
                  </Table.Td>
                  <Table.Td>{r.customerName ?? '—'}</Table.Td>
                  <Table.Td>{r.containerNumber ?? '—'}</Table.Td>
                  <Table.Td>{r.cargoType ?? '—'}</Table.Td>
                  <Table.Td>{formatNumber(Number(r.weight))}</Table.Td>
                  <Table.Td>
                    {r.origin || r.destination ? `${r.origin ?? '?'} → ${r.destination ?? '?'}` : '—'}
                  </Table.Td>
                  <Table.Td>
                    <Badge color="green" variant="light" size="sm">
                      {r.inspectionStatus ?? '—'}
                    </Badge>
                  </Table.Td>
                  <Table.Td>
                    <Badge color="teal" variant="light" size="sm">
                      {r.status}
                    </Badge>
                  </Table.Td>
                </Table.Tr>
              ))}
            </Table.Tbody>
          </Table>
        </Table.ScrollContainer>
      )}
    </Stack>
  );
}

/**
 * Export items that are LOADED onto a wagon. Serves both the "Loaded" tab (read-only)
 * and the "Dispatch Queue" tab (dispatchable=true → selection + Dispatch actions).
 */
function LoadedExportTab({
  enabled,
  dispatchable,
  onChanged,
}: {
  enabled: boolean;
  dispatchable: boolean;
  onChanged?: () => void;
}) {
  const { toast } = useToast();
  const { data: rows = [], isLoading } = useQuery(
    api.warehouses.loadedExport.queryOptions({ enabled }),
  );
  const bulkDispatch = useMutation(
    api.warehouses.bulkDispatchExport.mutationOptions(),
  );
  const [selected, setSelected] = useState<Set<string>>(new Set());

  const allSelected = rows.length > 0 && selected.size === rows.length;
  const someSelected = selected.size > 0 && !allSelected;
  const toggleAll = () => setSelected(allSelected ? new Set() : new Set(rows.map((r) => r.id)));
  const toggleOne = (id: string) =>
    setSelected((prev) => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });

  const dispatch = async (inventoryIds: string[]) => {
    if (inventoryIds.length === 0) {
      toast({ variant: 'destructive', title: 'Select at least one item' });
      return;
    }
    try {
      const r = await bulkDispatch.mutateAsync(inventoryIds);
      toast({
        title: `${r.dispatchedCount} dispatched`,
        description: r.skippedCount ? `${r.skippedCount} skipped` : undefined,
      });
      setSelected(new Set());
      onChanged?.();
    } catch (error) {
      toast({ variant: 'destructive', title: 'Dispatch failed', description: extractErrorMessage(error) });
    }
  };

  return (
    <Stack gap="sm" mt="sm">
      <Group justify="space-between">
        <Text size="sm" c="dimmed">
          {dispatchable ? (
            <>
              Selected: <b>{selected.size}</b> / {rows.length} loaded
            </>
          ) : (
            <>
              <b>{rows.length}</b> item{rows.length !== 1 ? 's' : ''} loaded
            </>
          )}
        </Text>
        {dispatchable && (
          <Group gap="xs">
            <Button
              size="compact-sm"
              variant="default"
              disabled={rows.length === 0}
              loading={bulkDispatch.isPending}
              onClick={() => dispatch(rows.map((r) => r.id))}
            >
              Dispatch All
            </Button>
            <Button
              size="compact-sm"
              color="green"
              leftSection={<Truck size={14} />}
              disabled={selected.size === 0}
              loading={bulkDispatch.isPending}
              onClick={() => dispatch([...selected])}
            >
              Dispatch Selected
            </Button>
          </Group>
        )}
      </Group>

      {isLoading ? (
        <Group justify="center" py="lg">
          <Loader size="sm" />
        </Group>
      ) : rows.length === 0 ? (
        <Text c="dimmed" ta="center" py="lg" size="sm">
          No LOADED export items {dispatchable ? 'waiting to dispatch' : 'yet'}.
        </Text>
      ) : (
        <Table.ScrollContainer minWidth={1600}>
          <Table highlightOnHover verticalSpacing="xs" striped>
            <Table.Thead>
              <Table.Tr>
                {dispatchable && (
                  <Table.Th w={40}>
                    <Checkbox
                      aria-label="Select all"
                      checked={allSelected}
                      indeterminate={someSelected}
                      onChange={toggleAll}
                    />
                  </Table.Th>
                )}
                <Table.Th>Booking Ref</Table.Th>
                <Table.Th>Booking ID</Table.Th>
                <Table.Th>Customer ID</Table.Th>
                <Table.Th>Customer Name</Table.Th>
                <Table.Th>Container #</Table.Th>
                <Table.Th>Cargo Type</Table.Th>
                <Table.Th>Weight</Table.Th>
                <Table.Th>Route</Table.Th>
                <Table.Th>Status</Table.Th>
                {dispatchable && <Table.Th ta="right">Actions</Table.Th>}
              </Table.Tr>
            </Table.Thead>
            <Table.Tbody>
              {rows.map((r: ReadyToLoadRow) => (
                <Table.Tr key={r.id}>
                  {dispatchable && (
                    <Table.Td>
                      <Checkbox
                        aria-label={`Select ${r.bookingReference ?? r.id}`}
                        checked={selected.has(r.id)}
                        onChange={() => toggleOne(r.id)}
                      />
                    </Table.Td>
                  )}
                  <Table.Td>
                    <Text size="sm" fw={600}>{r.bookingReference ?? '—'}</Text>
                  </Table.Td>
                  <Table.Td>
                    <Text size="xs" c="dimmed">{r.bookingId ? `${r.bookingId.slice(0, 8)}…` : '—'}</Text>
                  </Table.Td>
                  <Table.Td>
                    <Text size="xs" c="dimmed">{r.customerId ? `${r.customerId.slice(0, 8)}…` : '—'}</Text>
                  </Table.Td>
                  <Table.Td>{r.customerName ?? '—'}</Table.Td>
                  <Table.Td>{r.containerNumber ?? '—'}</Table.Td>
                  <Table.Td>{r.cargoType ?? '—'}</Table.Td>
                  <Table.Td>{formatNumber(Number(r.weight))}</Table.Td>
                  <Table.Td>
                    {r.origin || r.destination ? `${r.origin ?? '?'} → ${r.destination ?? '?'}` : '—'}
                  </Table.Td>
                  <Table.Td>
                    <Badge color="blue" variant="light" size="sm">
                      {r.status}
                    </Badge>
                  </Table.Td>
                  {dispatchable && (
                    <Table.Td ta="right">
                      <Button
                        size="compact-xs"
                        variant="light"
                        color="green"
                        loading={bulkDispatch.isPending}
                        onClick={() => dispatch([r.id])}
                      >
                        Dispatch
                      </Button>
                    </Table.Td>
                  )}
                </Table.Tr>
              ))}
            </Table.Tbody>
          </Table>
        </Table.ScrollContainer>
      )}
    </Stack>
  );
}

/** Assigned bookings/items for an arrived import train (read-only detail view). */
function ImportTrainDetailTable({ scheduleId }: { scheduleId: string }) {
  const { data: items = [], isLoading } = useQuery(
    api.warehouses.importTrainItems.queryOptions({
      input: { scheduleId },
      enabled: Boolean(scheduleId),
    }),
  );

  if (isLoading) {
    return (
      <Group justify="center" py="md">
        <Loader size="sm" />
      </Group>
    );
  }
  if (items.length === 0) {
    return (
      <Text c="dimmed" ta="center" py="md" size="sm">
        No assigned bookings on this train.
      </Text>
    );
  }

  return (
    <Table withTableBorder verticalSpacing="xs" fz="xs">
      <Table.Thead>
        <Table.Tr>
          <Table.Th>Booking ID</Table.Th>
          <Table.Th>Booking Ref</Table.Th>
          <Table.Th>Customer ID</Table.Th>
          <Table.Th>Customer Name</Table.Th>
          <Table.Th>Container #</Table.Th>
          <Table.Th>Cargo Type</Table.Th>
          <Table.Th>Weight</Table.Th>
          <Table.Th>Arrival</Table.Th>
          <Table.Th>Inspection</Table.Th>
          <Table.Th>Current Status</Table.Th>
          <Table.Th>Last Mile</Table.Th>
          <Table.Th>Pickup Option</Table.Th>
        </Table.Tr>
      </Table.Thead>
      <Table.Tbody>
        {items.map((it: ImportTrainItem) => (
          <Table.Tr key={it.bookingId}>
            <Table.Td>
              <Text size="xs" c="dimmed">{it.bookingId.slice(0, 8)}…</Text>
            </Table.Td>
            <Table.Td>
              <Text size="xs" fw={600}>{it.bookingReference ?? '—'}</Text>
            </Table.Td>
            <Table.Td>
              <Text size="xs" c="dimmed">{it.customerId ? `${it.customerId.slice(0, 8)}…` : '—'}</Text>
            </Table.Td>
            <Table.Td>{it.customerName ?? '—'}</Table.Td>
            <Table.Td>{it.containerNumber ?? '—'}</Table.Td>
            <Table.Td>{it.cargoType ?? '—'}</Table.Td>
            <Table.Td>{formatNumber(Number(it.weight))}</Table.Td>
            <Table.Td>{formatDate(it.arrivalTime)}</Table.Td>
            <Table.Td>
              <Badge size="xs" variant="light" color={it.inspectionStatus === 'PASSED' ? 'green' : 'gray'}>
                {it.inspectionStatus ?? 'Not inspected'}
              </Badge>
            </Table.Td>
            <Table.Td>
              <Badge size="xs" variant="light" color="gray">{it.currentStatus ?? '—'}</Badge>
            </Table.Td>
            <Table.Td>
              <Badge size="xs" variant="light" color={it.lastMileRequested ? 'blue' : 'gray'}>
                {it.lastMileRequested ? 'Yes' : 'No'}
              </Badge>
            </Table.Td>
            <Table.Td>{it.pickupOption}</Table.Td>
          </Table.Tr>
        ))}
      </Table.Tbody>
    </Table>
  );
}

/** Import Arrive Queue: arrived IMPORT trains, with Open (detail) + Auto Unload per train. */
const getPendingUnloadBookings = (train: ImportTrain) =>
  train.pendingUnloadBookings ?? train.totalBookings;

const isFullyUnloaded = (train: ImportTrain) =>
  Boolean(train.fullyUnloaded) || (train.totalBookings > 0 && getPendingUnloadBookings(train) === 0);

function ImportArriveQueueTab({
  enabled,
  onChanged,
}: {
  enabled: boolean;
  onChanged?: () => void;
}) {
  const { toast } = useToast();
  const { data: trains = [], isLoading } = useQuery(
    api.warehouses.importArriveQueue.queryOptions({ enabled }),
  );
  const autoUnloadMutation = useMutation(
    api.warehouses.autoUnloadArrivedBookings.mutationOptions(),
  );
  const [openId, setOpenId] = useState<string | null>(null);
  const [busyId, setBusyId] = useState<string | null>(null);

  const autoUnload = async (train: ImportTrain) => {
    if (isFullyUnloaded(train)) {
      toast({
        title: 'Already unloaded',
        description: `${train.trainNumber ?? 'This train'} has no remaining bookings to auto unload.`,
      });
      return;
    }

    setBusyId(train.scheduleId);
    try {
      const r = await autoUnloadMutation.mutateAsync(train.scheduleId);
      const alreadyUnloaded = r.unloadedCount === 0 && r.skippedCount > 0 && r.failedCount === 0;
      const firstReason = r.results.find((item) => item.reason)?.reason;
      const extra = [
        r.skippedCount ? `${r.skippedCount} skipped` : '',
        r.failedCount ? `${r.failedCount} failed` : '',
      ]
        .filter(Boolean)
        .join(', ');
      toast({
        title: alreadyUnloaded ? 'Already unloaded' : `${r.unloadedCount} unloaded`,
        description: alreadyUnloaded ? firstReason ?? 'This train is already in warehouse inventory.' : extra || undefined,
      });
      onChanged?.();
    } catch (error) {
      toast({ variant: 'destructive', title: 'Auto unload failed', description: extractErrorMessage(error) });
    } finally {
      setBusyId(null);
    }
  };

  return (
    <Stack gap="sm" mt="sm">
      <Text size="sm" c="dimmed">
        <b>{trains.length}</b> arrived import train{trains.length !== 1 ? 's' : ''}
      </Text>

      {isLoading ? (
        <Group justify="center" py="lg">
          <Loader size="sm" />
        </Group>
      ) : trains.length === 0 ? (
        <Text c="dimmed" ta="center" py="lg" size="sm">
          No arrived import trains. Trains appear here once their schedule status is ARRIVED.
        </Text>
      ) : (
        <Table.ScrollContainer minWidth={1500}>
          <Table highlightOnHover verticalSpacing="xs" striped>
            <Table.Thead>
              <Table.Tr>
                <Table.Th>Schedule ID</Table.Th>
                <Table.Th>Train #</Table.Th>
                <Table.Th>Route</Table.Th>
                <Table.Th>Origin</Table.Th>
                <Table.Th>Destination</Table.Th>
                <Table.Th>Arrival Time</Table.Th>
                <Table.Th ta="center">Bookings</Table.Th>
                <Table.Th ta="center">Containers</Table.Th>
                <Table.Th ta="center">Cargoes</Table.Th>
                <Table.Th>Status</Table.Th>
                <Table.Th ta="right">Actions</Table.Th>
              </Table.Tr>
            </Table.Thead>
            <Table.Tbody>
              {trains.map((t: ImportTrain) => {
                const isOpen = openId === t.scheduleId;
                const fullyUnloaded = isFullyUnloaded(t);
                const unloadedBookings = t.unloadedBookings ?? t.totalBookings - getPendingUnloadBookings(t);
                return (
                  <Fragment key={t.scheduleId}>
                    <Table.Tr>
                      <Table.Td>
                        <Text size="xs" c="dimmed">{t.scheduleId.slice(0, 8)}…</Text>
                      </Table.Td>
                      <Table.Td>
                        <Text size="sm" fw={600}>{t.trainNumber ?? '—'}</Text>
                      </Table.Td>
                      <Table.Td>{t.route ?? '—'}</Table.Td>
                      <Table.Td>{t.origin ?? '—'}</Table.Td>
                      <Table.Td>{t.destination ?? '—'}</Table.Td>
                      <Table.Td>{formatDate(t.arrivalTime)}</Table.Td>
                      <Table.Td ta="center">{t.totalBookings}</Table.Td>
                      <Table.Td ta="center">{t.totalContainers}</Table.Td>
                      <Table.Td ta="center">{t.totalCargoes}</Table.Td>
                      <Table.Td>
                        <Stack gap={2}>
                          <Badge color={fullyUnloaded ? 'green' : 'indigo'} variant="light" size="sm">
                            {fullyUnloaded ? 'UNLOADED' : t.status}
                          </Badge>
                          <Text size="xs" c="dimmed">
                            {Math.max(unloadedBookings, 0)}/{t.totalBookings} unloaded
                          </Text>
                        </Stack>
                      </Table.Td>
                      <Table.Td ta="right">
                        <Group gap="xs" justify="flex-end" wrap="nowrap">
                          <Button
                            size="compact-xs"
                            variant="light"
                            leftSection={isOpen ? <ChevronDown size={14} /> : <ChevronRight size={14} />}
                            onClick={() => setOpenId(isOpen ? null : t.scheduleId)}
                          >
                            Open
                          </Button>
                          <Button
                            size="compact-xs"
                            color={fullyUnloaded ? 'gray' : 'indigo'}
                            leftSection={<Truck size={14} />}
                            loading={busyId === t.scheduleId}
                            disabled={fullyUnloaded || t.totalBookings === 0}
                            onClick={() => autoUnload(t)}
                          >
                            {fullyUnloaded ? 'Already Unloaded' : 'Auto Unload Arrived Bookings'}
                          </Button>
                        </Group>
                      </Table.Td>
                    </Table.Tr>
                    {isOpen && (
                      <Table.Tr>
                        <Table.Td colSpan={11} bg="var(--mantine-color-gray-0)">
                          <ImportTrainDetailTable scheduleId={t.scheduleId} />
                        </Table.Td>
                      </Table.Tr>
                    )}
                  </Fragment>
                );
              })}
            </Table.Tbody>
          </Table>
        </Table.ScrollContainer>
      )}
    </Stack>
  );
}

/**
 * Import Unloaded Queue (Batch 9): all unloaded import items with the destination-inspection columns.
 * Multi-select + Mark Selected as Inspected (import passed → READY_FOR_PICKUP), and the per-item
 * Inspect / Report action stays for damage / images / weight-loss detail.
 */
function ImportUnloadedQueueTab({ enabled }: { enabled: boolean }) {
  const { toast } = useToast();
  const { data: rows = [], isLoading } = useQuery(
    api.warehouses.importUnloadedQueue.queryOptions({ enabled }),
  );
  const inspectMutation = useMutation(
    api.warehouses.bulkMarkInspected.mutationOptions(),
  );
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [inspectId, setInspectId] = useState<string | null>(null);

  const allSelected = rows.length > 0 && selected.size === rows.length;
  const someSelected = selected.size > 0 && !allSelected;
  const selectAll = () => setSelected(new Set(rows.map((r) => r.id)));
  const unselectAll = () => setSelected(new Set());
  const toggleOne = (id: string) =>
    setSelected((prev) => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });

  const markInspected = async () => {
    if (selected.size === 0) {
      toast({ variant: 'destructive', title: 'Select at least one item' });
      return;
    }
    try {
      const r = await inspectMutation.mutateAsync({ inventoryIds: [...selected] });
      toast({
        title: `${r.inspectedCount} marked inspected`,
        description: r.skippedCount ? `${r.skippedCount} skipped` : undefined,
      });
      setSelected(new Set());
    } catch (error) {
      toast({ variant: 'destructive', title: 'Mark inspected failed', description: extractErrorMessage(error) });
    }
  };

  return (
    <Stack gap="sm" mt="sm">
      <Group justify="space-between">
        <Text size="sm" c="dimmed">
          Selected: <b>{selected.size}</b> / {rows.length} unloaded
        </Text>
        <Group gap="xs">
          <Button size="compact-sm" variant="default" disabled={rows.length === 0} onClick={selectAll}>
            Select All
          </Button>
          <Button size="compact-sm" variant="default" disabled={selected.size === 0} onClick={unselectAll}>
            Unselect All
          </Button>
          <Button
            size="compact-sm"
            color="indigo"
            leftSection={<ClipboardCheck size={14} />}
            disabled={selected.size === 0}
            loading={inspectMutation.isPending}
            onClick={markInspected}
          >
            Mark Selected as Inspected
          </Button>
        </Group>
      </Group>

      {isLoading ? (
        <Group justify="center" py="lg">
          <Loader size="sm" />
        </Group>
      ) : rows.length === 0 ? (
        <Text c="dimmed" ta="center" py="lg" size="sm">
          No unloaded import items. Items appear here after Auto Unload on an arrived train.
        </Text>
      ) : (
        <Table.ScrollContainer minWidth={2000}>
          <Table highlightOnHover verticalSpacing="xs" striped>
            <Table.Thead>
              <Table.Tr>
                <Table.Th w={40}>
                  <Checkbox
                    aria-label="Select all"
                    checked={allSelected}
                    indeterminate={someSelected}
                    onChange={() => (allSelected ? unselectAll() : selectAll())}
                  />
                </Table.Th>
                <Table.Th>Booking ID</Table.Th>
                <Table.Th>Booking Ref</Table.Th>
                <Table.Th>Customer ID</Table.Th>
                <Table.Th>Customer Name</Table.Th>
                <Table.Th>Arrival Time</Table.Th>
                <Table.Th>Container #</Table.Th>
                <Table.Th>Cargo Type</Table.Th>
                <Table.Th>Weight</Table.Th>
                <Table.Th>Train Schedule</Table.Th>
                <Table.Th>Inspection</Table.Th>
                <Table.Th>Pickup Option</Table.Th>
                <Table.Th>Last Mile</Table.Th>
                <Table.Th>Current Status</Table.Th>
                <Table.Th ta="right">Actions</Table.Th>
              </Table.Tr>
            </Table.Thead>
            <Table.Tbody>
              {rows.map((r: ImportUnloadedItem) => (
                <Table.Tr key={r.id}>
                  <Table.Td>
                    <Checkbox
                      aria-label={`Select ${r.bookingReference ?? r.id}`}
                      checked={selected.has(r.id)}
                      onChange={() => toggleOne(r.id)}
                    />
                  </Table.Td>
                  <Table.Td>
                    <Text size="xs" c="dimmed">{r.bookingId ? `${r.bookingId.slice(0, 8)}…` : '—'}</Text>
                  </Table.Td>
                  <Table.Td>
                    <Text size="sm" fw={600}>{r.bookingReference ?? '—'}</Text>
                  </Table.Td>
                  <Table.Td>
                    <Text size="xs" c="dimmed">{r.customerId ? `${r.customerId.slice(0, 8)}…` : '—'}</Text>
                  </Table.Td>
                  <Table.Td>{r.customerName ?? '—'}</Table.Td>
                  <Table.Td>{formatDate(r.arrivalTime)}</Table.Td>
                  <Table.Td>{r.containerNumber ?? '—'}</Table.Td>
                  <Table.Td>{r.cargoType ?? '—'}</Table.Td>
                  <Table.Td>{formatNumber(Number(r.weight))}</Table.Td>
                  <Table.Td>{r.trainSchedule ?? '—'}</Table.Td>
                  <Table.Td>
                    <Badge color={r.inspectionStatus === 'PASSED' ? 'green' : 'gray'} variant="light" size="sm">
                      {r.inspectionStatus ?? 'Not inspected'}
                    </Badge>
                  </Table.Td>
                  <Table.Td>{r.pickupOption}</Table.Td>
                  <Table.Td>
                    <Badge color={r.lastMileRequested ? 'blue' : 'gray'} variant="light" size="sm">
                      {r.lastMileRequested ? 'Yes' : 'No'}
                    </Badge>
                  </Table.Td>
                  <Table.Td>
                    <Badge color="indigo" variant="light" size="sm">{r.currentStatus}</Badge>
                  </Table.Td>
                  <Table.Td ta="right">
                    <Button size="compact-xs" variant="light" color="orange" onClick={() => setInspectId(r.id)}>
                      Inspect / Report
                    </Button>
                  </Table.Td>
                </Table.Tr>
              ))}
            </Table.Tbody>
          </Table>
        </Table.ScrollContainer>
      )}

      <InspectionReportModal
        opened={Boolean(inspectId)}
        onClose={() => setInspectId(null)}
        inventoryId={inspectId}
      />
    </Stack>
  );
}

/**
 * Import Dispatch Queue (Batch 10): inspected import items that are PICKUP_READY (READY_FOR_PICKUP),
 * awaiting Customer Pickup (release → deliver), Store, or Dispatch. Reuses InventoryWorkbench so all
 * existing actions + modals stay intact; Last Mile shows only when the booking requested door delivery.
 * Nothing is stored automatically — Store is an explicit operator action.
 */
function ImportDispatchQueueTab({ enabled }: { enabled: boolean }) {
  const { toast } = useToast();
  const { data: items = [], isLoading } = useQuery(
    api.warehouses.listInventory.queryOptions({
      input: { filter: enabled ? { status: 'READY_FOR_PICKUP' } : undefined },
    }),
  );

  return (
    <Stack gap="sm" mt="sm">
      <Text size="sm" c="dimmed">
        <b>{items.length}</b> pickup-ready item{items.length !== 1 ? 's' : ''}
      </Text>
      <InventoryWorkbench
        items={items}
        isLoading={isLoading}
        onLastMile={(it) =>
          toast({
            title: 'Last mile delivery',
            description: `Door delivery for ${it.booking?.reference ?? it.id} — handled in the next batch.`,
          })
        }
      />
    </Stack>
  );
}

/** New bulk Receive: Import / Export tabs with eligible PAID bookings. */
function BulkReceiveModal({ opened, onClose, onReceived }: ReceiveInventoryModalProps) {
  const [location, setLocation] = useState<Location>({ warehouseId: '', yardId: '', zoneId: '' });
  const [tab, setTab] = useState<'IMPORT' | 'EXPORT'>('IMPORT');

  useEffect(() => {
    if (opened) setLocation({ warehouseId: '', yardId: '', zoneId: '' });
  }, [opened]);

  return (
    <Modal opened={opened} onClose={onClose} title="Receive at warehouse" centered size="80rem">
      <Stack gap="md">
        <LocationSelects value={location} onChange={setLocation} />

        <Tabs value={tab} onChange={(v) => setTab((v as 'IMPORT' | 'EXPORT') ?? 'IMPORT')}>
          <Tabs.List>
            <Tabs.Tab value="IMPORT" leftSection={<PackageSearch size={16} />}>
              Import
            </Tabs.Tab>
            <Tabs.Tab value="EXPORT" leftSection={<Truck size={16} />}>
              Export
            </Tabs.Tab>
          </Tabs.List>

          <Tabs.Panel value="IMPORT">
            <Tabs defaultValue="arrive-queue" mt="xs">
              <Tabs.List>
                <Tabs.Tab value="arrive-queue" leftSection={<Train size={14} />}>
                  Arrive Queue
                </Tabs.Tab>
                <Tabs.Tab value="unloaded-queue">Unloaded Queue</Tabs.Tab>
                <Tabs.Tab value="dispatch-queue">Dispatch Queue</Tabs.Tab>
              </Tabs.List>

              <Tabs.Panel value="arrive-queue">
                <ImportArriveQueueTab enabled={opened} onChanged={onReceived} />
              </Tabs.Panel>
              <Tabs.Panel value="unloaded-queue">
                <ImportUnloadedQueueTab enabled={opened} />
              </Tabs.Panel>
              <Tabs.Panel value="dispatch-queue">
                <ImportDispatchQueueTab enabled={opened} />
              </Tabs.Panel>
            </Tabs>
          </Tabs.Panel>
          <Tabs.Panel value="EXPORT">
            <Tabs defaultValue="receive-queue" mt="xs">
              <Tabs.List>
                <Tabs.Tab value="receive-queue">Receive Queue</Tabs.Tab>
                <Tabs.Tab value="received">Received</Tabs.Tab>
                <Tabs.Tab value="ready-to-load">Ready To Load</Tabs.Tab>
                <Tabs.Tab value="loaded">Loaded</Tabs.Tab>
                <Tabs.Tab value="dispatch-queue">Dispatch Queue</Tabs.Tab>
              </Tabs.List>

              <Tabs.Panel value="receive-queue">
                <EligibleTab direction="EXPORT" location={location} enabled={opened} onChanged={onReceived} />
              </Tabs.Panel>
              <Tabs.Panel value="received">
                <ExportReceivedTab enabled={opened} onChanged={onReceived} />
              </Tabs.Panel>
              <Tabs.Panel value="ready-to-load">
                <ReadyToLoadTab enabled={opened} onChanged={onReceived} />
              </Tabs.Panel>
              <Tabs.Panel value="loaded">
                <LoadedExportTab enabled={opened} dispatchable={false} onChanged={onReceived} />
              </Tabs.Panel>
              <Tabs.Panel value="dispatch-queue">
                <LoadedExportTab enabled={opened} dispatchable onChanged={onReceived} />
              </Tabs.Panel>
            </Tabs>
          </Tabs.Panel>
        </Tabs>

        <Group justify="flex-end" mt="sm">
          <Button variant="default" onClick={onClose}>
            Close
          </Button>
        </Group>
      </Stack>
    </Modal>
  );
}

interface SingleFormState {
  warehouseId: string;
  yardId: string;
  zoneId: string;
  quantity: number | '';
  weight: number | '';
  volume: number | '';
  notes: string;
}

/** Legacy single-booking receive — used when a specific bookingId is supplied. */
function SingleBookingReceiveModal({
  opened,
  onClose,
  bookingId,
  bookingLabel,
  onReceived,
}: ReceiveInventoryModalProps) {
  const { toast } = useToast();
  const receiveMutation = useMutation(
    api.warehouses.receiveInventory.mutationOptions(),
  );
  const [selectedBooking, setSelectedBooking] = useState(bookingId ?? '');
  const [form, setForm] = useState<SingleFormState>({
    warehouseId: '',
    yardId: '',
    zoneId: '',
    quantity: '',
    weight: '',
    volume: '',
    notes: '',
  });
  const [truckForm, setTruckForm] = useState<TruckEntranceFormState>(emptyTruckEntrance());

  useEffect(() => {
    if (opened) {
      setSelectedBooking(bookingId ?? '');
      setForm({ warehouseId: '', yardId: '', zoneId: '', quantity: '', weight: '', volume: '', notes: '' });
      setTruckForm(emptyTruckEntrance());
    }
  }, [opened, bookingId]);

  const location: Location = { warehouseId: form.warehouseId, yardId: form.yardId, zoneId: form.zoneId };

  const handleSubmit = async () => {
    if (!selectedBooking.trim()) {
      toast({ variant: 'destructive', title: 'Booking is required' });
      return;
    }
    if (!form.warehouseId || !form.yardId || !form.zoneId) {
      toast({ variant: 'destructive', title: 'Select warehouse, yard and zone' });
      return;
    }
    if (!truckForm.truckPlateNumber.trim() || !truckForm.driverName.trim() || !truckForm.driverPhone.trim() || truckForm.entranceTareWeightKg === '') {
      toast({ variant: 'destructive', title: 'Truck, driver and entrance tare weight are required' });
      return;
    }
    const payload: ReceiveInventoryPayload = {
      bookingId: selectedBooking.trim(),
      warehouseId: form.warehouseId,
      yardId: form.yardId,
      zoneId: form.zoneId,
      quantity: 0,
      weight: 0,
      volume: form.volume === '' ? undefined : Number(form.volume),
      notes: form.notes.trim() || undefined,
      truckEntrance: toTruckEntrancePayload(truckForm),
    };
    try {
      await receiveMutation.mutateAsync(payload);
      toast({ title: 'Inventory received' });
      onReceived?.();
      onClose();
    } catch (error) {
      toast({ variant: 'destructive', title: 'Receive failed', description: extractErrorMessage(error) });
    }
  };

  return (
    <Modal opened={opened} onClose={onClose} title="Receive at warehouse" centered size="lg">
      <Stack gap="md">
        {bookingId ? (
          <TextInput label="Booking" value={bookingLabel ?? bookingId} readOnly />
        ) : (
          <BookingSelect label="Booking" value={selectedBooking} onChange={setSelectedBooking} />
        )}

        <LocationSelects value={location} onChange={(next) => setForm((f) => ({ ...f, ...next }))} />

        <Alert icon={<Info size={16} />} color="blue" variant="light">
          <Text size="sm">
            Customer, TIN, phone, quantity and weight are pulled from the selected booking when the GRN is generated.
          </Text>
        </Alert>

        <Group grow>
          <NumberInput
            label="Volume (m³)"
            placeholder="Optional"
            min={0}
            value={form.volume}
            onChange={(value) => setForm((f) => ({ ...f, volume: value === '' ? '' : Number(value) }))}
          />
        </Group>

        <TruckEntranceFields value={truckForm} onChange={setTruckForm} />

        <Textarea
          label="Notes"
          placeholder="Optional notes"
          autosize
          minRows={2}
          value={form.notes}
          onChange={(e) => {
            const v = e.currentTarget.value;
            setForm((f) => ({ ...f, notes: v }));
          }}
        />

        <Group justify="flex-end" mt="sm">
          <Button variant="default" onClick={onClose} disabled={receiveMutation.isPending}>
            Cancel
          </Button>
          <Button onClick={handleSubmit} loading={receiveMutation.isPending}>
            Receive inventory and generate GRN
          </Button>
        </Group>
      </Stack>
    </Modal>
  );
}

export function ReceiveInventoryModal(props: ReceiveInventoryModalProps) {
  // Locked to a booking → legacy single receive; otherwise the Import/Export bulk flow.
  return props.bookingId ? <SingleBookingReceiveModal {...props} /> : <BulkReceiveModal {...props} />;
}
