"use client";

import * as React from "react";

import { useRenderEffect } from "@/hooks/use-changed";
import { toast } from "sonner";

import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { cn } from "@/lib/utils";
import { isApiSuccess } from "@/lib/api-messages";
import { isRecord, stringOrEmpty } from "@/lib/server-utils";

import type { CustomerRow } from "./schema";
import type {
  DepositCurrencyDiffPayload,
  TallyDiffPayload,
  TallyStockRow,
} from "../_lib/transaction-tally-server-api";

type CheckerTone = "ok" | "off" | "error";

function badgeClass(tone: CheckerTone) {
  if (tone === "ok") {
    return "border-emerald-200 bg-emerald-50 text-emerald-800 hover:bg-emerald-100";
  }
  if (tone === "error") {
    return "border-amber-200 bg-amber-50 text-amber-900 hover:bg-amber-100";
  }
  return "border-red-200 bg-red-50 text-red-800 hover:bg-red-100";
}

function CheckerBadge({
  label,
  title,
  tone,
  onClick,
}: {
  label: string;
  title?: string;
  tone: CheckerTone;
  onClick?: () => void;
}) {
  if (!label) return null;
  const className = cn(
    "inline-flex h-auto max-w-full whitespace-normal rounded-md border px-1.5 py-0.5 text-left text-[10px] font-semibold leading-tight",
    badgeClass(tone),
    onClick ? "cursor-pointer" : "cursor-default",
  );

  if (onClick) {
    return (
      <button type="button" className={className} title={title} onClick={onClick}>
        {label}
      </button>
    );
  }

  return (
    <span className={className} title={title}>
      {label}
    </span>
  );
}

