// #bills — AP Task 4, mechanical mirror of invoices/InvoicesScreen.tsx. Lists
// GET /api/c/bills (already ordered overdue-first, then open/partial before
// paid/void, per server/src/bills.ts's ORDER BY), with a status dropdown and
// a vendor picker as filters, and three entry points: "Pay bills" (AP Task
// 5, mirrors InvoicesScreen.tsx's "Receive payment" — routes to #pay-bills,
// carrying the active vendor filter if one is set) and two into BillForm:
// "New bill" (normal) and "Add older bill (already in your books)"
// (document-only — design brief's migrated-history entry point).
//
// The vendor filter's initial value can arrive pre-set from #vendors'
// balance links (see vendorFilterHandoff.ts) — consumed once on mount.

import { useEffect, useMemo, useState } from "react";
import { useCompany } from "../lib/company";
import { useApiGet } from "../lib/useApiGet";
import { fmtMoney } from "../lib/money";
import { fmtDate } from "../lib/date";
import { ErrorBanner } from "../components/ErrorBanner";
import type { NavTarget } from "../lib/useHashView";
import { BillForm, type BillFormInitial } from "./BillForm";
import { consumePendingVendorFilter } from "./vendorFilterHandoff";
import { consumePendingNewBillPrefill } from "./newBillPrefillHandoff";
import { consumePendingReceive } from "../purchaseOrders/receiveHandoff";
import { fmtQuantity } from "../items/itemTypes";
import { todayIso } from "../lib/date";

interface BillListRow {
  billId: string;
  refNo: string | null;
  vendorId: string;
  vendorName: string;
  billDate: string;
  dueDate: string;
  memo: string | null;
  documentOnly: boolean;
  status: string;
  state: "draft" | "open" | "partial" | "paid" | "void";
  total: string;
  applied: string;
  open: string;
  overdue: boolean;
}

interface BillListResponse {
  total: number;
  bills: BillListRow[];
}

interface VendorOption {
  id: string;
  name: string;
}

const STATE_LABEL: Record<BillListRow["state"], string> = {
  draft: "Draft",
  open: "Open",
  partial: "Partly paid",
  paid: "Paid",
  void: "Void",
};

const STATE_CHIP_CLASS: Record<BillListRow["state"], string> = {
  draft: "chip chip-muted",
  open: "chip chip-info",
  partial: "chip chip-warn",
  paid: "chip",
  void: "chip chip-muted",
};

type Mode =
  | { name: "list" }
  | { name: "create"; documentOnly: boolean; initial?: BillFormInitial; notice?: string | null };

