"use client";

import { useState, useMemo, useCallback } from "react";
import { useRouter } from "@/i18n/navigation";
import { useTranslations } from "next-intl";
import { Card, CardHeader } from "@/components/ui/card";
import type {
  CustomInvoiceDraftLine,
  CustomInvoiceDraftPayload,
  InvoiceDraftRecord,
  OrgBilling,
} from "@/types";

interface Props {
  draft: InvoiceDraftRecord;
  orgBilling: OrgBilling | null;
}

const LOCALE_OPTIONS = [
  { value: "de", label: "Deutsch" },
  { value: "en", label: "English" },
  { value: "fr", label: "Français" },
  { value: "it", label: "Italiano" },
];

/**
 * Custom invoice editor — Phase 8.
 *
 * Local state mirrors the persisted payload. Save persists the
 * current state via PUT. Preview re-renders the PDF in-memory (no
 * persistence). Issue allocates the invoice number and emails the
 * customer.
 *
 * VAT preview is computed client-side from the country in the org
 * billing snapshot — it's an estimate for the admin's eye, not
 * authoritative. The server recomputes at issue time using the
 * same vatRateForAddress() helper to ensure consistency.
 *
 * Discount/Rabatt is supported via a row with a negative
 * unitPriceChf. The "Add discount" button seeds a new row with
 * quantity 1 and a -50 placeholder to nudge the admin toward the
 * intended sign.
 */
