import { useState } from 'react';
import { Button, Center, Group, Loader, Stack, Text } from '@mantine/core';
import { ClipboardCheck } from 'lucide-react';

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

import { api } from '@/services/api';
import { useToast } from '@/hooks/use-toast';
import { lastMileService } from '@/services/last-mile.service';
import { warehouseService } from '@/services/warehouse.service';
import type { InventoryAction, WarehouseInventoryItem } from '@/types/warehouse';
import { DeliverInventoryModal } from './DeliverInventoryModal';
import { FeePreviewModal } from './FeePreviewModal';
import { InspectionReportModal } from './InspectionReportModal';
import { InventoryDetailModal } from './InventoryDetailModal';
import { InventoryHistoryModal } from './InventoryHistoryModal';
import { LoadInventoryModal } from './LoadInventoryModal';
import { MoveInventoryModal } from './MoveInventoryModal';
import { ReleaseOrderModal } from './ReleaseOrderModal';
import { WarehouseInventoryTable } from './WarehouseInventoryTable';
import ListControls from '@/components/common/ListControls';
// Generic list footer — already shared by the fleet and train-scheduling lists
// despite the ruleEngine path; reused here rather than adding a second one.
import RuleEngineListFooter from '@/components/ruleEngine/RuleEngineListFooter';
import { useListControls } from '@/hooks/useListControls';
import { extractDownloadErrorMessage, extractErrorMessage } from './options';
import { openPdfBlob, saveBlob } from './pdf';

interface InventoryWorkbenchProps {
  items: WarehouseInventoryItem[];
  isLoading?: boolean;
  /** Optional Last Mile action (Batch 8) — only shown for items whose booking requested door delivery. */
  onLastMile?: (item: WarehouseInventoryItem) => void;
}

