import { useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  Badge,
  Box,
  Button,
  FileButton,
  Group,
  Loader,
  Modal,
  NumberInput,
  Paper,
  Select,
  Stack,
  Text,
  Textarea,
  Tooltip,
} from "@mantine/core";
import { DateInput } from "@mantine/dates";
import {
  Ban,
  Download,
  Eye,
  FileText,
  Plus,
  Receipt,
  Send,
  Upload,
} from "lucide-react";
import toast from "react-hot-toast";
import type { Freight } from "@edr/types";
import { isViewable } from "@edr/ui-common";

import { bookingsService } from "@/services/bookings.service";
import { downloadBookingFile, fetchViewableFile } from "@/services/files.service";
import { formatDate, formatDateTime } from "@/lib/format";
import { extractErrorMessage } from "@/utils/errorExtractor";

const CURRENCIES = ["ETB", "USD", "DJF"];

const STATUS_META: Record<Freight.AdditionalChargeStatus, { label: string; color: string }> = {
  DRAFT: { label: "Draft", color: "gray" },
  SENT: { label: "Sent — unpaid", color: "orange" },
  PAID: { label: "Paid", color: "edr-green" },
  CANCELLED: { label: "Cancelled", color: "red" },
};

export interface AdditionalPaymentsTabProps {
  bookingId: string;
  onViewFile: (file: { name: string; url: string }) => void;
}

/**
 * Ad-hoc extra charges finance raises against a booking — any number, free-text
 * reason. Draft until sent; sending issues the payable invoice and notifies the
 * customer (in-app + SMS + email). Settles the same way every invoice does.
 */
export function AdditionalPaymentsTab({ bookingId, onViewFile }: AdditionalPaymentsTabProps) {
  const qc = useQueryClient();
  const [modalOpen, setModalOpen] = useState(false);

  const { data: charges, isLoading } = useQuery({
    queryKey: ["additional-charges", bookingId],
    queryFn: () => bookingsService.getAdditionalCharges(bookingId),
  });

  const refresh = (next: Freight.AdditionalCharge[]) =>
    qc.setQueryData(["additional-charges", bookingId], next);
  const onError = (e: unknown) =>
    toast.error(extractErrorMessage(e, "Could not update the charge"));

  const create = useMutation({
    mutationFn: (p: {
      reason: string;
      amount: number;
      currency: string;
      action: "draft" | "send";
      file?: File | null;
      dueDate?: string | null;
    }) => bookingsService.createAdditionalCharge(bookingId, p),
    onSuccess: (next, p) => {
      toast.success(p.action === "send" ? "Charge sent to the customer" : "Draft saved");
      refresh(next);
      setModalOpen(false);
    },
    onError,
  });
  const send = useMutation({
    mutationFn: (chargeId: string) => bookingsService.sendAdditionalCharge(bookingId, chargeId),
    onSuccess: (next) => {
      toast.success("Charge sent to the customer");
      refresh(next);
    },
    onError,
  });
  const cancel = useMutation({
    mutationFn: (chargeId: string) => bookingsService.cancelAdditionalCharge(bookingId, chargeId),
    onSuccess: (next) => {
      toast.success("Charge cancelled");
      refresh(next);
    },
    onError,
  });

  if (isLoading) {
    return (
      <Group justify="center" py="xl" gap={10}>
        <Loader size="sm" color="edr-green" />
        <Text c="dimmed">Loading additional charges…</Text>
      </Group>
    );
  }

  const rows = charges ?? [];
  const busy = send.isPending || cancel.isPending;

  return (
    <Stack gap="md" maw={860}>
      <Group justify="space-between">
        <Text fz="13px" fw={700} c="edr-text">
          Additional charges
        </Text>
        <Button
          size="compact-sm"
          color="edr-green"
          radius="md"
          leftSection={<Plus size={14} />}
          onClick={() => setModalOpen(true)}
        >
          Add charge
        </Button>
      </Group>

      {rows.length === 0 && (
        <Text fz="12.5px" c="dimmed">
          No additional charges raised on this booking yet.
        </Text>
      )}

      {rows.map((charge) => (
        <ChargeCard
          key={charge.id}
          charge={charge}
          busy={busy}
          onViewFile={onViewFile}
          onSend={() => send.mutate(charge.id)}
          onCancel={() => cancel.mutate(charge.id)}
        />
      ))}

      <AddChargeModal
        opened={modalOpen}
        onClose={() => setModalOpen(false)}
        busy={create.isPending}
        onSubmit={(p) => create.mutate(p)}
      />
    </Stack>
  );
}

