"use client";

import { useState, Fragment } from "react";
import { useRouter } from "@/i18n/navigation";
import { useTranslations } from "next-intl";
import { Card, CardHeader } from "@/components/ui/card";
import type { CreditNote, InvoiceDetail, InvoiceStatus } from "@/types";

interface Props {
  detail: InvoiceDetail;
  /**
   * Phase 7: credit notes linked to this invoice (voids + refunds).
   * Empty array when none. Passed from the server page; client
   * doesn't re-fetch — router.refresh() rebuilds after actions.
   */
  creditNotes?: CreditNote[];
}

/**
 * Renders the invoice header (status, totals, action bar) then
 * line items grouped by tenant, then billing snapshot. Actions are
 * mark-paid (POST), void (POST), refund (POST), delete (DELETE),
 * PDF download (link to /pdf).
 *
 * Phase 7 adds void + refund. The action bar shows:
 *   - status open/overdue → Mark paid, Void, Delete
 *   - status paid          → Refund, Delete
 *   - status partially_refunded → Refund (for remainder), Delete
 *   - status fully_refunded / void → Delete only (read-only otherwise)
 *
 * On successful action we router.refresh() — the server-side page
 * re-renders against the new DB state, including any new credit
 * notes.
 */
export function InvoiceDetailView({ detail, creditNotes = [] }: Props) {
  const t = useTranslations("adminBilling");
  const router = useRouter();
  const { invoice, lines } = detail;

  const [busyAction, setBusyAction] = useState<
    null | "mark-paid" | "delete" | "void" | "refund"
  >(null);
  const [actionError, setActionError] = useState("");
  const [noteInput, setNoteInput] = useState("");
  const [noteOpen, setNoteOpen] = useState(false);

  // Phase 7 — void modal state
  const [voidOpen, setVoidOpen] = useState(false);
  const [voidReason, setVoidReason] = useState("");

  // Phase 7 — refund modal state. Amount defaults to the full
  // remaining refundable on open.
  const [refundOpen, setRefundOpen] = useState(false);
  const [refundAmount, setRefundAmount] = useState("");
  const [refundReason, setRefundReason] = useState("");

  const remainingRefundable =
    Math.round(
      (invoice.totalChf - invoice.refundedTotalChf) * 100
    ) / 100;

  const markPaid = async () => {
    setActionError("");
    setBusyAction("mark-paid");
    try {
      const res = await fetch(
        `/api/admin/billing/invoices/${invoice.id}/mark-paid`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ note: noteInput || undefined }),
        }
      );
      const j = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(j.error || `HTTP ${res.status}`);
      setNoteOpen(false);
      setNoteInput("");
      router.refresh();
    } catch (e: any) {
      setActionError(e.message);
    } finally {
      setBusyAction(null);
    }
  };

  const deleteInvoice = async () => {
    if (!confirm(t("confirmDeleteInvoice", { num: invoice.invoiceNumber })))
      return;
    setActionError("");
    setBusyAction("delete");
    try {
      const res = await fetch(`/api/admin/billing/invoices/${invoice.id}`, {
        method: "DELETE",
      });
      if (!res.ok) {
        const j = await res.json().catch(() => ({}));
        throw new Error(j.error || `HTTP ${res.status}`);
      }
      router.push("/admin/billing/invoices");
    } catch (e: any) {
      setActionError(e.message);
      setBusyAction(null);
    }
  };

  // Phase 7 — void: marks an unpaid invoice as cancelled and issues
  // a credit note. Backend rejects if the invoice is paid (use
  // refund) or already voided/refunded.
  const voidInvoice = async () => {
    if (!voidReason.trim()) {
      setActionError(t("voidReasonRequired"));
      return;
    }
    setActionError("");
    setBusyAction("void");
    try {
      const res = await fetch(
        `/api/admin/billing/invoices/${invoice.id}/void`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ reason: voidReason }),
        }
      );
      const j = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(j.error || `HTTP ${res.status}`);
      setVoidOpen(false);
      setVoidReason("");
      router.refresh();
    } catch (e: any) {
      setActionError(e.message);
    } finally {
      setBusyAction(null);
    }
  };

  // Phase 7 — refund: paid invoices only. Amount may be partial;
  // backend caps at remaining refundable.
  const refundInvoice = async () => {
    const amt = parseFloat(refundAmount);
    if (!isFinite(amt) || amt <= 0) {
      setActionError(t("refundAmountInvalid"));
      return;
    }
    if (amt - remainingRefundable > 0.005) {
      setActionError(
        t("refundAmountExceeds", {
          max: remainingRefundable.toFixed(2),
        })
      );
      return;
    }
    if (!refundReason.trim()) {
      setActionError(t("refundReasonRequired"));
      return;
    }
    setActionError("");
    setBusyAction("refund");
    try {
      const res = await fetch(
        `/api/admin/billing/invoices/${invoice.id}/refund`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            amountChf: Math.round(amt * 100) / 100,
            reason: refundReason,
          }),
        }
      );
      const j = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(j.error || `HTTP ${res.status}`);
      setRefundOpen(false);
      setRefundAmount("");
      setRefundReason("");
      router.refresh();
    } catch (e: any) {
      setActionError(e.message);
    } finally {
      setBusyAction(null);
    }
  };

  // Group lines by tenant for display (matches PDF layout).
  const linesByTenant = new Map<string | null, typeof lines>();
  for (const ln of lines) {
    const k = ln.tenantName;
    if (!linesByTenant.has(k)) linesByTenant.set(k, []);
    linesByTenant.get(k)!.push(ln);
  }
  const tenantOrder = [...linesByTenant.keys()].sort((a, b) => {
    if (a === null) return 1;
    if (b === null) return -1;
    return a.localeCompare(b);
  });

  return (
    <div className="space-y-4 animate-in">
      <div className="flex items-end justify-between flex-wrap gap-3">
        <div>
          <h1 className="font-display text-2xl font-semibold accent-rule">
            {invoice.invoiceNumber}
          </h1>
          <div className="flex items-center gap-3 mt-3 text-sm">
            <StatusPill status={invoice.status} />
            {invoice.periodStart && invoice.periodEnd && (
              <>
                <span className="text-text-muted">
                  {invoice.periodStart} → {invoice.periodEnd}
                </span>
                <span className="text-text-muted">·</span>
              </>
            )}
            <span className="text-text-muted">
              {t("dueOnLabel")}: {invoice.dueAt}
            </span>
            <span className="text-text-muted">·</span>
            <span className="text-text-muted font-mono text-xs">
              {invoice.locale}
            </span>
          </div>
        </div>
        <div className="text-right">
          <div className="text-xs text-text-muted">{t("totalLabel")}</div>
          <div className="text-2xl font-semibold font-mono">
            CHF {invoice.totalChf.toFixed(2)}
          </div>
        </div>
      </div>

      {/* Action bar */}
      <Card>
        <div className="flex flex-wrap items-center gap-3">
          {invoice.hasPdf && (
            <a
              href={`/api/admin/billing/invoices/${invoice.id}/pdf`}
              target="_blank"
              rel="noopener noreferrer"
              className="px-4 py-2 rounded-md border border-border text-sm hover:bg-surface-2"
            >
              {t("downloadPdfBtn")}
            </a>
          )}
          {(invoice.status === "open" || invoice.status === "overdue") && (
            <>
              {!noteOpen ? (
                <button
                  onClick={() => setNoteOpen(true)}
                  disabled={busyAction !== null}
                  className="px-4 py-2 rounded-md bg-accent text-surface-0 text-sm disabled:opacity-50"
                >
                  {t("markPaidBtn")}
                </button>
              ) : (
                <div className="flex items-center gap-2 flex-grow">
                  <input
                    type="text"
                    placeholder={t("paidNotePlaceholder")}
                    value={noteInput}
                    onChange={(e) => setNoteInput(e.target.value)}
                    className="flex-grow px-3 py-1.5 rounded-md border border-border bg-surface-2 text-sm"
                    autoFocus
                  />
                  <button
                    onClick={markPaid}
                    disabled={busyAction !== null}
                    className="px-3 py-1.5 rounded-md bg-accent text-surface-0 text-sm disabled:opacity-50"
                  >
                    {busyAction === "mark-paid" ? t("saving") : t("confirm")}
                  </button>
                  <button
                    onClick={() => {
                      setNoteOpen(false);
                      setNoteInput("");
                    }}
                    className="px-3 py-1.5 rounded-md border border-border text-sm"
                  >
                    {t("cancel")}
                  </button>
                </div>
              )}
            </>
          )}
          {/* Phase 7 — Void: visible only for open/overdue invoices.
              Same gating as Mark Paid but mutually exclusive with it
              via the chosen action. Opens a small inline form so
              the admin can enter a reason; reason is required and
              lands on the credit-note PDF. */}
          {(invoice.status === "open" || invoice.status === "overdue") && (
            <>
              {!voidOpen ? (
                <button
                  onClick={() => {
                    setVoidOpen(true);
                    setNoteOpen(false);
                    setRefundOpen(false);
                  }}
                  disabled={busyAction !== null}
                  className="px-4 py-2 rounded-md border border-error text-error text-sm disabled:opacity-50 hover:bg-error/10"
                >
                  {t("voidBtn")}
                </button>
              ) : (
                <div className="flex items-center gap-2 flex-grow">
                  <input
                    type="text"
                    placeholder={t("voidReasonPlaceholder")}
                    value={voidReason}
                    onChange={(e) => setVoidReason(e.target.value)}
                    maxLength={500}
                    className="flex-grow px-3 py-1.5 rounded-md border border-border bg-surface-2 text-sm"
                    autoFocus
                  />
                  <button
                    onClick={voidInvoice}
                    disabled={busyAction !== null}
                    className="px-3 py-1.5 rounded-md bg-error text-white text-sm disabled:opacity-50"
                  >
                    {busyAction === "void" ? t("saving") : t("confirmVoid")}
                  </button>
                  <button
                    onClick={() => {
                      setVoidOpen(false);
                      setVoidReason("");
                    }}
                    className="px-3 py-1.5 rounded-md border border-border text-sm"
                  >
                    {t("cancel")}
                  </button>
                </div>
              )}
            </>
          )}
          {/* Phase 7 — Refund: paid invoices, including ones already
              partially refunded (as long as some refundable amount
              remains). Opens an inline form with amount + reason.
              The remaining-refundable hint helps admin pick the
              right number. */}
          {(invoice.status === "paid" ||
            invoice.status === "partially_refunded") &&
            remainingRefundable > 0 && (
              <>
                {!refundOpen ? (
                  <button
                    onClick={() => {
                      setRefundOpen(true);
                      setNoteOpen(false);
                      setVoidOpen(false);
                      setRefundAmount(remainingRefundable.toFixed(2));
                    }}
                    disabled={busyAction !== null}
                    className="px-4 py-2 rounded-md border border-error text-error text-sm disabled:opacity-50 hover:bg-error/10"
                  >
                    {t("refundBtn")}
                  </button>
                ) : (
                  <div className="flex flex-col gap-2 flex-grow">
                    <div className="text-xs text-text-muted">
                      {t("refundRemainingHint", {
                        max: remainingRefundable.toFixed(2),
                      })}
                    </div>
                    <div className="flex items-center gap-4 flex-wrap">
                      <div className="flex flex-col gap-1">
                        <label className="text-[10px] uppercase tracking-wider text-text-muted">
                          {t("refundAmountLabel")}
                        </label>
                        <input
                          type="number"
                          step="0.01"
                          min="0.01"
                          max={remainingRefundable}
                          placeholder="CHF"
                          value={refundAmount}
                          onChange={(e) => setRefundAmount(e.target.value)}
                          className="w-32 px-3 py-1.5 rounded-md border border-border bg-surface-2 text-sm font-mono"
                          autoFocus
                        />
                        <span className="text-[10px] text-text-muted italic">
                          {t("refundAmountInclVatHint")}
                        </span>
                      </div>
                      <div className="flex flex-col gap-1 flex-grow min-w-[200px]">
                        <label className="text-[10px] uppercase tracking-wider text-text-muted">
                          {t("refundReasonLabel")}
                        </label>
                        <input
                          type="text"
                          placeholder={t("refundReasonPlaceholder")}
                          value={refundReason}
                          onChange={(e) => setRefundReason(e.target.value)}
                          maxLength={500}
                          className="w-full px-3 py-1.5 rounded-md border border-border bg-surface-2 text-sm"
                        />
                      </div>
                      <div className="flex items-center gap-2 self-end">
                        <button
                          onClick={refundInvoice}
                          disabled={busyAction !== null}
                          className="px-3 py-1.5 rounded-md bg-error text-white text-sm disabled:opacity-50"
                        >
                          {busyAction === "refund"
                            ? t("saving")
                            : t("confirmRefund")}
                        </button>
                        <button
                          onClick={() => {
                            setRefundOpen(false);
                            setRefundAmount("");
                            setRefundReason("");
                          }}
                          className="px-3 py-1.5 rounded-md border border-border text-sm"
                        >
                          {t("cancel")}
                        </button>
                      </div>
                    </div>
                  </div>
                )}
              </>
            )}
          <button
            onClick={deleteInvoice}
            disabled={busyAction !== null}
            className="ml-auto px-4 py-2 rounded-md border border-error text-error text-sm disabled:opacity-50 hover:bg-error/10"
            title={t("deleteHint")}
          >
            {busyAction === "delete" ? t("deleting") : t("deleteBtn")}
          </button>
        </div>
        {actionError && (
          <div className="mt-3 text-sm text-error">{actionError}</div>
        )}
        {invoice.paidAt && (
          <div className="mt-3 text-xs text-text-muted">
            {t("paidOnLabel")}: {invoice.paidAt} · {invoice.paidBy} ·{" "}
            {invoice.paidMethodDetail}
          </div>
        )}
        {/* Phase 7 — void/refund summary lines, shown when applicable.
            Surfaces the auditing context that the columns alone don't
            (who voided, what the reason was, how much has been
            refunded vs how much remains). */}
        {invoice.voidedAt && (
          <div className="mt-3 text-xs text-text-muted">
            {t("voidedOnLabel")}: {invoice.voidedAt} · {invoice.voidedBy}
            {invoice.voidReason ? ` · ${invoice.voidReason}` : ""}
          </div>
        )}
        {invoice.refundedTotalChf > 0 && (
          <div className="mt-3 text-xs text-text-muted">
            {t("refundedTotalLabel")}: CHF{" "}
            {invoice.refundedTotalChf.toFixed(2)} ·{" "}
            {t("refundedRemainingLabel")}: CHF{" "}
            {remainingRefundable.toFixed(2)}
          </div>
        )}
      </Card>

      {/* Phase 7 — linked credit notes panel. Hidden when there are
          none (most invoices). When present, lists each credit note
          with kind, amount, reason, issued date, and PDF download. */}
      {creditNotes.length > 0 && (
        <Card>
          <CardHeader>{t("creditNotesPanelTitle")}</CardHeader>
          <div className="overflow-x-auto">
          <table className="w-full text-sm">
            <thead className="text-xs text-text-muted text-left">
              <tr>
                <th className="pb-2 pr-4">{t("creditNoteNumberHeader")}</th>
                <th className="pb-2 pr-4">{t("creditNoteKindHeader")}</th>
                <th className="pb-2 pr-4 text-right">
                  {t("creditNoteAmountHeader")}
                </th>
                <th className="pb-2 pr-4">{t("creditNoteReasonHeader")}</th>
                <th className="pb-2 pr-4">{t("creditNoteIssuedHeader")}</th>
                <th className="pb-2 text-right">{t("creditNotePdfHeader")}</th>
              </tr>
            </thead>
            <tbody>
              {creditNotes.map((cn) => (
                <tr key={cn.id} className="border-t border-border">
                  <td className="py-2 pr-4 font-mono text-xs">
                    {cn.creditNoteNumber}
                  </td>
                  <td className="py-2 pr-4">
                    <span className="px-2 py-0.5 rounded text-xs text-error bg-error/10">
                      {t(`creditNoteKind_${cn.kind}` as any)}
                    </span>
                  </td>
                  <td className="py-2 pr-4 text-right font-mono whitespace-nowrap">
                    CHF {cn.amountChf.toFixed(2)}
                  </td>
                  <td className="py-2 pr-4 text-text-secondary text-xs">
                    {cn.reason ?? "—"}
                  </td>
                  <td className="py-2 pr-4 text-xs text-text-muted whitespace-nowrap">
                    {cn.issuedAt.slice(0, 10)}
                  </td>
                  <td className="py-2 text-right">
                    {cn.hasPdf ? (
                      <a
                        href={`/api/credit-notes/${encodeURIComponent(
                          cn.creditNoteNumber
                        )}/pdf`}
                        target="_blank"
                        rel="noopener noreferrer"
                        className="text-accent hover:underline text-xs"
                      >
                        {t("downloadPdfBtn")}
                      </a>
                    ) : (
                      <span className="text-text-muted text-xs italic">
                        {t("creditNoteNoPdf")}
                      </span>
                    )}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
          </div>
        </Card>
      )}

      {/* Lines */}
      <Card>
        <CardHeader>{t("lineItemsTitle")}</CardHeader>
        <div className="overflow-x-auto">
        <table className="w-full text-sm">
          <thead className="text-xs text-text-muted text-left">
            <tr>
              <th className="pb-2">{t("descCol")}</th>
              <th className="pb-2 text-right">{t("qtyCol")}</th>
              <th className="pb-2 text-right">{t("unitPriceCol")}</th>
              <th className="pb-2 text-right">{t("amountCol")}</th>
            </tr>
          </thead>
          <tbody>
            {tenantOrder.map((tenantKey) => {
              const tenantLines = linesByTenant.get(tenantKey)!;
              return (
                <Fragment key={tenantKey ?? "_org"}>
                  {tenantKey && (
                    <tr>
                      <td colSpan={4} className="pt-3 pb-1">
                        <span className="text-xs font-semibold text-accent">
                          {tenantKey}
                        </span>
                      </td>
                    </tr>
                  )}
                  {tenantLines.map((ln) => (
                    <tr key={ln.id} className="border-t border-border">
                      <td className="py-1.5">
                        <div>{ln.description}</div>
                        <div className="text-xs text-text-muted font-mono">
                          {ln.kind}
                        </div>
                      </td>
                      <td className="py-1.5 text-right">
                        {ln.quantity}
                        {ln.unitLabel ? ` ${ln.unitLabel}` : ""}
                      </td>
                      <td className="py-1.5 text-right font-mono text-xs">
                        {ln.unitPriceChf.toFixed(4)}
                      </td>
                      <td className="py-1.5 text-right">
                        {ln.amountChf.toFixed(2)}
                      </td>
                    </tr>
                  ))}
                </Fragment>
              );
            })}
          </tbody>
        </table>
        </div>
        <div className="mt-4 pt-3 border-t border-border space-y-1 text-sm">
          <div className="flex justify-between">
            <span className="text-text-muted">{t("subtotal")}</span>
            <span>CHF {invoice.subtotalChf.toFixed(2)}</span>
          </div>
          <div className="flex justify-between">
            <span className="text-text-muted">
              {t("vat")} ({invoice.vatRate.toFixed(2)}%)
            </span>
            <span>CHF {invoice.vatAmountChf.toFixed(2)}</span>
          </div>
          <div className="flex justify-between pt-1 border-t border-border font-semibold">
            <span>{t("total")}</span>
            <span>CHF {invoice.totalChf.toFixed(2)}</span>
          </div>
        </div>
      </Card>

      {/* Billing snapshot */}
      <Card>
        <CardHeader>{t("billToSnapshotTitle")}</CardHeader>
        <div className="text-sm space-y-1">
          <div className="font-semibold">
            {invoice.billingSnapshot.companyName}
          </div>
          <div>{invoice.billingSnapshot.streetAddress}</div>
          <div>
            {invoice.billingSnapshot.postalCode}{" "}
            {invoice.billingSnapshot.city}
          </div>
          <div>{invoice.billingSnapshot.country}</div>
          {invoice.billingSnapshot.vatNumber && (
            <div className="text-text-muted">
              VAT: {invoice.billingSnapshot.vatNumber}
            </div>
          )}
          <div className="text-text-muted">
            {invoice.billingSnapshot.billingEmail}
          </div>
        </div>
      </Card>
    </div>
  );
}

function StatusPill({ status }: { status: InvoiceStatus }) {
  const t = useTranslations("adminBilling");
  const color =
    status === "paid"
      ? "bg-success/15 text-success"
      : status === "overdue"
        ? "bg-error/15 text-error"
        : status === "void" || status === "uncollectible"
          ? "bg-text-muted/15 text-text-muted"
          : status === "partially_refunded" || status === "fully_refunded"
            ? "bg-error/15 text-error"
            : "bg-accent/15 text-accent";
  return (
    <span
      className={`inline-block px-2 py-0.5 rounded text-xs font-medium ${color}`}
    >
      {t(`status_${status}`)}
    </span>
  );
}
