import { useState } from 'react';
import { Badge, Button, Card, Divider, Group, Loader, Modal, SegmentedControl, Stack, Text } from '@mantine/core';
import { CalendarClock, Coins, DoorOpen, FileText } from 'lucide-react';

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

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

const INVOICE_STATUS_COLOR: Record<WarehouseInvoiceStatus, string> = {
  DRAFT: 'gray',
  ISSUED: 'orange',
  PARTIALLY_PAID: 'yellow',
  PAID: 'edr-green',
  CANCELLED: 'gray',
};

interface FeePreviewModalProps {
  opened: boolean;
  onClose: () => void;
  inventoryId: string | null;
}

const LABELS: Record<string, { label: string; color: string }> = {
  DEMURRAGE_FEE: { label: 'Demurrage', color: 'orange' },
  STORAGE_FEE: { label: 'Storage', color: 'teal' },
  DOUBLE_HANDLING_FEE: { label: 'Double Handling', color: 'grape' },
  TRUCK_DETENTION_FEE: { label: 'Truck Detention Cost', color: 'blue' },
};

function fmtDate(iso: string | null) {
  if (!iso) return '—';
  return new Date(iso).toLocaleDateString();
}

const UNIT_LABEL_PLURAL: Record<string, string> = {
  container: 'Containers',
  truck: 'Trucks',
  ton: 'Tons',
  item: 'Items',
};
const unitLabelPlural = (unitLabel?: string) => UNIT_LABEL_PLURAL[unitLabel ?? 'container'] ?? 'Containers';

const money = (amount: number, currency: string) =>
  `${Number(amount).toLocaleString()} ${currency === 'ETB' ? 'Birr (ETB)' : currency}`;

function FeeCard({ fee }: { fee: FeePreview }) {
  const meta = LABELS[fee.ruleType] ?? { label: fee.ruleType, color: 'gray' };
  const configured = Boolean(fee.ruleId);
  return (
    <Card withBorder radius="md" padding="md" style={{ borderColor: `var(--mantine-color-${meta.color}-3)` }}>
      <Group justify="space-between" mb="xs">
        <Group gap="xs">
          <Coins size={16} />
          <Text fw={700}>{meta.label}</Text>
          {fee.endIsOpen && (
            <Badge size="xs" color={meta.color} variant="light">
              accruing
            </Badge>
          )}
        </Group>
        <Text fw={800} size="lg" c={`${meta.color}.7`}>
          {money(fee.amount, fee.currency)}
        </Text>
      </Group>

      {!configured ? (
        <Text size="xs" c="dimmed">
          No active {meta.label.toLowerCase()} rule configured — amount shown as 0.
        </Text>
      ) : (
        <Stack gap={4}>
          <Row label="Rule" value={fee.ruleName ?? '—'} />
          <Row label="Free days" value={String(fee.freeDays)} />
          <Row label="Rate / day" value={money(fee.ratePerDay, fee.currency)} />
          <Row label="Period" value={`${fmtDate(fee.startDate)} → ${fmtDate(fee.endDate)}${fee.endIsOpen ? ' (today)' : ''}`} />
          <Row label="Elapsed days" value={String(fee.elapsedDays)} />
          <Row label="Chargeable days" value={`${fee.chargeableDays} (after ${fee.freeDays} free)`} />
          <Row label={unitLabelPlural(fee.unitLabel)} value={String(fee.containerCount ?? 1)} />
          <Row
            label="Billable units"
            value={`${fee.billableUnits ?? fee.chargeableDays} ${fee.unitLabel ?? 'container'}-day(s)`}
          />
          {(fee.tiers ?? []).map((tier) => (
            <Row
              key={`${tier.appliedFromDay}-${tier.appliedToDay}-${tier.ratePerDay}`}
              label={`Days ${tier.appliedFromDay}-${tier.appliedToDay}`}
              value={`${tier.days} x ${money(tier.ratePerDay, fee.currency)} = ${money(tier.amount, fee.currency)}`}
            />
          ))}
        </Stack>
      )}
    </Card>
  );
}

function Row({ label, value }: { label: string; value: string }) {
  return (
    <Group justify="space-between" wrap="nowrap">
      <Text size="xs" c="dimmed">
        {label}
      </Text>
      <Text size="sm">{value}</Text>
    </Group>
  );
}