function ChargeCard({
  charge,
  busy,
  onViewFile,
  onSend,
  onCancel,
}: {
  charge: Freight.AdditionalCharge;
  busy: boolean;
  onViewFile: (file: { name: string; url: string }) => void;
  onSend: () => void;
  onCancel: () => void;
}) {
  const meta = STATUS_META[charge.status];

  return (
    <Paper withBorder radius="md" p="md">
      <Group justify="space-between" wrap="nowrap" align="flex-start">
        <Group gap={10} wrap="nowrap" align="flex-start">
          <Receipt size={18} color="var(--mantine-color-edr-green-6)" />
          <Box>
            <Text fz="14px" fw={700} c="edr-text">
              {charge.reason}
            </Text>
            <Text fz="11.5px" c="dimmed">
              Raised{charge.createdByName ? ` by ${charge.createdByName}` : ""} ·{" "}
              {formatDateTime(charge.createdAt)}
            </Text>
            {charge.sentAt && (
              <Text fz="11.5px" c="dimmed">
                Sent{charge.sentByName ? ` by ${charge.sentByName}` : ""} ·{" "}
                {formatDateTime(charge.sentAt)}
                {charge.paymentReference ? ` · ref ${charge.paymentReference}` : ""}
              </Text>
            )}
            {charge.paidAt && (
              <Text fz="11.5px" c="edr-green.8" fw={600}>
                Paid · {formatDateTime(charge.paidAt)}
                {charge.invoiceNumber ? ` (invoice ${charge.invoiceNumber})` : ""}
              </Text>
            )}
            {charge.cancelledAt && (
              <Text fz="11.5px" c="red.7">
                Cancelled · {formatDateTime(charge.cancelledAt)}
                {charge.cancelReason ? ` — ${charge.cancelReason}` : ""}
              </Text>
            )}
            {charge.dueAt && charge.status !== "PAID" && charge.status !== "CANCELLED" && (
              <Text fz="11.5px" c="dimmed">
                Due {formatDate(charge.dueAt)}
              </Text>
            )}
          </Box>
        </Group>
        <Group gap={8} wrap="nowrap" align="flex-end" style={{ flexDirection: "column" }}>
          <Group gap={8} wrap="nowrap">
            <Text fz="14px" fw={800} c="edr-text">
              {charge.amount.toLocaleString(undefined, { minimumFractionDigits: 2 })}{" "}
              {charge.currency}
            </Text>
            <Badge variant="light" color={meta.color} radius="sm">
              {meta.label}
            </Badge>
          </Group>
          {charge.convertedAmount != null && (
            <Text fz="11.5px" c="dimmed">
              ≈ {charge.convertedAmount.toLocaleString(undefined, { minimumFractionDigits: 2 })}{" "}
              {charge.convertedCurrency}
            </Text>
          )}
        </Group>
      </Group>

      {charge.file && (
        <Group gap={8} mt="sm" wrap="nowrap">
          <FileText size={15} color="var(--mantine-color-edr-green-6)" />
          <Text fz="12.5px" c="edr-text" truncate style={{ minWidth: 0 }}>
            {charge.file.name}
          </Text>
          {isViewable({ name: charge.file.name, url: "" }) && (
            <Tooltip label="View">
              <Box
                component="button"
                type="button"
                onClick={() =>
                  void fetchViewableFile(charge.file!.id, charge.file!.name).then(onViewFile)
                }
                c="edr-green"
                style={{ display: "flex", background: "transparent", border: "none", cursor: "pointer" }}
              >
                <Eye size={15} />
              </Box>
            </Tooltip>
          )}
          <Tooltip label="Download">
            <Box
              component="button"
              type="button"
              onClick={() => void downloadBookingFile(charge.file!.id, charge.file!.name)}
              c="edr-green"
              style={{ display: "flex", background: "transparent", border: "none", cursor: "pointer" }}
            >
              <Download size={15} />
            </Box>
          </Tooltip>
        </Group>
      )}

      {(charge.status === "DRAFT" || charge.status === "SENT") && (
        <Group mt="sm" gap={8} justify="flex-end">
          <Button
            size="compact-sm"
            variant="light"
            color="red"
            radius="md"
            leftSection={<Ban size={14} />}
            disabled={busy}
            onClick={onCancel}
          >
            Cancel
          </Button>
          {charge.status === "DRAFT" && (
            <Button
              size="compact-sm"
              color="edr-green"
              radius="md"
              leftSection={<Send size={14} />}
              disabled={busy}
              onClick={onSend}
            >
              Send to customer
            </Button>
          )}
        </Group>
      )}
    </Paper>
  );
}

