import { Fragment, useEffect, useMemo, useState } from 'react';
import {
  Badge,
  Button,
  Card,
  Group,
  Loader,
  Select,
  Stack,
  Table,
  Text,
} from '@mantine/core';
import { ChevronDown, ChevronRight, PackageOpen, Truck } from 'lucide-react';

import { PageContainer, PageHeader } from '@/components/page';
import {
  VisualEmptyState,
  WarehouseOpsKpiStrip,
  formatDate,
  formatNumber,
} from '@/components/warehouses';
import {
  useAutoUnloadArrivedBookings,
  useAllWarehouseYards,
  useAllWarehouseZones,
  useImportArriveQueue,
  useImportTrainItems,
  useWarehouses,
} from '@/hooks/useWarehouses';
import { useToast } from '@/hooks/use-toast';
import type { AutoUnloadArrivedResult, ImportTrain, ImportTrainItem, Warehouse, WarehouseYard, WarehouseZone } from '@/types/warehouse';

type UnloadAssignment = { bookingId: string; warehouseId: string; yardId: string; zoneId: string };
type AssignmentDraft = Partial<Omit<UnloadAssignment, 'bookingId'>>;

const getErrorMessage = (error: unknown) => {
  if (error && typeof error === 'object' && 'response' in error) {
    const response = (error as { response?: { data?: { message?: unknown } } }).response;
    const message = response?.data?.message;
    if (Array.isArray(message)) return message.join(', ');
    if (typeof message === 'string') return message;
  }
  return error instanceof Error ? error.message : undefined;
};

const getPendingUnloadBookings = (train: ImportTrain) =>
  train.pendingUnloadBookings ?? train.totalBookings;

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

const locationTypesForFreight = (freightType: string | null | undefined) => {
  const normalized = (freightType ?? '').toUpperCase();
  if (normalized === 'CONTAINER') {
    return { yardTypes: ['CONTAINER_YARD', 'GENERAL_CARGO_YARD'], zoneTypes: ['CONTAINER_ZONE', 'GENERAL_CARGO_ZONE'] };
  }
  return { yardTypes: ['BULK_YARD', 'GENERAL_CARGO_YARD'], zoneTypes: ['BULK_ZONE', 'GENERAL_CARGO_ZONE'] };
};

const isContainerFreight = (freightType: string | null | undefined) =>
  (freightType ?? '').toUpperCase() === 'CONTAINER';

function isUnloadPending(item: ImportTrainItem) {
  return !item.currentStatus || item.currentStatus === 'RECEIVED';
}