export function BillsScreen({ navigate }: { navigate: (target: NavTarget) => void }) {
  const { selectedCompanyId } = useCompany();
  const [mode, setMode] = useState<Mode>({ name: "list" });
  const [statusFilter, setStatusFilter] = useState<string>("");
  const [vendorFilter, setVendorFilter] = useState<string>("");

  // One-time pickup of a vendor filter handed off from #vendors (see the
  // file header) — only ever applies on the very first mount. The sales tax
  // report's "Record a tax payment" handoff (newBillPrefillHandoff.ts) is
  // consumed the same way: it opens the New-bill form already prefilled with
  // the agency vendor and one line categorized to the Sales Tax Payable
  // account for the owed amount.
  useEffect(() => {
    const pending = consumePendingVendorFilter();
    if (pending) setVendorFilter(pending);

    const prefill = consumePendingNewBillPrefill();
    if (prefill) {
      setMode({
        name: "create",
        documentOnly: false,
        initial: {
          vendorId: prefill.vendorId,
          billDate: todayIso(),
          dueDate: "",
          refNo: "",
          memo: "",
          lines: [{
            description: prefill.description,
            quantity: "1",
            unitPrice: prefill.unitPrice,
            categoryAccountId: prefill.categoryAccountId,
          }],
        },
      });
    }

    // "Receive" on a purchase order (Inventory Task 4) lands here the same
    // way, carrying the API's own prefilled bill draft. Nothing has been
    // recorded yet: entering THIS bill is what records the goods and the
    // money, together, on the same date (spec as-built decision 1).
    const receive = consumePendingReceive();
    if (receive) {
      setMode({
        name: "create",
        documentOnly: false,
        notice: receive.notice,
        initial: {
          vendorId: receive.vendorId,
          billDate: receive.billDate,
          dueDate: "",
          refNo: "",
          memo: receive.memo ?? "",
          lines: receive.lines.map((l) => ({
            description: l.description ?? l.itemName ?? "",
            quantity: fmtQuantity(l.quantity),
            unitPrice: fmtQuantity(l.unitPrice),
            // A description-only purchase order line arrives as an ordinary
            // bill line the user still has to categorise (it can't carry a
            // po_line_id — bill_lines_po_line_requires_item).
            categoryAccountId: null,
            itemId: l.itemId,
            poLineId: l.poLineId,
          })),
        },
      });
    }
  }, []);

  const { data: vendors } = useApiGet<VendorOption[]>("/api/c/vendors", selectedCompanyId);

  const path = useMemo(() => {
    const params = new URLSearchParams();
    if (statusFilter) params.set("status", statusFilter);
    if (vendorFilter) params.set("vendorId", vendorFilter);
    const qs = params.toString();
    return `/api/c/bills${qs ? `?${qs}` : ""}`;
  }, [statusFilter, vendorFilter]);

  const { data, loading, error, retry } = useApiGet<BillListResponse>(path, selectedCompanyId);

  function goToBill(id: string) {
    navigate({ view: "bill", id });
  }

  return (
    <div className="wrap">
      <header className="top">
        <h1>Bills</h1>
        {mode.name === "list" && (
          <div style={{ display: "flex", gap: 10 }}>
            <button
              type="button"
              className="btn"
              onClick={() =>
                navigate({
                  view: "pay-bills",
                  params: vendorFilter ? { vendorId: vendorFilter } : {},
                })
              }
            >
              Pay bills
            </button>
            <button type="button" className="btn" onClick={() => setMode({ name: "create", documentOnly: true })}>
              Add older bill (already in your books)
            </button>
            <button type="button" className="btn" onClick={() => setMode({ name: "create", documentOnly: false })}>
              New bill
            </button>
          </div>
        )}
      </header>

      {mode.name === "create" && (
        <BillForm
          mode="create"
          documentOnly={mode.documentOnly}
          initial={mode.initial}
          notice={mode.notice}
          onCancel={() => setMode({ name: "list" })}
          onSaved={({ billId }) => {
            setMode({ name: "list" });
            goToBill(billId);
          }}
        />
      )}

      {mode.name === "list" && (
        <>
          <div className="report-toolbar">
            <label>
              Status
              <select
                className="select-input"
                value={statusFilter}
                onChange={(ev) => setStatusFilter(ev.target.value)}
              >
                <option value="">All</option>
                <option value="draft">Draft</option>
                <option value="open">Open</option>
                <option value="partial">Partly paid</option>
                <option value="paid">Paid</option>
                <option value="void">Void</option>
              </select>
            </label>
            <label>
              Vendor
              <select
                className="select-input"
                value={vendorFilter}
                onChange={(ev) => setVendorFilter(ev.target.value)}
              >
                <option value="">All vendors</option>
                {(vendors ?? []).map((v) => (
                  <option key={v.id} value={v.id}>
                    {v.name}
                  </option>
                ))}
              </select>
            </label>
          </div>

          {error && <ErrorBanner message={error} onRetry={retry} />}
          {loading && !data && <p className="msg-inline">Loading bills&hellip;</p>}

          {data && data.bills.length === 0 && (
            <div className="empty-state">No bills match those filters.</div>
          )}

          {data && data.bills.length > 0 && (
            <table>
              <thead>
                <tr>
                  <th>Reference</th>
                  <th>Vendor</th>
                  <th>Date</th>
                  <th>Due</th>
                  <th>Status</th>
                  <th className="num">Total</th>
                  <th className="num">Open</th>
                </tr>
              </thead>
              <tbody>
                {data.bills.map((b) => (
                  <tr key={b.billId} style={{ cursor: "pointer" }} onClick={() => goToBill(b.billId)}>
                    {/* Unlike invoices.invoiceNo (server-assigned only on
                        issue, so its absence always means "draft"), a bill's
                        refNo is optional and vendor-supplied — it can be
                        blank on an issued bill too. Status is what actually
                        distinguishes draft from issued (shown by the chip in
                        the next column), so a missing reference here just
                        reads as "no reference", never "Draft". */}
                    <td>{b.refNo ? `#${b.refNo}` : "—"}</td>
                    <td>{b.vendorName}</td>
                    <td>{fmtDate(b.billDate)}</td>
                    <td className={b.overdue ? "invoice-due-overdue" : undefined}>{fmtDate(b.dueDate)}</td>
                    <td>
                      <span className={STATE_CHIP_CLASS[b.state]}>{STATE_LABEL[b.state]}</span>
                      {b.documentOnly && <span className="badge" style={{ marginLeft: 6 }}>Doc only</span>}
                    </td>
                    <td className="num">{fmtMoney(b.total)}</td>
                    <td className="num">{fmtMoney(b.open)}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </>
      )}
    </div>
  );
}