function AddChargeModal({
  opened,
  onClose,
  busy,
  onSubmit,
}: {
  opened: boolean;
  onClose: () => void;
  busy: boolean;
  onSubmit: (p: {
    reason: string;
    amount: number;
    currency: string;
    action: "draft" | "send";
    file?: File | null;
    dueDate?: string | null;
  }) => void;
}) {
  const [reason, setReason] = useState("");
  const [amount, setAmount] = useState<number | string>("");
  const [currency, setCurrency] = useState("ETB");
  const [file, setFile] = useState<File | null>(null);
  const [dueDate, setDueDate] = useState<Date | null>(null);

  const valid = reason.trim().length > 0 && Number(amount) > 0;

  const reset = () => {
    setReason("");
    setAmount("");
    setCurrency("ETB");
    setFile(null);
    setDueDate(null);
  };

  const submit = (action: "draft" | "send") => {
    if (!valid) return;
    onSubmit({
      reason: reason.trim(),
      amount: Number(amount),
      currency,
      action,
      file,
      // Local calendar date, not a UTC-shifted ISO timestamp — toISOString() can
      // roll the date back a day for evening local time in a positive-offset zone.
      dueDate: dueDate
        ? `${dueDate.getFullYear()}-${String(dueDate.getMonth() + 1).padStart(2, "0")}-${String(dueDate.getDate()).padStart(2, "0")}`
        : null,
    });
  };

  return (
    <Modal
      opened={opened}
      onClose={() => {
        onClose();
        reset();
      }}
      title="Add additional charge"
      radius="md"
      centered
    >
      <Stack gap="sm">
        <Textarea
          label="Reason for charge"
          placeholder="e.g. Re-weighing fee at Mojo dry port"
          autosize
          minRows={2}
          value={reason}
          onChange={(e) => setReason(e.currentTarget.value)}
        />
        <Group gap={8} align="flex-end">
          <NumberInput
            label="Amount"
            min={0.01}
            decimalScale={2}
            value={amount}
            onChange={setAmount}
            style={{ flex: 1 }}
          />
          <Select
            label="Currency"
            data={CURRENCIES}
            value={currency}
            onChange={(v) => v && setCurrency(v)}
            w={100}
          />
        </Group>
        <DateInput
          label="Due date"
          placeholder="Defaults to 14 days after sending"
          value={dueDate}
          onChange={(v) => setDueDate(v ? new Date(v) : null)}
          minDate={new Date()}
          clearable
        />
        <FileButton onChange={setFile} accept="application/pdf,image/*">
          {(props) => (
            <Button
              {...props}
              variant="light"
              color="edr-green"
              radius="md"
              leftSection={<Upload size={14} />}
            >
              {file ? file.name : "Attach a document (optional)"}
            </Button>
          )}
        </FileButton>

        <Group justify="flex-end" mt="sm" gap={8}>
          <Button
            variant="light"
            color="gray"
            radius="md"
            disabled={busy || !valid}
            loading={busy}
            onClick={() => submit("draft")}
          >
            Save draft
          </Button>
          <Button
            color="edr-green"
            radius="md"
            leftSection={<Send size={14} />}
            disabled={busy || !valid}
            loading={busy}
            onClick={() => submit("send")}
          >
            Send to customer
          </Button>
        </Group>
      </Stack>
    </Modal>
  );
}
