import { useEffect, useState } from 'react';
import { Alert, Button, Group, Modal, NumberInput, Select, SimpleGrid, Stack, Text, TextInput } from '@mantine/core';
import { Info, Scale } from 'lucide-react';

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

import { api } from '@/services/api';
import { useToast } from '@/hooks/use-toast';
import { warehouseService } from '@/services/warehouse.service';
import type { WarehouseInventoryItem } from '@/types/warehouse';
import { extractErrorMessage } from './options';
import { openPdfBlob } from './pdf';

interface ReleaseOrderModalProps {
  opened: boolean;
  onClose: () => void;
  item: WarehouseInventoryItem | null;
}

const REGISTERED_FIRST_LAST_MILE_TRUCKS = [
  ['03-ET A45843', '43495'], ['03-ET A45866', '43470'], ['03-ET A45853', '43508'], ['03-ET A45849', '43414'],
  ['03-ET A45845', '43492'], ['03-ET A45820', '43487'], ['03-ET A45842', '43478'], ['03-ET A45841', '43515'],
  ['03-ET A45832', '43504'], ['03-ET A45856', '43510'], ['03-ET A45865', '43490'], ['03-ET A45855', '43485'],
  ['03-ET A45840', '43499'], ['03-ET A45867', '43493'], ['03-ET A45833', '43466'], ['03-ET A45858', '43496'],
  ['03-ET A45819', '43474'], ['03-ET A45834', '43502'], ['03-ET A45868', '43469'], ['03-ET A45831', '43488'],
  ['03-ET A45828', '43479'], ['03-ET A45850', '43505'], ['03-ET A45823', '43480'], ['03-ET A45838', '43472'],
  ['03-ET A45854', '43500'], ['03-ET A45839', '43486'], ['03-ET A45861', '43513'], ['03-ET A45830', '43501'],
  ['03-ET A45826', '43498'], ['03-ET A45836', '43467'], ['03-ET A45822', '43512'], ['03-ET A45821', '43210'],
  ['03-ET A45837', '43475'], ['03-ET A45860', '43497'], ['03-ET A45863', '43477'], ['03-ET A45825', '43483'],
  ['03-ET A45829', '43473'], ['03-ET A45824', '43491'], ['03-ET A45857', '43481'], ['03-ET A45851', '43509'],
  ['03-ET A45827', '43468'], ['03-ET A45859', '43887'], ['03-ET A45846', '43471'], ['03-ET A45847', '43511'],
  ['03-ET A45852', '43484'], ['03-ET A45844', '43476'], ['03-ET A45835', '43482'], ['03-ET A45864', '43503'],
  ['03-ET A45848', '43494'], ['03-ET A45862', '43465'], ['03-ET A39105', '41218'], ['03-ET A39098', '41220'],
  ['03-ET A29900', '41865'], ['03-ET A39097', '41226'], ['03-ET A39104', '41225'], ['03-ET A39103', '41223'],
  ['03-ET A39106', '41221'], ['03-ET A39107', '41215'], ['03-ET A39094', '41222'], ['03-ET A39099', '41216'],
  ['03-ET A39092', '41224'], ['03-ET A31801', '41214'],
].map(([powerPlate, trailerPlate], index) => ({
  value: powerPlate,
  label: `${index + 1}. ${powerPlate} / ${trailerPlate}`,
  trailerPlate,
}));

const toIsoDateTime = (value: string) => {
  if (!value) return undefined;
  const date = new Date(value);
  return Number.isNaN(date.getTime()) ? undefined : date.toISOString();
};

const toLocalDateTimeInput = (value?: string | null) => {
  if (!value) return '';
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return '';
  const offsetMs = date.getTimezoneOffset() * 60_000;
  return new Date(date.getTime() - offsetMs).toISOString().slice(0, 16);
};

const generateReleaseReference = (item: WarehouseInventoryItem | null) => {
  const bookingReference = item?.booking?.reference;
  if (bookingReference) return `REL-${bookingReference.replace(/^BK-?/i, '')}`;
  if (item?.bookingId) return `REL-${item.bookingId.replace(/-/g, '').slice(0, 8).toUpperCase()}`;
  return '';
};

const lineValue = (notes: string | null | undefined, label: string) => {
  const match = notes?.match(new RegExp(`^${label}:\\s*(.+)$`, 'im'));
  return match?.[1]?.trim() ?? '';
};

const lineNumber = (notes: string | null | undefined, label: string): number | '' => {
  const value = lineValue(notes, label).replace(/\s*kg$/i, '');
  if (!value) return '';
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : '';
};