export function CustomInvoiceEditor({ draft, orgBilling }: Props) {
  const t = useTranslations("adminBilling");
  const router = useRouter();

  // Editable state — initialized from the draft payload.
  const [issueDate, setIssueDate] = useState(draft.payload.issueDate);
  const [dueDate, setDueDate] = useState(draft.payload.dueDate);
  const [locale, setLocale] = useState<"de" | "en" | "fr" | "it">(
    draft.payload.locale
  );
  const [paymentMethod, setPaymentMethod] = useState<"invoice" | "card">(
    draft.payload.paymentMethod
  );
  const [adminNotes, setAdminNotes] = useState(draft.payload.adminNotes ?? "");
  const [lines, setLines] = useState<CustomInvoiceDraftLine[]>(
    draft.payload.lines.length > 0
      ? draft.payload.lines
      : [{ description: "", quantity: 1, unitPriceChf: 0 }]
  );

  const [busy, setBusy] = useState<null | "save" | "preview" | "issue" | "delete">(
    null
  );
  const [error, setError] = useState("");
  const [dirty, setDirty] = useState(false);

  // Build current payload — used by every action.
  const buildPayload = useCallback((): CustomInvoiceDraftPayload => {
    return {
      issueDate,
      dueDate,
      locale,
      paymentMethod,
      adminNotes: adminNotes.trim() ? adminNotes.trim() : undefined,
      lines: lines.map((ln) => ({
        description: ln.description,
        quantity: Number(ln.quantity) || 0,
        unitPriceChf: Number(ln.unitPriceChf) || 0,
      })),
    };
  }, [issueDate, dueDate, locale, paymentMethod, adminNotes, lines]);

  // Client-side VAT estimate. The auth-of-truth math runs server-side
  // at issue time; this is just to show the admin what they're about
  // to commit to.
  const totals = useMemo(() => {
    const subtotal = Math.round(
      lines.reduce(
        (s, ln) => s + (Number(ln.quantity) || 0) * (Number(ln.unitPriceChf) || 0),
        0
      ) * 100
    ) / 100;
    // Country-based VAT estimate. Mirrors vatRateForAddress() —
    // simplified because the editor doesn't know the platform
    // pricing config. Defaults to 8.1 for CH/LI; 0 otherwise.
    const country = (orgBilling?.country ?? "").toUpperCase();
    let vatRate = 0;
    if (country === "CH" || country === "LI") {
      vatRate = 8.1;
    } else if (orgBilling?.vatNumber) {
      vatRate = 0; // reverse charge
    } else {
      vatRate = 0; // out of scope OR consumer (server will fix)
    }
    const vatAmount = Math.round(subtotal * (vatRate / 100) * 100) / 100;
    const total = Math.round((subtotal + vatAmount) * 100) / 100;
    return { subtotal, vatRate, vatAmount, total };
  }, [lines, orgBilling]);

  // Line management
  const updateLine = (idx: number, patch: Partial<CustomInvoiceDraftLine>) => {
    setLines((prev) =>
      prev.map((ln, i) => (i === idx ? { ...ln, ...patch } : ln))
    );
    setDirty(true);
  };
  const addLine = () => {
    setLines((prev) => [
      ...prev,
      { description: "", quantity: 1, unitPriceChf: 0 },
    ]);
    setDirty(true);
  };
  const addDiscountLine = () => {
    setLines((prev) => [
      ...prev,
      { description: t("editorRabattDefaultDescription"), quantity: 1, unitPriceChf: -50 },
    ]);
    setDirty(true);
  };
  const removeLine = (idx: number) => {
    setLines((prev) => prev.filter((_, i) => i !== idx));
    setDirty(true);
  };

  // Actions
  const save = async (): Promise<boolean> => {
    setError("");
    setBusy("save");
    try {
      const res = await fetch(
        `/api/admin/billing/invoice-drafts/${draft.id}`,
        {
          method: "PUT",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(buildPayload()),
        }
      );
      const j = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(j.error || `HTTP ${res.status}`);
      setDirty(false);
      return true;
    } catch (e: any) {
      setError(e.message);
      return false;
    } finally {
      setBusy(null);
    }
  };

  const preview = async () => {
    // Save first if there are unsaved changes — otherwise the
    // preview reflects stale data.
    if (dirty) {
      const ok = await save();
      if (!ok) return;
    }
    // Open the preview in a new tab. The browser handles the PDF
    // download/render natively; we don't need to fetch the bytes
    // ourselves.
    window.open(
      `/api/admin/billing/invoice-drafts/${draft.id}/preview`,
      "_blank",
      "noopener"
    );
  };

  const issue = async () => {
    if (!confirm(t("editorIssueConfirm"))) return;
    if (dirty) {
      const ok = await save();
      if (!ok) return;
    }
    setError("");
    setBusy("issue");
    try {
      const res = await fetch(
        `/api/admin/billing/invoice-drafts/${draft.id}/issue`,
        { method: "POST" }
      );
      const j = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(j.error || `HTTP ${res.status}`);
      // The draft was deleted server-side; go look at the new invoice.
      router.push(`/admin/billing/invoices/${j.invoice.id}`);
    } catch (e: any) {
      setError(e.message);
      setBusy(null);
    }
  };

  const deleteDraft = async () => {
    if (!confirm(t("editorDeleteConfirm"))) return;
    setError("");
    setBusy("delete");
    try {
      const res = await fetch(
        `/api/admin/billing/invoice-drafts/${draft.id}`,
        { method: "DELETE" }
      );
      if (!res.ok) {
        const j = await res.json().catch(() => ({}));
        throw new Error(j.error || `HTTP ${res.status}`);
      }
      router.push("/admin/billing/invoice-drafts");
    } catch (e: any) {
      setError(e.message);
      setBusy(null);
    }
  };

  // No billing snapshot = can't issue. Save still works so admin
  // can come back once the customer has completed onboarding.
  const canIssue =
    !!orgBilling &&
    lines.length > 0 &&
    lines.every((ln) => ln.description.trim().length > 0);

  return (
    <div className="flex flex-col gap-6">
      {/* Bill-to preview — read-only, sourced from the org's billing
          snapshot. Issued at issue time. */}
      <Card>
        <CardHeader>{t("editorBillToHeading")}</CardHeader>
        <div className="p-4 text-sm">
          {orgBilling ? (
            <>
              <p className="font-medium">{orgBilling.companyName}</p>
              {orgBilling.contactName && (
                <p className="text-text-secondary text-xs">
                  {orgBilling.contactName}
                </p>
              )}
              <p className="text-text-secondary text-xs">
                {orgBilling.streetAddress}, {orgBilling.postalCode}{" "}
                {orgBilling.city}, {orgBilling.country}
              </p>
              {orgBilling.vatNumber && (
                <p className="text-text-muted text-xs mt-1">
                  MWST/VAT: {orgBilling.vatNumber}
                </p>
              )}
              <p className="text-text-muted text-xs">
                {orgBilling.billingEmail}
              </p>
            </>
          ) : (
            <p className="text-error">{t("editorNoBillingSnapshot")}</p>
          )}
        </div>
      </Card>

      {/* Dates + locale + payment method */}
      <Card>
        <CardHeader>{t("editorMetadataHeading")}</CardHeader>
        <div className="p-4 grid grid-cols-2 md:grid-cols-4 gap-4">
          <div className="flex flex-col gap-1">
            <label className="text-xs uppercase tracking-wider text-text-muted">
              {t("editorIssueDateLabel")}
            </label>
            <input
              type="date"
              value={issueDate}
              onChange={(e) => {
                setIssueDate(e.target.value);
                setDirty(true);
              }}
              className="px-3 py-2 rounded-md border border-border bg-surface-2 text-sm"
            />
          </div>
          <div className="flex flex-col gap-1">
            <label className="text-xs uppercase tracking-wider text-text-muted">
              {t("editorDueDateLabel")}
            </label>
            <input
              type="date"
              value={dueDate}
              onChange={(e) => {
                setDueDate(e.target.value);
                setDirty(true);
              }}
              className="px-3 py-2 rounded-md border border-border bg-surface-2 text-sm"
            />
          </div>
          <div className="flex flex-col gap-1">
            <label className="text-xs uppercase tracking-wider text-text-muted">
              {t("editorLocaleLabel")}
            </label>
            <select
              value={locale}
              onChange={(e) => {
                setLocale(e.target.value as "de" | "en" | "fr" | "it");
                setDirty(true);
              }}
              className="px-3 py-2 rounded-md border border-border bg-surface-2 text-sm"
            >
              {LOCALE_OPTIONS.map((o) => (
                <option key={o.value} value={o.value}>
                  {o.label}
                </option>
              ))}
            </select>
          </div>
          <div className="flex flex-col gap-1">
            <label className="text-xs uppercase tracking-wider text-text-muted">
              {t("editorPaymentMethodLabel")}
            </label>
            <select
              value={paymentMethod}
              onChange={(e) => {
                setPaymentMethod(e.target.value as "invoice" | "card");
                setDirty(true);
              }}
              className="px-3 py-2 rounded-md border border-border bg-surface-2 text-sm"
            >
              <option value="invoice">{t("editorPaymentInvoice")}</option>
              <option value="card">{t("editorPaymentCard")}</option>
            </select>
          </div>
        </div>
      </Card>

      {/* Line editor */}
      <Card>
        <CardHeader>{t("editorLinesHeading")}</CardHeader>
        <div className="p-4">
          <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-3">{t("editorLineDescription")}</th>
                <th className="pb-2 pr-3 w-20 text-right">
                  {t("editorLineQty")}
                </th>
                <th className="pb-2 pr-3 w-32 text-right">
                  {t("editorLineUnitPrice")}
                </th>
                <th className="pb-2 pr-3 w-32 text-right">
                  {t("editorLineAmount")}
                </th>
                <th className="pb-2 w-12"></th>
              </tr>
            </thead>
            <tbody>
              {lines.map((ln, idx) => {
                const amount =
                  Math.round(
                    (Number(ln.quantity) || 0) *
                      (Number(ln.unitPriceChf) || 0) *
                      100
                  ) / 100;
                return (
                  <tr key={idx} className="border-t border-border">
                    <td className="py-2 pr-3">
                      <input
                        type="text"
                        value={ln.description}
                        onChange={(e) =>
                          updateLine(idx, { description: e.target.value })
                        }
                        placeholder={t("editorLineDescriptionPlaceholder")}
                        className="w-full px-2 py-1.5 rounded border border-border bg-surface-2 text-sm"
                        maxLength={500}
                      />
                    </td>
                    <td className="py-2 pr-3">
                      <input
                        type="number"
                        step="0.01"
                        value={ln.quantity}
                        onChange={(e) =>
                          updateLine(idx, {
                            quantity: parseFloat(e.target.value) || 0,
                          })
                        }
                        className="w-full px-2 py-1.5 rounded border border-border bg-surface-2 text-sm font-mono text-right"
                      />
                    </td>
                    <td className="py-2 pr-3">
                      <input
                        type="number"
                        step="0.01"
                        value={ln.unitPriceChf}
                        onChange={(e) =>
                          updateLine(idx, {
                            unitPriceChf: parseFloat(e.target.value) || 0,
                          })
                        }
                        className="w-full px-2 py-1.5 rounded border border-border bg-surface-2 text-sm font-mono text-right"
                      />
                    </td>
                    <td className="py-2 pr-3 text-right font-mono text-sm whitespace-nowrap">
                      <span className={amount < 0 ? "text-error" : ""}>
                        CHF {amount.toFixed(2)}
                      </span>
                    </td>
                    <td className="py-2 text-right">
                      <button
                        onClick={() => removeLine(idx)}
                        className="text-text-muted hover:text-error text-lg leading-none"
                        title={t("editorLineRemove")}
                        type="button"
                      >
                        ×
                      </button>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
          </div>
          <div className="flex gap-2 mt-3">
            <button
              onClick={addLine}
              type="button"
              className="px-3 py-1.5 rounded-md border border-border text-sm hover:bg-surface-3"
            >
              + {t("editorAddLine")}
            </button>
            <button
              onClick={addDiscountLine}
              type="button"
              className="px-3 py-1.5 rounded-md border border-border text-sm hover:bg-surface-3 text-text-secondary"
              title={t("editorAddDiscountHint")}
            >
              − {t("editorAddDiscount")}
            </button>
          </div>
        </div>
      </Card>

      {/* Admin notes */}
      <Card>
        <CardHeader>{t("editorNotesHeading")}</CardHeader>
        <div className="p-4">
          <textarea
            value={adminNotes}
            onChange={(e) => {
              setAdminNotes(e.target.value);
              setDirty(true);
            }}
            placeholder={t("editorNotesPlaceholder")}
            rows={2}
            maxLength={2000}
            className="w-full px-3 py-2 rounded-md border border-border bg-surface-2 text-sm"
          />
          <p className="text-xs text-text-muted mt-1">
            {t("editorNotesHint")}
          </p>
        </div>
      </Card>

      {/* Totals preview */}
      <Card>
        <CardHeader>{t("editorTotalsHeading")}</CardHeader>
        <div className="p-4 max-w-sm ml-auto text-sm">
          <div className="flex justify-between py-1">
            <span className="text-text-muted">{t("editorSubtotal")}</span>
            <span className="font-mono">CHF {totals.subtotal.toFixed(2)}</span>
          </div>
          <div className="flex justify-between py-1">
            <span className="text-text-muted">
              {t("editorVat")} ({totals.vatRate.toFixed(1)}%)
            </span>
            <span className="font-mono">CHF {totals.vatAmount.toFixed(2)}</span>
          </div>
          <div className="flex justify-between py-2 border-t border-border mt-1 font-medium">
            <span>{t("editorTotal")}</span>
            <span className="font-mono">CHF {totals.total.toFixed(2)}</span>
          </div>
          <p className="text-xs text-text-muted mt-2 italic">
            {t("editorTotalsEstimateNote")}
          </p>
        </div>
      </Card>

      {/* Error + actions */}
      {error && (
        <div className="text-sm text-error border border-error/30 bg-error/10 rounded-md px-4 py-2">
          {error}
        </div>
      )}

      <div className="flex flex-wrap gap-2 justify-between items-center">
        <button
          onClick={deleteDraft}
          disabled={busy !== null}
          className="px-4 py-2 rounded-md border border-error text-error text-sm disabled:opacity-50 hover:bg-error/10"
          type="button"
        >
          {busy === "delete" ? t("deleting") : t("editorDeleteBtn")}
        </button>
        <div className="flex gap-2 ml-auto">
          <button
            onClick={save}
            disabled={busy !== null || !dirty}
            className="px-4 py-2 rounded-md border border-border text-sm disabled:opacity-50"
            type="button"
          >
            {busy === "save"
              ? t("saving")
              : dirty
                ? t("editorSaveBtn")
                : t("editorSavedBtn")}
          </button>
          <button
            onClick={preview}
            disabled={busy !== null || lines.length === 0}
            className="px-4 py-2 rounded-md border border-border text-sm disabled:opacity-50"
            type="button"
          >
            {busy === "preview" ? t("previewing") : t("editorPreviewBtn")}
          </button>
          <button
            onClick={issue}
            disabled={busy !== null || !canIssue}
            className="px-4 py-2 rounded-md bg-accent text-surface-0 text-sm disabled:opacity-50"
            type="button"
          >
            {busy === "issue" ? t("issuing") : t("editorIssueBtn")}
          </button>
        </div>
      </div>
    </div>
  );
}