/** Batch 5 fee preview + Batch 6 invoice generation / gate clearance for an inventory item. */
export function FeePreviewModal({ opened, onClose, inventoryId }: FeePreviewModalProps) {
  const { toast } = useToast();
  const [billingCurrency, setBillingCurrency] = useState<'ETB' | 'USD'>('USD');
  const enabledId = opened ? inventoryId ?? undefined : undefined;
  const { data, isLoading } = useQuery(
    api.warehouses.feePreview.queryOptions({
      input: { inventoryId: enabledId ?? '', billingCurrency },
      enabled: Boolean(enabledId),
    }),
  );
  const { data: invoices } = useQuery(
    api.warehouses.invoicesForInventory.queryOptions({
      input: { inventoryId: enabledId ?? '' },
      enabled: Boolean(enabledId),
    }),
  );
  const generate = useMutation(api.warehouses.generateInvoice.mutationOptions());
  const gateClear = useMutation(api.warehouses.gateClearance.mutationOptions());

  const activeInvoice = (invoices ?? []).find((i) => i.status !== 'CANCELLED');
  const totalPreviewAmount = (data ?? []).reduce((sum, fee) => sum + Number(fee.amount || 0), 0);

  const handleGenerate = async () => {
    if (!inventoryId) return;
    if (totalPreviewAmount <= 0) {
      toast({
        title: 'No fee to invoice',
        description: 'The item is still within the configured free days, or no active fee rule matched it.',
      });
      return;
    }
    try {
      const inv = await generate.mutateAsync({ inventoryId, billingCurrency });
      toast({ title: 'Invoice generated', description: `${inv.invoiceNumber} - ${money(inv.totalAmount, inv.currency)}` });
    } catch (error) {
      toast({ variant: 'destructive', title: 'Generate failed', description: extractErrorMessage(error) });
    }
  };

  const handleGateClearance = async () => {
    if (!inventoryId) return;
    const pdfWindow = window.open('', '_blank');
    try {
      const releasedItem = await gateClear.mutateAsync(inventoryId) as WarehouseInventoryItem;
      try {
        const documentResponse = await warehouseService.downloadReleaseDocument(inventoryId);
        const filename = `release-${releasedItem?.booking?.reference ?? releasedItem?.bookingId ?? inventoryId}.pdf`;
        const opened = openPdfBlob(documentResponse.data, filename, pdfWindow);
        toast({
          title: 'Gate clearance recorded',
          description: opened
            ? 'The release PDF opened in a browser tab.'
            : 'The browser blocked the preview tab, so the PDF was downloaded.',
        });
      } catch (documentError) {
        pdfWindow?.close();
        toast({
          title: 'Gate clearance recorded',
          description: `Release paper could not be opened: ${await extractDownloadErrorMessage(documentError)}`,
        });
      }
      onClose();
    } catch (error) {
      pdfWindow?.close();
      toast({ variant: 'destructive', title: 'Release blocked', description: extractErrorMessage(error) });
    }
  };

  return (
    <Modal
      opened={opened}
      onClose={onClose}
      title={
        <Group gap="xs">
          <CalendarClock size={18} />
          <Text fw={700}>Storage &amp; Demurrage Preview</Text>
        </Group>
      }
      centered
      size="md"
    >
      {isLoading ? (
        <Group justify="center" py="xl">
          <Loader />
        </Group>
      ) : (
        <Stack gap="md">
          {(data ?? []).map((fee) => (
            <FeeCard key={fee.ruleType} fee={fee} />
          ))}

          <Divider label="Invoice & Release" labelPosition="left" />

          <Group justify="space-between" align="center">
            <Text size="sm" fw={600}>
              Billing currency
            </Text>
            <SegmentedControl
              size="xs"
              value={billingCurrency}
              onChange={(value) => setBillingCurrency(value as 'ETB' | 'USD')}
              data={[
                { value: 'USD', label: 'USD' },
                { value: 'ETB', label: 'Birr' },
              ]}
              disabled={Boolean(activeInvoice)}
            />
          </Group>

          {activeInvoice ? (
            <Group justify="space-between">
              <Group gap="xs">
                <FileText size={16} />
                <Text size="sm" fw={600}>{activeInvoice.invoiceNumber}</Text>
                <Badge variant="light" color={INVOICE_STATUS_COLOR[activeInvoice.status]}>
                  {activeInvoice.status.replace(/_/g, ' ')}
                </Badge>
              </Group>
              <Text size="sm">
                {money(Number(activeInvoice.balanceAmount), activeInvoice.currency)} due
              </Text>
            </Group>
          ) : (
            <Button
              variant="light"
              color="orange"
              leftSection={<FileText size={16} />}
              loading={generate.isPending}
              onClick={handleGenerate}
            >
              Generate Fee Invoice
            </Button>
          )}

          <Button
            variant="light"
            color="edr-green"
            leftSection={<DoorOpen size={16} />}
            loading={gateClear.isPending}
            onClick={handleGateClearance}
          >
            Gate Clearance / Release
          </Button>

          <Text size="xs" c="dimmed">
            Charges accrue from arrival until gate clearance / release. Final release is blocked while a
            demurrage/storage invoice is unpaid.
          </Text>
        </Stack>
      )}
    </Modal>
  );
}