const splitContainerNumbers = (value: string | null | undefined) =>
  (value ?? '')
    .split(/[,;\n]+/)
    .map((number) => number.trim())
    .filter(Boolean);

const getItemContainerNumber = (item: WarehouseInventoryItem | null) =>
  (item as (WarehouseInventoryItem & { containerNumber?: string | null }) | null)?.containerNumber ?? '';

const isContainerInventory = (item: WarehouseInventoryItem | null, containerCount: number) => {
  const freightType = (item as (WarehouseInventoryItem & { booking?: { freightType?: string | null } | null }) | null)
    ?.booking?.freightType;
  return Boolean(item?.containerId || containerCount > 0 || freightType === 'CONTAINER');
};

const initialContainerNumbers = (item: WarehouseInventoryItem | null, savedContainerNumber: string) => {
  const savedNumbers = splitContainerNumbers(savedContainerNumber);
  const itemNumbers = splitContainerNumbers(getItemContainerNumber(item));
  const sourceNumbers = savedNumbers.length ? savedNumbers : itemNumbers;
  const quantityCount = isContainerInventory(item, sourceNumbers.length) ? Number(item?.quantity ?? 0) : 0;
  const expectedCount = Math.max(1, sourceNumbers.length, quantityCount);
  return Array.from({ length: expectedCount }, (_, index) => sourceNumbers[index] ?? '');
};

const parseInspectionNote = (notes: string | null | undefined) => {
  const marker = '[Exit Inspection]';
  const index = notes?.lastIndexOf(marker) ?? -1;
  const note = index >= 0 ? notes?.slice(index + marker.length) : notes;
  return {
    truckPlateNumber: lineValue(note, 'Truck Plate'),
    trailerPlateNumber: lineValue(note, 'Trailer Plate'),
    driverName: lineValue(note, 'Driver'),
    driverLicense: lineValue(note, 'Driver License'),
    driverPhone: lineValue(note, 'Driver Phone'),
    truckType: lineValue(note, 'Truck Type'),
    containerNumber: lineValue(note, 'Container Number'),
    gateInTime: toLocalDateTimeInput(lineValue(note, 'Gate In Time')),
    tareWeight: lineNumber(note, 'Tare Weight'),
    grossWeight: lineNumber(note, 'Gross Weight'),
    netWeight: lineNumber(note, 'Net Weight'),
    gateOutTime: toLocalDateTimeInput(lineValue(note, 'Gate Out Time')),
  };
};

