"use client";

import { useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { CustomerPicker } from "@/components/CustomerPicker";
import { createMovementBatch, getBillingFacets, getByCheck } from "@/lib/api";
import { formatMoney, formatNumber, txTypeLabel } from "@/lib/labels";
import type {
  BatchCreateInput,
  BillingFacets,
  ByCheckResponse,
  Currency,
  LedgerCurrency,
  TransactionDomain,
} from "@/lib/types";

/**
 * Batch capture by check — the "Editor" screen from the legacy system
 * (docs/RECEIPT_CAPTURE_SPEC.md §1.2), and the manual half of the Captura
 * screen (see `Captura`).
 *
 * Staff key many customers' receipts against ONE physical check before cutting
 * it, then check that the captured total matches the check's amount. That
 * reconciliation is the whole point, so the running total is the most prominent
 * thing on the page and an optional "importe del cheque" field turns it into a
 * live difference.
 *
 * No batch entity is persisted: `checkNumber` is a plain column, and grouping
 * by it answers every by-check question (see the "Reporte por cheque" report).
 */

const DOMAINS: { key: TransactionDomain; label: string }[] = [
  { key: "UTILITY", label: "Servicios" },
  { key: "INSURANCE", label: "Seguros" },
  { key: "TRUST", label: "Fideicomiso" },
];

interface Line {
  /** Local row key — lines have no server identity until the batch posts. */
  key: number;
  customerId: string;
  customerName: string;
  amount: string;
  reference: string;
  period: string;
  outstanding: boolean;
}

function blankLine(key: number): Line {
  return {
    key,
    customerId: "",
    customerName: "",
    amount: "",
    reference: "",
    period: "",
    outstanding: false,
  };
}

export function ManualCheckCapture() {
  const [facets, setFacets] = useState<BillingFacets | null>(null);

  // Check-level fields — shared by every line.
  const [domain, setDomain] = useState<TransactionDomain>("UTILITY");
  const [currency, setCurrency] = useState<LedgerCurrency>("MXN");
  const [typeId, setTypeId] = useState("");
  const [checkNumber, setCheckNumber] = useState("");
  const [transactionDate, setTransactionDate] = useState(
    new Date().toISOString().slice(0, 10),
  );
  /** The physical check's amount, for reconciliation only — never submitted. */
  const [checkAmount, setCheckAmount] = useState("");

  const [lines, setLines] = useState<Line[]>([blankLine(1), blankLine(2), blankLine(3)]);
  const [nextKey, setNextKey] = useState(4);

  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [posted, setPosted] = useState<ByCheckResponse | null>(null);

  useEffect(() => {
    getBillingFacets().then(setFacets).catch(() => setFacets(null));
  }, []);

  const filled = lines.filter(
    (l) => l.customerId && l.amount.trim() !== "" && Number.isFinite(Number(l.amount)),
  );

  // Charges are captured as positive numbers and signed on submit, matching
  // MovementForm — staff type what's on the bill, not a negative.
  const total = useMemo(
    () =>
      filled
        .filter((l) => !l.outstanding)
        .reduce((sum, l) => sum + Math.abs(Number(l.amount)), 0),
    [filled],
  );
  const outstandingTotal = useMemo(
    () =>
      filled
        .filter((l) => l.outstanding)
        .reduce((sum, l) => sum + Math.abs(Number(l.amount)), 0),
    [filled],
  );

  const checkAmt = Number(checkAmount);
  const hasCheckAmt = checkAmount.trim() !== "" && Number.isFinite(checkAmt);
  const diff = hasCheckAmt ? checkAmt - total : 0;
  const reconciled = hasCheckAmt && Math.abs(diff) < 0.005;

  function update(key: number, patch: Partial<Line>) {
    setLines((ls) => ls.map((l) => (l.key === key ? { ...l, ...patch } : l)));
  }

  function addLine() {
    setLines((ls) => [...ls, blankLine(nextKey)]);
    setNextKey((k) => k + 1);
  }

  function removeLine(key: number) {
    setLines((ls) => (ls.length === 1 ? ls : ls.filter((l) => l.key !== key)));
  }

  async function submit(e: React.FormEvent) {
    e.preventDefault();
    if (!checkNumber.trim()) {
      setError("Indica el número de cheque.");
      return;
    }
    if (filled.length === 0) {
      setError("Captura al menos una línea con cliente y monto.");
      return;
    }
    const dupes = filled
      .map((l) => l.customerId)
      .filter((id, i, arr) => arr.indexOf(id) !== i);
    if (dupes.length) {
      const names = filled
        .filter((l) => dupes.includes(l.customerId))
        .map((l) => l.customerName);
      if (
        !window.confirm(
          `Hay más de una línea para el mismo cliente (${[...new Set(names)].join(
            ", ",
          )}). ¿Continuar?`,
        )
      )
        return;
    }

    const payload: BatchCreateInput = {
      domain,
      transactionDate,
      checkNumber: checkNumber.trim(),
      currency: currency as Currency,
      typeId: typeId || undefined,
      lines: filled.map((l) => ({
        customerId: l.customerId,
        // Every line of a check batch is a charge the office paid out.
        amount: -Math.abs(Number(l.amount)),
        reference: l.reference.trim() || undefined,
        period: l.period.trim() || undefined,
        outstanding: l.outstanding || undefined,
      })),
    };

    setSaving(true);
    setError(null);
    try {
      await createMovementBatch(payload);
      // Re-read through the by-check view so the confirmation shows what's
      // actually stored (including anything captured against this check
      // earlier), not just what this request sent.
      setPosted(await getByCheck(payload.checkNumber));
    } catch (e2) {
      setError((e2 as Error)?.message ?? "No se pudo guardar el lote.");
    } finally {
      setSaving(false);
    }
  }

  function reset() {
    setPosted(null);
    setLines([blankLine(nextKey), blankLine(nextKey + 1), blankLine(nextKey + 2)]);
    setNextKey((k) => k + 3);
    setCheckNumber("");
    setCheckAmount("");
  }

  if (posted) {
    return (
      <>
        <div className="page-head">
          <div>
            <h2 className="page-title">Lote capturado</h2>
            <p className="eyebrow">
              Cheque {posted.checkNumber} · {formatNumber(posted.count)}{" "}
              {posted.count === 1 ? "movimiento" : "movimientos"}
            </p>
          </div>
          <div style={{ display: "flex", gap: 10 }}>
            <button type="button" className="btn btn-primary" onClick={reset}>
              Capturar otro cheque
            </button>
            <Link href="/estado-cuenta" className="btn btn-outline">
              Volver a estado de cuenta
            </Link>
          </div>
        </div>

        <div className="filtered-totals" style={{ marginBottom: 16 }}>
          {posted.totals.map((t) => (
            <div className="filtered-total" key={t.currency}>
              <span className="filtered-total-cur">{t.currency}</span>
              <span className="filtered-total-net">
                Total del cheque <strong>{formatMoney(t.total, t.currency)}</strong>
              </span>
              <span>{formatNumber(t.count)} movimientos</span>
            </div>
          ))}
          {posted.outstandingCount > 0 && (
            <div className="filtered-total">
              <span>
                {formatNumber(posted.outstandingCount)} sin fondos (no suman al
                total)
              </span>
            </div>
          )}
        </div>

        <div className="tx-scroll">
          <table className="tx-table">
            <thead>
              <tr>
                <th>Cliente</th>
                <th>Referencia</th>
                <th>Periodo</th>
                <th>Estado</th>
                <th className="num">Monto</th>
              </tr>
            </thead>
            <tbody>
              {posted.items.map((i) => (
                <tr key={i.id}>
                  <td>
                    <Link
                      href={`/estado-cuenta/${i.customerId}`}
                      className="inline-link"
                    >
                      {i.customerName}
                    </Link>
                  </td>
                  <td>{i.reference || "—"}</td>
                  <td>{i.period || "—"}</td>
                  <td>{i.outstanding ? "Sin fondos" : "Pagado"}</td>
                  <td className="num">
                    <span className="tx-amount neg">
                      {formatMoney(i.amount, i.currency)}
                    </span>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>

        <p className="muted" style={{ marginTop: 14 }}>
          Para imprimir la conciliación, usa el reporte{" "}
          <Link
            href={`/reportes/cheque-count?checkNumber=${encodeURIComponent(
              posted.checkNumber,
            )}`}
            className="inline-link"
          >
            Reporte por cheque
          </Link>
          .
        </p>
      </>
    );
  }

  return (
    <>
      {error && <div className="state-box state-error">{error}</div>}

      <form onSubmit={submit}>
        <div className="card" style={{ padding: 20, marginBottom: 16 }}>
          <h2 className="section-title" style={{ marginBottom: 14 }}>
            Datos del cheque
          </h2>
          <div className="form-grid">
            <label className="field">
              <span className="field-label">Número de cheque *</span>
              <input
                className="input"
                value={checkNumber}
                onChange={(e) => setCheckNumber(e.target.value)}
                required
              />
            </label>
            <label className="field">
              <span className="field-label">Fecha *</span>
              <input
                className="input"
                type="date"
                required
                value={transactionDate}
                onChange={(e) => setTransactionDate(e.target.value)}
              />
            </label>
            <label className="field">
              <span className="field-label">Línea de negocio *</span>
              <select
                className="select"
                value={domain}
                onChange={(e) => setDomain(e.target.value as TransactionDomain)}
              >
                {DOMAINS.map((d) => (
                  <option key={d.key} value={d.key}>
                    {d.label}
                  </option>
                ))}
              </select>
            </label>
            <label className="field">
              <span className="field-label">Moneda *</span>
              <select
                className="select"
                value={currency}
                onChange={(e) => setCurrency(e.target.value as LedgerCurrency)}
              >
                <option value="MXN">Pesos (MXN)</option>
                <option value="USD">Dólares (USD)</option>
              </select>
            </label>
            <label className="field">
              <span className="field-label">Concepto</span>
              <select
                className="select"
                value={typeId}
                onChange={(e) => setTypeId(e.target.value)}
              >
                <option value="">(sin concepto)</option>
                {facets?.types.map((t) => (
                  <option key={t.id} value={t.id}>
                    {txTypeLabel({ nameEn: t.name })}
                  </option>
                ))}
              </select>
            </label>
            <label className="field">
              <span className="field-label">Importe del cheque</span>
              <input
                className="input"
                type="number"
                step="0.01"
                min="0"
                value={checkAmount}
                onChange={(e) => setCheckAmount(e.target.value)}
                placeholder="Para conciliar"
              />
            </label>
          </div>
        </div>

        <div className="card" style={{ padding: 20, marginBottom: 16 }}>
          <div
            style={{
              display: "flex",
              justifyContent: "space-between",
              alignItems: "center",
              marginBottom: 14,
            }}
          >
            <h2 className="section-title" style={{ margin: 0 }}>
              Recibos ({formatNumber(filled.length)})
            </h2>
            <button type="button" className="btn btn-outline" onClick={addLine}>
              Agregar línea
            </button>
          </div>

          <div className="tx-scroll">
            <table className="tx-table">
              <thead>
                <tr>
                  <th style={{ minWidth: 240 }}>Cliente *</th>
                  <th style={{ minWidth: 120 }}>Referencia</th>
                  <th style={{ minWidth: 100 }}>Periodo</th>
                  <th style={{ minWidth: 110 }} className="num">
                    Monto *
                  </th>
                  <th style={{ whiteSpace: "nowrap" }}>Sin fondos</th>
                  <th style={{ width: 1 }} />
                </tr>
              </thead>
              <tbody>
                {lines.map((l) => (
                  <tr key={l.key}>
                    <td>
                      <CustomerPicker
                        value={l.customerId}
                        valueName={l.customerId ? l.customerName : undefined}
                        onPick={(id, name) =>
                          update(l.key, { customerId: id, customerName: name })
                        }
                      />
                    </td>
                    <td>
                      <input
                        className="input"
                        value={l.reference}
                        onChange={(e) =>
                          update(l.key, { reference: e.target.value })
                        }
                      />
                    </td>
                    <td>
                      <input
                        className="input"
                        value={l.period}
                        onChange={(e) => update(l.key, { period: e.target.value })}
                        placeholder="2026-07"
                      />
                    </td>
                    <td>
                      <input
                        className="input num"
                        type="number"
                        step="0.01"
                        min="0"
                        value={l.amount}
                        onChange={(e) => update(l.key, { amount: e.target.value })}
                        placeholder="0.00"
                      />
                    </td>
                    <td style={{ textAlign: "center" }}>
                      <input
                        type="checkbox"
                        checked={l.outstanding}
                        onChange={(e) =>
                          update(l.key, { outstanding: e.target.checked })
                        }
                        aria-label="Sin fondos"
                      />
                    </td>
                    <td>
                      <button
                        type="button"
                        className="btn btn-ghost"
                        style={{ padding: "4px 10px", fontSize: 12 }}
                        onClick={() => removeLine(l.key)}
                        disabled={lines.length === 1}
                      >
                        Quitar
                      </button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>

        <div className="card" style={{ padding: 20, marginBottom: 16 }}>
          <h2 className="section-title" style={{ marginBottom: 14 }}>
            Conciliación
          </h2>
          <div className="filtered-totals">
            <div className="filtered-total">
              <span className="filtered-total-cur">{currency}</span>
              <span className="filtered-total-net">
                Capturado <strong>{formatMoney(String(-total), currency)}</strong>
              </span>
              <span>{formatNumber(filled.filter((l) => !l.outstanding).length)} recibos</span>
            </div>
            {outstandingTotal > 0 && (
              <div className="filtered-total">
                <span>
                  Sin fondos{" "}
                  <strong>{formatMoney(String(-outstandingTotal), currency)}</strong>{" "}
                  (no suma al cheque)
                </span>
              </div>
            )}
            {hasCheckAmt && (
              <div className="filtered-total">
                <span className="filtered-total-net">
                  {reconciled ? (
                    <strong className="tx-amount pos">Cuadra con el cheque</strong>
                  ) : (
                    <>
                      Diferencia{" "}
                      <strong className="tx-amount neg">
                        {formatMoney(String(diff), currency)}
                      </strong>
                    </>
                  )}
                </span>
              </div>
            )}
          </div>
        </div>

        <div className="form-actions">
          <button
            type="submit"
            className="btn btn-primary"
            disabled={saving || filled.length === 0}
          >
            {saving
              ? "Guardando…"
              : `Capturar ${formatNumber(filled.length)} ${
                  filled.length === 1 ? "recibo" : "recibos"
                }`}
          </button>
          <Link href="/estado-cuenta" className="btn btn-outline">
            Cancelar
          </Link>
        </div>
      </form>
    </>
  );
}