/** Inventory table + all lifecycle actions (advance / move / history). */
export function InventoryWorkbench({ items, isLoading, onLastMile }: InventoryWorkbenchProps) {
  const { toast } = useToast();
  const [busyId, setBusyId] = useState<string | null>(null);
  const [moveItem, setMoveItem] = useState<WarehouseInventoryItem | null>(null);
  const [loadItem, setLoadItem] = useState<WarehouseInventoryItem | null>(null);
  const [historyItem, setHistoryItem] = useState<WarehouseInventoryItem | null>(null);
  const [viewItem, setViewItem] = useState<WarehouseInventoryItem | null>(null);
  const [inspectItem, setInspectItem] = useState<WarehouseInventoryItem | null>(null);
  const [feeItem, setFeeItem] = useState<WarehouseInventoryItem | null>(null);
  const [releaseItem, setReleaseItem] = useState<WarehouseInventoryItem | null>(null);
  const [deliverItem, setDeliverItem] = useState<WarehouseInventoryItem | null>(null);

  const storeMutation = useMutation(api.warehouses.store.mutationOptions());
  const readyMutation = useMutation(
    api.warehouses.markReadyForLoading.mutationOptions(),
  );
  const pickupMutation = useMutation(
    api.warehouses.markReadyForPickup.mutationOptions(),
  );
  const dispatchMutation = useMutation(api.warehouses.dispatch.mutationOptions());
  const lastMileMutation = useMutation({
    mutationFn: (bookingReference: string) => lastMileService.accept(bookingReference).then((r) => r.data),
  });
  const inspectMutation = useMutation(
    api.warehouses.bulkMarkInspected.mutationOptions(),
  );

  const controls = useListControls(items, {
    searchKeys: ['grnNumber', 'bookingReference', 'customerName', 'status', 'releaseOrderReference', 'notes'],
    dateKey: 'arrivedAt',
  });
  const visible = controls.filteredRows;

  const [selected, setSelected] = useState<Set<string>>(new Set());
  // Select-all spans everything matching the current filters, not just the rows
  // on screen — bulk "mark inspected" over one page of a filtered set would be a
  // surprise. Counts compare against the filtered set for the same reason.
  const allSelected = visible.length > 0 && selected.size === visible.length;
  const someSelected = selected.size > 0 && !allSelected;
  const toggleSelect = (id: string) =>
    setSelected((prev) => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });
  const toggleSelectAll = () =>
    setSelected(allSelected ? new Set() : new Set(visible.map((i) => i.id)));

  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) });
    }
  };

  const runDirect = async (item: WarehouseInventoryItem, fn: () => Promise<unknown>, label: string) => {
    setBusyId(item.id);
    try {
      await fn();
      toast({ title: label });
    } catch (error) {
      toast({ variant: 'destructive', title: 'Action failed', description: extractErrorMessage(error) });
    } finally {
      setBusyId(null);
    }
  };

  const downloadReleaseDocument = async (item: WarehouseInventoryItem) => {
    setBusyId(item.id);
    const pdfWindow = window.open('', '_blank');
    try {
      const response = await warehouseService.downloadReleaseDocument(item.id);
      const blob = response.data;
      const filename = `release-${item.booking?.reference ?? item.bookingId ?? item.id}.pdf`;
      const opened = openPdfBlob(blob, filename, pdfWindow);
      toast({ title: opened ? 'Release exit paper opened' : 'Release exit paper downloaded' });
    } catch (error) {
      pdfWindow?.close();
      toast({
        variant: 'destructive',
        title: 'Release paper preview failed',
        description: await extractDownloadErrorMessage(error),
      });
    } finally {
      setBusyId(null);
    }
  };

  const openHandoverDocument = async (item: WarehouseInventoryItem) => {
    setBusyId(item.id);
    const pdfWindow = window.open('', '_blank');
    try {
      const response = await warehouseService.downloadHandoverDocument(item.id);
      const filename = `handover-${item.booking?.reference ?? item.bookingId ?? item.id}.pdf`;
      const opened = openPdfBlob(response.data, filename, pdfWindow);
      toast({ title: opened ? 'Handover document opened' : 'Handover document downloaded' });
    } catch (error) {
      pdfWindow?.close();
      toast({
        variant: 'destructive',
        title: 'Handover document failed',
        description: await extractDownloadErrorMessage(error),
      });
    } finally {
      setBusyId(null);
    }
  };

  // One-click bundle: download every available document for the item (GRN +
  // gate clearance / release order + handover). Best-effort — docs that aren't
  // generatable yet for this item are skipped.
  const downloadDocumentBundle = async (item: WarehouseInventoryItem) => {
    setBusyId(item.id);
    const ref = item.booking?.reference ?? item.bookingId ?? item.id;
    const jobs: Array<{ name: string; fn: () => Promise<{ data: Blob }> }> = [
      { name: `GRN-${ref}.pdf`, fn: () => warehouseService.downloadGrnDocument(item.id) },
      { name: `gate-clearance-${ref}.pdf`, fn: () => warehouseService.downloadReleaseDocument(item.id) },
      { name: `handover-${ref}.pdf`, fn: () => warehouseService.downloadHandoverDocument(item.id) },
    ];
    let saved = 0;
    for (const job of jobs) {
      try {
        const response = await job.fn();
        saveBlob(response.data, job.name);
        saved += 1;
      } catch {
        // Document not available for this item yet — skip it.
      }
    }
    setBusyId(null);
    if (saved === 0) {
      toast({
        variant: 'destructive',
        title: 'No documents available',
        description: 'This item has no GRN, gate clearance or handover document yet.',
      });
    } else {
      toast({
        title: `Downloaded ${saved} document${saved !== 1 ? 's' : ''}`,
        description: `Bundle for ${ref} (available documents only).`,
      });
    }
  };

  const acceptLastMile = async (item: WarehouseInventoryItem) => {
    const reference = item.booking?.reference;
    if (!reference) {
      toast({
        variant: 'destructive',
        title: 'Last mile failed',
        description: 'Booking reference is missing for this inventory item.',
      });
      return;
    }
    setBusyId(item.id);
    try {
      const record = await lastMileMutation.mutateAsync(reference);
      toast({
        title: 'Last mile accepted',
        description: `${reference} moved to last-mile queue (${record.status.replace(/_/g, ' ')}).`,
      });
    } catch (error) {
      toast({
        variant: 'destructive',
        title: 'Last mile failed',
        description: extractErrorMessage(error),
      });
    } finally {
      setBusyId(null);
    }
  };

  const storeInventory = async (item: WarehouseInventoryItem) => {
    setBusyId(item.id);
    try {
      const stored = await storeMutation.mutateAsync({ id: item.id });
      toast({
        title: 'Inventory stored',
        description: [stored.warehouse?.code, stored.yard?.code, stored.zone?.code].filter(Boolean).join(' / '),
      });
    } catch (error) {
      toast({ variant: 'destructive', title: 'Store failed', description: extractErrorMessage(error) });
    } finally {
      setBusyId(null);
    }
  };

  const advance = (item: WarehouseInventoryItem, action: InventoryAction) => {
    switch (action) {
      case 'store':
        return storeInventory(item);
      case 'ready-for-loading':
        return runDirect(item, () => readyMutation.mutateAsync(item.id), 'Ready for loading');
      case 'load':
        setLoadItem(item);
        return;
      case 'dispatch':
        return runDirect(item, () => dispatchMutation.mutateAsync(item.id), 'Inventory dispatched');
      case 'ready-for-pickup':
        return runDirect(item, () => pickupMutation.mutateAsync(item.id), 'Ready for pickup');
      case 'release':
        setReleaseItem(item);
        return;
      case 'deliver':
        setDeliverItem(item);
        return;
      default:
        return;
    }
  };

  if (isLoading) {
    return (
      <Center py="xl">
        <Loader />
      </Center>
    );
  }

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

        <ListControls
          search={controls.search}
          onSearchChange={controls.setSearch}
          searchPlaceholder="GRN, container, booking, customer…"
          dateFrom={controls.dateFrom}
          onDateFromChange={controls.setDateFrom}
          dateTo={controls.dateTo}
          onDateToChange={controls.setDateTo}
          dateLabel="Arrived"
          hasFilters={controls.hasFilters}
          onReset={controls.reset}
        />

        <WarehouseInventoryTable
          items={controls.pagedRows}
          busyId={busyId}
          onAdvance={advance}
          onMove={setMoveItem}
          onHistory={setHistoryItem}
          onView={setViewItem}
          onInspect={setInspectItem}
          onFeePreview={setFeeItem}
          onReleaseDocument={downloadReleaseDocument}
          onHandoverDocument={openHandoverDocument}
          onDownloadBundle={downloadDocumentBundle}
          onLastMile={onLastMile ? acceptLastMile : undefined}
          selectedIds={selected}
          onToggleSelect={toggleSelect}
          onToggleSelectAll={toggleSelectAll}
          allSelected={allSelected}
          someSelected={someSelected}
        />

        <RuleEngineListFooter
          pagination={controls.pagination}
          pageCount={controls.pageCount}
          totalCount={controls.totalCount}
          itemLabel="items"
          onPaginationChange={controls.setPagination}
        />
      </Stack>

      <MoveInventoryModal opened={Boolean(moveItem)} onClose={() => setMoveItem(null)} item={moveItem} />
      <LoadInventoryModal opened={Boolean(loadItem)} onClose={() => setLoadItem(null)} item={loadItem} />
      <InventoryHistoryModal
        opened={Boolean(historyItem)}
        onClose={() => setHistoryItem(null)}
        item={historyItem}
      />
      <InventoryDetailModal opened={Boolean(viewItem)} onClose={() => setViewItem(null)} item={viewItem} />
      <InspectionReportModal
        opened={Boolean(inspectItem)}
        onClose={() => setInspectItem(null)}
        inventoryId={inspectItem?.id ?? null}
      />
      <FeePreviewModal
        opened={Boolean(feeItem)}
        onClose={() => setFeeItem(null)}
        inventoryId={feeItem?.id ?? null}
      />
      <ReleaseOrderModal opened={Boolean(releaseItem)} onClose={() => setReleaseItem(null)} item={releaseItem} />
      <DeliverInventoryModal opened={Boolean(deliverItem)} onClose={() => setDeliverItem(null)} item={deliverItem} />
    </>
  );
}