export function ReleaseOrderModal({ opened, onClose, item }: ReleaseOrderModalProps) {
  const { toast } = useToast();
  const releaseMutation = useMutation(api.warehouses.release.mutationOptions());
  const [reference, setReference] = useState('');
  const [truckPlateNumber, setTruckPlateNumber] = useState('');
  const [trailerPlateNumber, setTrailerPlateNumber] = useState('');
  const [driverName, setDriverName] = useState('');
  const [driverLicense, setDriverLicense] = useState('');
  const [driverPhone, setDriverPhone] = useState('');
  const [truckType, setTruckType] = useState('');
  const [containerNumbers, setContainerNumbers] = useState<string[]>(['']);
  const [gateInTime, setGateInTime] = useState('');
  const [tareWeight, setTareWeight] = useState<number | ''>('');
  const [grossWeight, setGrossWeight] = useState<number | ''>('');
  const [netWeight, setNetWeight] = useState<number | ''>('');
  const [gateOutTime, setGateOutTime] = useState('');
  const [downloading, setDownloading] = useState(false);

  useEffect(() => {
    if (opened) {
      const inspection = parseInspectionNote(item?.notes);
      setReference(item?.releaseOrderReference ?? generateReleaseReference(item));
      setTruckPlateNumber(inspection.truckPlateNumber);
      setTrailerPlateNumber(inspection.trailerPlateNumber);
      setDriverName(inspection.driverName);
      setDriverLicense(inspection.driverLicense);
      setDriverPhone(inspection.driverPhone);
      setTruckType(inspection.truckType);
      setContainerNumbers(initialContainerNumbers(item, inspection.containerNumber));
      setGateInTime(inspection.gateInTime);
      setTareWeight(inspection.tareWeight);
      setGrossWeight(inspection.grossWeight);
      setNetWeight(item?.weight == null ? inspection.netWeight : Number(item.weight));
      setGateOutTime(inspection.gateOutTime);
    }
  }, [opened, item]);

  const savedInspection = parseInspectionNote(item?.notes);
  const isExitStep = savedInspection.tareWeight !== '';
  const isEntranceLocked = isExitStep;
  const systemNetWeight = item?.weight == null ? netWeight : Number(item.weight);
  const computedNetWeight =
    tareWeight !== '' && grossWeight !== '' ? Number((Number(grossWeight) - Number(tareWeight)).toFixed(3)) : null;
  const weightMismatch =
    computedNetWeight != null && systemNetWeight !== '' && Math.abs(Number(systemNetWeight) - computedNetWeight) > 0.001;
  const title = isExitStep ? 'Customer truck leaving and exit weighing' : 'Customer truck arrival weighing';

  const handleSubmit = async () => {
    if (!item) return;
    if (!truckPlateNumber.trim() || !driverName.trim()) {
      toast({ variant: 'destructive', title: 'Truck plate and driver name are required' });
      return;
    }
    if (!gateInTime || tareWeight === '') {
      toast({ variant: 'destructive', title: 'Gate in time and tare weight are required' });
      return;
    }
    if (isExitStep && (!gateOutTime || grossWeight === '')) {
      toast({ variant: 'destructive', title: 'Gate out time and gross weight are required' });
      return;
    }
    if (isExitStep && systemNetWeight === '') {
      toast({ variant: 'destructive', title: 'System recorded net weight is missing' });
      return;
    }
    if (isExitStep && weightMismatch) {
      toast({
        variant: 'destructive',
        title: 'Weight mismatch',
        description: 'Gate clearance is blocked. Reassign the item to warehouse if it cannot exit.',
      });
      return;
    }
    const pdfWindow = isExitStep ? window.open('', '_blank') : null;
    try {
      const released = await releaseMutation.mutateAsync({
        id: item.id,
        payload: {
          reference: reference.trim() || undefined,
          bookingId: item.bookingId ?? undefined,
          customerId: undefined,
          truckPlateNumber: truckPlateNumber.trim(),
          trailerPlateNumber: trailerPlateNumber.trim() || undefined,
          driverName: driverName.trim(),
          driverLicense: driverLicense.trim() || undefined,
          driverPhone: driverPhone.trim() || undefined,
          truckType: truckType.trim() || undefined,
          containerNumber: containerNumbers.map((number) => number.trim()).filter(Boolean).join(', ') || undefined,
          gateInTime: toIsoDateTime(gateInTime),
          tareWeight: Number(tareWeight),
          grossWeight: grossWeight === '' ? undefined : Number(grossWeight),
          netWeight: isExitStep && systemNetWeight !== '' ? Number(systemNetWeight) : undefined,
          gateOutTime: isExitStep ? toIsoDateTime(gateOutTime) : undefined,
        },
      });
      if (!isExitStep) {
        toast({
          title: 'Truck arrival saved',
          description: `${released.releaseOrderReference ?? reference} is ready for exit weighing.`,
        });
        onClose();
        return;
      }
      setDownloading(true);
      const response = await warehouseService.downloadReleaseDocument(item.id);
      const blob = response.data;
      const filename = `release-${released.booking?.reference ?? released.bookingId ?? item.id}.pdf`;
      const opened = openPdfBlob(blob, filename, pdfWindow);
      toast({
        title: 'Release exit paper issued',
        description: opened
          ? 'The PDF opened in a browser tab for printing or saving.'
          : 'The browser blocked the preview tab, so the PDF was downloaded.',
      });
      onClose();
    } catch (error) {
      pdfWindow?.close();
      toast({ variant: 'destructive', title: 'Release failed', description: extractErrorMessage(error) });
    } finally {
      setDownloading(false);
    }
  };

  return (
    <Modal opened={opened} onClose={onClose} title={title} centered size="lg">
      <Stack gap="md">
        <Alert icon={<Info size={16} />} color="orange" variant="light">
          {isExitStep ? (
            <Text size="sm">
              Record the truck leaving time and gross weight. The system recorded net weight is locked,
              and the exit paper is generated only when it equals gross weight minus tare weight.
            </Text>
          ) : (
            <Text size="sm">
              Register the customer truck and driver at arrival, then save gate in time and tare weight.
              Reopen this form when the truck is leaving to complete the exit weighing.
            </Text>
          )}
        </Alert>
        <TextInput
          label="Release document reference"
          placeholder="e.g. REL-2026-001"
          value={reference}
          onChange={(e) => setReference(e.currentTarget.value)}
          readOnly={isEntranceLocked}
        />
        <Select
          label="Registered first / last-mile truck"
          placeholder="Select truck or type plate manually below"
          searchable
          clearable
          data={REGISTERED_FIRST_LAST_MILE_TRUCKS}
          disabled={isEntranceLocked}
          value={REGISTERED_FIRST_LAST_MILE_TRUCKS.some((truck) => truck.value === truckPlateNumber) ? truckPlateNumber : null}
          onChange={(value) => {
            const truck = REGISTERED_FIRST_LAST_MILE_TRUCKS.find((row) => row.value === value);
            setTruckPlateNumber(truck?.value ?? '');
            setTrailerPlateNumber(truck?.trailerPlate ?? '');
          }}
        />
        <Group grow>
          <TextInput
            label="Truck plate number"
            required
            value={truckPlateNumber}
            onChange={(e) => setTruckPlateNumber(e.currentTarget.value)}
            readOnly={isEntranceLocked}
          />
          <TextInput
            label="Trailer plate number"
            value={trailerPlateNumber}
            onChange={(e) => setTrailerPlateNumber(e.currentTarget.value)}
            readOnly={isEntranceLocked}
          />
        </Group>
        <Group grow>
          <TextInput label="Driver name" required value={driverName} onChange={(e) => setDriverName(e.currentTarget.value)} readOnly={isEntranceLocked} />
          <TextInput label="Driver license" value={driverLicense} onChange={(e) => setDriverLicense(e.currentTarget.value)} readOnly={isEntranceLocked} />
        </Group>
        <Group grow>
          <TextInput label="Driver phone" value={driverPhone} onChange={(e) => setDriverPhone(e.currentTarget.value)} readOnly={isEntranceLocked} />
          <TextInput label="Truck type" value={truckType} onChange={(e) => setTruckType(e.currentTarget.value)} readOnly={isEntranceLocked} />
        </Group>
        <Group grow>
          <Stack gap={6}>
            <SimpleGrid cols={containerNumbers.length > 1 ? 2 : 1} spacing="sm">
              {containerNumbers.map((containerNumber, index) => (
                <TextInput
                  key={index}
                  label={containerNumbers.length > 1 ? `Container number ${index + 1}` : 'Container number'}
                  value={containerNumber}
                  onChange={(e) =>
                    setContainerNumbers((numbers) =>
                      numbers.map((number, numberIndex) => (numberIndex === index ? e.currentTarget.value : number)),
                    )
                  }
                  readOnly={isEntranceLocked}
                />
              ))}
            </SimpleGrid>
          </Stack>
          <TextInput label="Gate in time" type="datetime-local" value={gateInTime} onChange={(e) => setGateInTime(e.currentTarget.value)} readOnly={isEntranceLocked} />
        </Group>
        <Group grow>
          <NumberInput label="Tare weight (kg)" required min={0} value={tareWeight} onChange={(v) => setTareWeight(v === '' ? '' : Number(v))} readOnly={isEntranceLocked} />
          <NumberInput label="Gross weight (kg)" required={isExitStep} min={0} value={grossWeight} onChange={(v) => setGrossWeight(v === '' ? '' : Number(v))} disabled={!isExitStep} />
          <NumberInput label="Recorded net weight (system kg)" min={0} value={systemNetWeight} readOnly />
        </Group>
        <Group justify="space-between">
          <Text size="sm" c={weightMismatch ? 'red' : 'dimmed'}>
            Computed net: <b>{computedNetWeight == null ? '-' : `${computedNetWeight.toLocaleString()} kg`}</b>
          </Text>
          <TextInput label="Gate out time" type="datetime-local" value={gateOutTime} onChange={(e) => setGateOutTime(e.currentTarget.value)} disabled={!isExitStep} />
        </Group>
        {weightMismatch && (
          <Alert icon={<Scale size={16} />} color="red" variant="light">
            <Text size="sm">
              Weight mismatch detected. Exit paper and gate clearance are blocked; use Store or Move to
              reassign the item back to warehouse handling.
            </Text>
          </Alert>
        )}
        <Group justify="flex-end" mt="sm">
          <Button variant="default" onClick={onClose} disabled={releaseMutation.isPending || downloading}>
            Cancel
          </Button>
          <Button color="orange" onClick={handleSubmit} loading={releaseMutation.isPending || downloading}>
            {isExitStep ? 'Save Truck Leaving & View Exit Paper' : 'Save Truck Arrival'}
          </Button>
        </Group>
      </Stack>
    </Modal>
  );
}