function ImportTrainDetailRows({
  scheduleId,
  warehouses,
  yards,
  zones,
  assignments,
  onAssignmentChange,
  onReadyChange,
}: {
  scheduleId: string;
  warehouses: Warehouse[];
  yards: WarehouseYard[];
  zones: WarehouseZone[];
  assignments: Record<string, AssignmentDraft>;
  onAssignmentChange: (bookingId: string, draft: AssignmentDraft) => void;
  onReadyChange: (ready: boolean) => void;
}) {
  const { data: items = [], isLoading } = useImportTrainItems(scheduleId);
  const warehouseOptions = useMemo(
    () => warehouses.map((warehouse) => ({ value: warehouse.id, label: `${warehouse.name} (${warehouse.code})` })),
    [warehouses],
  );

  useEffect(() => {
    const pending = items.filter(isUnloadPending);
    onReadyChange(
      pending.length > 0 &&
        pending.every((item) => {
          const draft = assignments[item.bookingId];
          return Boolean(draft?.warehouseId && draft.yardId && draft.zoneId);
        }),
    );
  }, [assignments, items]);

  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 found for this train.
      </Text>
    );
  }

  return (
    <Table highlightOnHover verticalSpacing="xs">
      <Table.Thead>
        <Table.Tr>
          <Table.Th>Booking</Table.Th>
          <Table.Th>Customer</Table.Th>
          <Table.Th>Container</Table.Th>
          <Table.Th>Cargo</Table.Th>
          <Table.Th>Weight</Table.Th>
          <Table.Th>Arrival</Table.Th>
          <Table.Th>Status</Table.Th>
          <Table.Th>Warehouse</Table.Th>
          <Table.Th>Yard</Table.Th>
          <Table.Th>Zone</Table.Th>
          <Table.Th>Inspection</Table.Th>
          <Table.Th>Pickup</Table.Th>
        </Table.Tr>
      </Table.Thead>
      <Table.Tbody>
        {items.map((item: ImportTrainItem) => {
          const draft = assignments[item.bookingId] ?? {};
          const { yardTypes, zoneTypes } = locationTypesForFreight(item.freightType);
          const yardOptions = yards
            .filter((yard) => yard.warehouseId === draft.warehouseId && yardTypes.includes(yard.type))
            .map((yard) => ({ value: yard.id, label: `${yard.name} (${yard.code})` }));
          const zoneOptions = zones
            .filter((zone) => zone.yardId === draft.yardId && zoneTypes.includes(zone.type))
            .map((zone) => ({ value: zone.id, label: `${zone.name} (${zone.code})` }));
          const pending = isUnloadPending(item);

          return (
          <Table.Tr key={item.bookingId}>
            <Table.Td>
              <Text size="sm" fw={600}>
                {item.bookingReference ?? item.bookingId.slice(0, 8)}
              </Text>
            </Table.Td>
            <Table.Td>{item.customerName ?? '—'}</Table.Td>
            <Table.Td>{item.containerNumber ?? '—'}</Table.Td>
            <Table.Td>{item.cargoType ?? '—'}</Table.Td>
            <Table.Td>{formatNumber(item.weight)}</Table.Td>
            <Table.Td>{formatDate(item.arrivalTime)}</Table.Td>
            <Table.Td>
              <Badge variant="light" color={item.currentStatus === 'UNLOADED' ? 'green' : 'orange'} size="sm">
                {item.currentStatus ?? 'PENDING'}
              </Badge>
            </Table.Td>
            <Table.Td>
              <Select
                placeholder="Warehouse"
                data={warehouseOptions}
                value={draft.warehouseId ?? null}
                onChange={(value) => onAssignmentChange(item.bookingId, { warehouseId: value ?? undefined })}
                searchable
                disabled={!pending}
                w={210}
              />
            </Table.Td>
            <Table.Td>
              <Select
                placeholder={isContainerFreight(item.freightType) ? 'Container yard' : 'Bulk yard'}
                data={yardOptions}
                value={draft.yardId ?? null}
                onChange={(value) =>
                  onAssignmentChange(item.bookingId, { ...draft, yardId: value ?? undefined, zoneId: undefined })
                }
                searchable
                disabled={!pending || !draft.warehouseId}
                w={190}
              />
            </Table.Td>
            <Table.Td>
              <Select
                placeholder={isContainerFreight(item.freightType) ? 'Container zone' : 'Bulk zone'}
                data={zoneOptions}
                value={draft.zoneId ?? null}
                onChange={(value) => onAssignmentChange(item.bookingId, { ...draft, zoneId: value ?? undefined })}
                searchable
                disabled={!pending || !draft.yardId}
                w={190}
              />
            </Table.Td>
            <Table.Td>
              <Badge variant="light" color={item.inspectionStatus === 'PASSED' ? 'green' : 'gray'} size="sm">
                {item.inspectionStatus ?? 'Not inspected'}
              </Badge>
            </Table.Td>
            <Table.Td>{item.pickupOption.replace(/_/g, ' ')}</Table.Td>
          </Table.Tr>
          );
        })}
      </Table.Tbody>
    </Table>
  );
}