function StockDiffTable({
  rows,
  allowTrash,
  allowApply,
  customerId: _customerId,
  onTrash,
  onApply,
  trashBusyId,
  applyBusyId,
}: {
  rows: TallyStockRow[];
  allowTrash?: boolean;
  allowApply?: boolean;
  customerId: number;
  onTrash?: (stockId: number) => void;
  onApply?: (stockId: number, tempId: number | null) => void;
  trashBusyId?: number | null;
  applyBusyId?: number | null;
}) {
  if (rows.length === 0) {
    return <p className="text-muted-foreground text-sm">None</p>;
  }

  return (
    <div className="max-h-80 overflow-auto rounded-md border">
      <table className="w-full min-w-[640px] text-left text-xs">
        <thead className="bg-muted/40 sticky top-0">
          <tr>
            <th className="px-2 py-1.5 font-medium">ID</th>
            {allowApply ? <th className="px-2 py-1.5 font-medium">Temp ID</th> : null}
            <th className="px-2 py-1.5 font-medium">UID</th>
            <th className="px-2 py-1.5 font-medium">Date</th>
            <th className="px-2 py-1.5 font-medium">Ticker</th>
            <th className="px-2 py-1.5 font-medium">ISIN</th>
            <th className="px-2 py-1.5 font-medium">Qty</th>
            <th className="px-2 py-1.5 font-medium">Type</th>
            {allowTrash || allowApply ? (
              <th className="px-2 py-1.5 font-medium">Options</th>
            ) : null}
          </tr>
        </thead>
        <tbody>
          {rows.map((row) => (
            <tr key={`${row.id ?? row.uid}-${row.tDate}`} className="border-t">
              <td className="px-2 py-1.5">{row.id ?? "—"}</td>
              {allowApply ? (
                <td className="px-2 py-1.5">{row.tempId ?? "—"}</td>
              ) : null}
              <td className="px-2 py-1.5">{row.uid || "—"}</td>
              <td className="px-2 py-1.5">{row.tDate || "—"}</td>
              <td className="px-2 py-1.5">{row.ticker || "—"}</td>
              <td className="px-2 py-1.5">{row.isin || "—"}</td>
              <td className="px-2 py-1.5">{row.quantity || "—"}</td>
              <td className="px-2 py-1.5" title={row.fType || undefined}>
                {row.fTypeLabel || row.fType || "—"}
              </td>
              {allowTrash || allowApply ? (
                <td className="px-2 py-1.5">
                  <div className="flex flex-wrap gap-1">
                    {allowApply && row.id != null && onApply ? (
                      <Button
                        type="button"
                        size="sm"
                        className="h-7 bg-emerald-600 text-xs text-white hover:bg-emerald-700"
                        disabled={applyBusyId === row.id}
                        onClick={() => onApply(row.id!, row.tempId)}
                      >
                        {applyBusyId === row.id ? "…" : "Apply"}
                      </Button>
                    ) : null}
                    {allowTrash && row.id != null && onTrash ? (
                      <Button
                        type="button"
                        size="sm"
                        variant="destructive"
                        className="h-7 text-xs"
                        disabled={trashBusyId === row.id}
                        onClick={() => onTrash(row.id!)}
                      >
                        {trashBusyId === row.id ? "…" : "Trash"}
                      </Button>
                    ) : null}
                    {!(allowApply && row.id != null && onApply) &&
                    !(allowTrash && row.id != null && onTrash)
                      ? "—"
                      : null}
                  </div>
                </td>
              ) : null}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

export function CustomerCurrencyTallyCell({
  row,
  onOpenTallyDiff,
}: {
  row: CustomerRow;
  onOpenTallyDiff: (row: CustomerRow) => void;
  onOpenDepositCurrencyDiff?: (row: CustomerRow) => void;
}) {
  const tally = row.transactionTally;

  return (
    <div className="flex min-w-[140px] flex-col gap-1.5">
      <div className="text-sm font-medium">{row.defaultCurrency || "USD"}</div>
      {tally && tally.status !== "unavailable" ? (
        <CheckerBadge
          label={tally.label}
          title={tally.title}
          tone={tally.status === "ok" ? "ok" : tally.status === "error" ? "error" : "off"}
          onClick={tally.status === "off" ? () => onOpenTallyDiff(row) : undefined}
        />
      ) : null}
    </div>
  );
}

export function CustomerTallyDiffDialog({
  open,
  customer,
  onOpenChange,
}: {
  open: boolean;
  customer: CustomerRow | null;
  onOpenChange: (open: boolean) => void;
}) {
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  const [payload, setPayload] = React.useState<TallyDiffPayload | null>(null);
  const [trashBusyId, setTrashBusyId] = React.useState<number | null>(null);

  const loadDiff = React.useCallback(async (customerId: number) => {
    setLoading(true);
    setError(null);
    try {
      const response = await fetch(
        `/dashboard/customers/transaction-tally/diff?customerId=${customerId}`,
      );
      const json = await response.json().catch(() => null);
      if (!response.ok || !isApiSuccess(json) || !isRecord(json?.data)) {
        throw new Error(
          stringOrEmpty(json?.message) || "Could not load tally differences.",
        );
      }
      setPayload(json.data as TallyDiffPayload);
    } catch (err) {
      setPayload(null);
      setError(err instanceof Error ? err.message : "Could not load tally differences.");
    } finally {
      setLoading(false);
    }
  }, []);

  React.useEffect(() => {
    if (!open || !customer) return;
    // Fetch kickoff: the loader raises its own loading flag first (fetch-in-effect).
    // eslint-disable-next-line react-hooks/set-state-in-effect
    void loadDiff(customer.id);
  }, [open, customer, loadDiff]);

  async function handleTrash(stockId: number) {
    if (!customer) return;
    if (!window.confirm("Move this corporate transaction to trash (pending-delete)?")) {
      return;
    }
    setTrashBusyId(stockId);
    try {
      const response = await fetch("/dashboard/customers/transaction-tally/trash", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ customerId: customer.id, stockId }),
      });
      const json = await response.json().catch(() => null);
      if (!response.ok || !isApiSuccess(json)) {
        throw new Error(stringOrEmpty(json?.message) || "Could not trash transaction.");
      }
      toast.success(stringOrEmpty(json?.message) || "Moved to trash.");
      await loadDiff(customer.id);
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Could not trash transaction.");
    } finally {
      setTrashBusyId(null);
    }
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-4xl">
        <DialogHeader>
          <DialogTitle>
            Transaction tally
            {customer ? ` #${customer.id}` : ""}
          </DialogTitle>
          <DialogDescription>
            Rows present only in the customer DB or only in the corporate DB.
          </DialogDescription>
        </DialogHeader>

        {loading ? (
          <p className="text-muted-foreground text-sm">Loading…</p>
        ) : error ? (
          <p className="text-destructive text-sm">{error}</p>
        ) : payload ? (
          <div className="space-y-4">
            <p className="text-sm">
              <span className="font-medium">{payload.customer.fullName || customer?.firstName}</span>
              {payload.customer.dbName ? (
                <span className="text-muted-foreground"> ({payload.customer.dbName})</span>
              ) : null}
              {payload.customer.corporateDbName ? (
                <span className="text-muted-foreground">
                  {" "}
                  vs corporate ({payload.customer.corporateDbName})
                </span>
              ) : null}
            </p>
            {payload.message ? (
              <p className="text-muted-foreground text-sm">{payload.message}</p>
            ) : null}

            <div className="space-y-2">
              <h4 className="text-sm font-semibold">
                Only in customer DB ({payload.onlyInCustomer.length})
              </h4>
              <StockDiffTable
                rows={payload.onlyInCustomer}
                customerId={customer?.id ?? 0}
              />
            </div>

            <div className="space-y-2">
              <h4 className="text-sm font-semibold">
                Only in corporate DB ({payload.onlyInCorporate.length})
              </h4>
              <StockDiffTable
                rows={payload.onlyInCorporate}
                allowTrash
                customerId={customer?.id ?? 0}
                onTrash={handleTrash}
                trashBusyId={trashBusyId}
              />
            </div>
          </div>
        ) : null}
      </DialogContent>
    </Dialog>
  );
}

export function CustomerDepositCurrencyDiffDialog({
  open,
  customer,
  onOpenChange,
}: {
  open: boolean;
  customer: CustomerRow | null;
  onOpenChange: (open: boolean) => void;
}) {
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  const [payload, setPayload] = React.useState<DepositCurrencyDiffPayload | null>(null);

  // Opening for a customer shows the loading state straight away (adjusted during render, not in an effect).
  useRenderEffect([open, customer], () => {
    if (!open || !customer) return;
    setLoading(true);
    setError(null);
  });

  React.useEffect(() => {
    if (!open || !customer) return;
    let cancelled = false;
    void (async () => {
      try {
        const response = await fetch(
          `/dashboard/customers/deposit-currency/diff?customerId=${customer.id}`,
        );
        const json = await response.json().catch(() => null);
        if (!response.ok || !isApiSuccess(json) || !isRecord(json?.data)) {
          throw new Error(
            stringOrEmpty(json?.message) || "Could not load currency mismatches.",
          );
        }
        if (!cancelled) setPayload(json.data as DepositCurrencyDiffPayload);
      } catch (err) {
        if (!cancelled) {
          setPayload(null);
          setError(
            err instanceof Error ? err.message : "Could not load currency mismatches.",
          );
        }
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [open, customer]);

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-4xl">
        <DialogHeader>
          <DialogTitle>
            Deposit currency mismatches
            {customer ? ` #${customer.id}` : ""}
          </DialogTitle>
          <DialogDescription>
            Fixed Deposit / Call Deposit sales whose currency differs from the parent placement.
          </DialogDescription>
        </DialogHeader>

        {loading ? (
          <p className="text-muted-foreground text-sm">Loading…</p>
        ) : error ? (
          <p className="text-destructive text-sm">{error}</p>
        ) : payload ? (
          <div className="space-y-3">
            <p className="text-sm">
              <span className="font-medium">{payload.customer.fullName || customer?.firstName}</span>
              {payload.customer.dbName ? (
                <span className="text-muted-foreground"> ({payload.customer.dbName})</span>
              ) : null}
            </p>
            {payload.rows.length === 0 ? (
              <p className="text-muted-foreground text-sm">
                {payload.message || "No currency mismatches found."}
              </p>
            ) : (
              <div className="max-h-80 overflow-auto rounded-md border">
                <table className="w-full min-w-[720px] text-left text-xs">
                  <thead className="bg-muted/40 sticky top-0">
                    <tr>
                      <th className="px-2 py-1.5 font-medium">Sale ID</th>
                      <th className="px-2 py-1.5 font-medium">UID</th>
                      <th className="px-2 py-1.5 font-medium">Date</th>
                      <th className="px-2 py-1.5 font-medium">Ticker</th>
                      <th className="px-2 py-1.5 font-medium">Type</th>
                      <th className="px-2 py-1.5 font-medium">Sale Currency</th>
                      <th className="px-2 py-1.5 font-medium">Parent ID</th>
                      <th className="px-2 py-1.5 font-medium">Parent Currency</th>
                    </tr>
                  </thead>
                  <tbody>
                    {payload.rows.map((row) => (
                      <tr key={`${row.id}-${row.parentId}`} className="border-t">
                        <td className="px-2 py-1.5">{row.id ?? "—"}</td>
                        <td className="px-2 py-1.5">{row.uid || "—"}</td>
                        <td className="px-2 py-1.5">{row.tDate || "—"}</td>
                        <td className="px-2 py-1.5">{row.ticker || "—"}</td>
                        <td className="px-2 py-1.5">{row.fTypeLabel || "—"}</td>
                        <td className="px-2 py-1.5">{row.saleCurrencyCode || "—"}</td>
                        <td className="px-2 py-1.5">{row.parentId ?? "—"}</td>
                        <td className="px-2 py-1.5">{row.parentCurrencyCode || "—"}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
          </div>
        ) : null}
      </DialogContent>
    </Dialog>
  );
}