/** Arrived import trains awaiting unload into warehouse inventory. */
export default function ArrivalQueuePage() {
  const { toast } = useToast();
  const { data: trains = [], isLoading } = useImportArriveQueue();
  const { data: warehouses = [], isLoading: warehousesLoading } = useWarehouses({ status: 'ACTIVE' });
  const { data: yards = [] } = useAllWarehouseYards();
  const { data: zones = [] } = useAllWarehouseZones();
  const autoUnload = useAutoUnloadArrivedBookings();
  const [openScheduleId, setOpenScheduleId] = useState<string | null>(null);
  const [busyScheduleId, setBusyScheduleId] = useState<string | null>(null);
  const [assignmentsBySchedule, setAssignmentsBySchedule] = useState<Record<string, Record<string, AssignmentDraft>>>({});
  const [readyBySchedule, setReadyBySchedule] = useState<Record<string, boolean>>({});

  const unloadTrain = async (train: ImportTrain) => {
    const assignments = Object.entries(assignmentsBySchedule[train.scheduleId] ?? {})
      .filter((entry): entry is [string, Required<AssignmentDraft>] =>
        Boolean(entry[1].warehouseId && entry[1].yardId && entry[1].zoneId),
      )
      .map(([bookingId, draft]) => ({
        bookingId,
        warehouseId: draft.warehouseId,
        yardId: draft.yardId,
        zoneId: draft.zoneId,
      }));

    if (!readyBySchedule[train.scheduleId] || assignments.length === 0) {
      toast({
        variant: 'destructive',
        title: 'Assign locations',
        description: 'Select warehouse, yard and zone for each pending booking before unloading.',
      });
      return;
    }

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

    setBusyScheduleId(train.scheduleId);
    try {
      const res = (await autoUnload.mutateAsync({ scheduleId: train.scheduleId, assignments })) as {
        data: AutoUnloadArrivedResult;
      };
      const result = res.data;
      const alreadyUnloaded = result.unloadedCount === 0 && result.skippedCount > 0 && result.failedCount === 0;
      const firstReason = result.results.find((item) => item.reason)?.reason;
      const details = [
        result.skippedCount ? `${result.skippedCount} skipped` : '',
        result.failedCount ? `${result.failedCount} failed` : '',
      ]
        .filter(Boolean)
        .join(', ');

      toast({
        title: alreadyUnloaded ? 'Already unloaded' : `${result.unloadedCount} booking(s) unloaded`,
        description: alreadyUnloaded
          ? firstReason ?? `${train.trainNumber ?? 'Train'} is already in warehouse inventory.`
          : details || `${train.trainNumber ?? 'Train'} moved into warehouse inventory.`,
      });
    } catch (error) {
      toast({
        variant: 'destructive',
        title: 'Auto unload failed',
        description: getErrorMessage(error),
      });
    } finally {
      setBusyScheduleId(null);
    }
  };

  return (
    <PageContainer>
      <PageHeader
        title="Arrival / Unloading Queue"
        subtitle="Arrived import trains ready to unload assigned bookings into warehouse inventory."
        breadcrumbs={[{ label: 'Arrival queue' }]}
      />

      <WarehouseOpsKpiStrip />

      <Card withBorder radius="md" padding="lg">
          <Group justify="space-between" mb="md">
            <Stack gap={2}>
              <Text fw={600}>{trains.length} arrived import train(s)</Text>
              <Text size="sm" c="dimmed">
                Open a train, assign each booking to a warehouse yard and zone, then unload it.
              </Text>
            </Stack>
          </Group>

          {isLoading ? (
            <Group justify="center" py="xl">
              <Loader />
            </Group>
          ) : trains.length === 0 ? (
            <VisualEmptyState
              variant="container"
              title="No arrived import trains"
              description="Import trains appear here once their train schedule status is ARRIVED."
            />
          ) : (
            <Table.ScrollContainer minWidth={1150}>
              <Table verticalSpacing="sm" highlightOnHover striped>
                <Table.Thead>
                  <Table.Tr>
                    <Table.Th>Train</Table.Th>
                    <Table.Th>Route</Table.Th>
                    <Table.Th>Origin</Table.Th>
                    <Table.Th>Destination</Table.Th>
                    <Table.Th>Arrival</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((train: ImportTrain) => {
                    const isOpen = openScheduleId === train.scheduleId;
                    const fullyUnloaded = isFullyUnloaded(train);
                    const unloadedBookings = train.unloadedBookings ?? train.totalBookings - getPendingUnloadBookings(train);
                    return (
                      <Fragment key={train.scheduleId}>
                        <Table.Tr>
                          <Table.Td>
                            <Stack gap={0}>
                              <Text size="sm" fw={700}>
                                {train.trainNumber ?? '—'}
                              </Text>
                              <Text size="xs" c="dimmed">
                                {train.scheduleId.slice(0, 8)}
                              </Text>
                            </Stack>
                          </Table.Td>
                          <Table.Td>{train.route ?? '—'}</Table.Td>
                          <Table.Td>{train.origin ?? '—'}</Table.Td>
                          <Table.Td>{train.destination ?? '—'}</Table.Td>
                          <Table.Td>
                            <Text size="xs">{formatDate(train.arrivalTime)}</Text>
                          </Table.Td>
                          <Table.Td ta="center">{train.totalBookings}</Table.Td>
                          <Table.Td ta="center">{train.totalContainers}</Table.Td>
                          <Table.Td ta="center">{train.totalCargoes}</Table.Td>
                          <Table.Td>
                            <Stack gap={2}>
                              <Badge variant="light" color="teal" size="sm">
                                {train.status}
                              </Badge>
                              <Text size="xs" c="dimmed">
                                {Math.max(unloadedBookings, 0)}/{train.totalBookings} unloaded
                              </Text>
                            </Stack>
                          </Table.Td>
                          <Table.Td>
                            <Group gap="xs" justify="flex-end" wrap="nowrap">
                              <Button
                                size="compact-xs"
                                variant="light"
                                leftSection={isOpen ? <ChevronDown size={14} /> : <ChevronRight size={14} />}
                                onClick={() => setOpenScheduleId(isOpen ? null : train.scheduleId)}
                              >
                                Open
                              </Button>
                              <Button
                                size="compact-xs"
                                color={fullyUnloaded ? 'gray' : 'orange'}
                                leftSection={busyScheduleId === train.scheduleId ? <PackageOpen size={14} /> : <Truck size={14} />}
                                loading={busyScheduleId === train.scheduleId}
                                disabled={fullyUnloaded || train.totalBookings === 0 || !readyBySchedule[train.scheduleId] || warehousesLoading}
                                onClick={() => unloadTrain(train)}
                              >
                                {fullyUnloaded ? 'Already Unloaded' : 'Auto Unload'}
                              </Button>
                            </Group>
                          </Table.Td>
                        </Table.Tr>
                        {isOpen && (
                          <Table.Tr>
                            <Table.Td colSpan={10} bg="var(--mantine-color-gray-0)">
                              <ImportTrainDetailRows
                                scheduleId={train.scheduleId}
                                warehouses={warehouses}
                                yards={yards}
                                zones={zones}
                                assignments={assignmentsBySchedule[train.scheduleId] ?? {}}
                                onAssignmentChange={(bookingId, draft) =>
                                  setAssignmentsBySchedule((current) => ({
                                    ...current,
                                    [train.scheduleId]: {
                                      ...(current[train.scheduleId] ?? {}),
                                      [bookingId]: draft.warehouseId
                                        ? draft
                                        : {},
                                    },
                                  }))
                                }
                                onReadyChange={(ready) =>
                                  setReadyBySchedule((current) => ({ ...current, [train.scheduleId]: ready }))
                                }
                              />
                            </Table.Td>
                          </Table.Tr>
                        )}
                      </Fragment>
                    );
                  })}
                </Table.Tbody>
              </Table>
            </Table.ScrollContainer>
          )}
      </Card>
    </PageContainer>
  );
}
