// #vendors — AP Task 4, mechanical mirror of customers/CustomersScreen.tsx
// (vendor/bill vocabulary, plus the track_1099 flag). A plain table
// (name/contact/terms/1099/balance/oldest due), sorted by name (the API
// already returns it that way — server/src/vendors.ts's GET orders by
// v.name). "Add vendor" and row-click-to-edit both open the SAME inline
// panel (VendorPanel below) — same single-form-multiple-entry-points pattern
// as CustomerPanel.
//
// A vendor's balance is a link to #bills pre-filtered to that vendor (mirrors
// the design brief's customer-balance link) via the sessionStorage handoff in
// bills/vendorFilterHandoff.ts — see that file's header for why this isn't a
// hash query param instead.

import { useState } from "react";
import { useCompany } from "../lib/company";
import { useApiGet } from "../lib/useApiGet";
import { apiPost, apiPatch, ApiError } from "../lib/api";
import { fmtMoney, isZeroMoney } from "../lib/money";
import { fmtDate } from "../lib/date";
import { ErrorBanner } from "../components/ErrorBanner";
import type { NavTarget } from "../lib/useHashView";
import { setPendingVendorFilter } from "../bills/vendorFilterHandoff";

interface VendorRow {
  id: string;
  name: string;
  email: string | null;
  phone: string | null;
  address: string | null;
  termsDays: number;
  track1099: boolean;
  active: boolean;
  balance: string;
  oldestOpenDueDate: string | null;
}

interface VendorFormState {
  name: string;
  email: string;
  phone: string;
  address: string;
  termsDays: string;
  track1099: boolean;
  active: boolean;
}

const BLANK_FORM: VendorFormState = {
  name: "",
  email: "",
  phone: "",
  address: "",
  termsDays: "30",
  track1099: false,
  active: true,
};

function toFormState(row: VendorRow): VendorFormState {
  return {
    name: row.name,
    email: row.email ?? "",
    phone: row.phone ?? "",
    address: row.address ?? "",
    termsDays: String(row.termsDays),
    track1099: row.track1099,
    active: row.active,
  };
}

// Loose client-side check only — the server is the real validator
// (vendors.ts's nameSchema/emailSchema/termsDaysSchema); this just avoids a
// round trip for the obviously-empty case and gives an immediate English
// hint for a malformed terms number, matching the codebase's existing
// pattern (Record.tsx's amountError).
function validateForm(form: VendorFormState): string | null {
  if (form.name.trim() === "") return "A vendor needs a name.";
  if (form.termsDays.trim() !== "" && !/^\d+$/.test(form.termsDays.trim())) {
    return "Terms should be a whole number of days.";
  }
  return null;
}

function buildBody(form: VendorFormState): Record<string, unknown> {
  return {
    name: form.name.trim(),
    email: form.email.trim() || undefined,
    phone: form.phone.trim() || undefined,
    address: form.address.trim() || undefined,
    termsDays: form.termsDays.trim() === "" ? undefined : Number(form.termsDays.trim()),
    track1099: form.track1099,
  };
}

function VendorPanel({
  title,
  initial,
  showActiveToggle,
  onCancel,
  onSave,
}: {
  title: string;
  initial: VendorFormState;
  showActiveToggle: boolean;
  onCancel: () => void;
  onSave: (form: VendorFormState) => Promise<void>;
}) {
  const [form, setForm] = useState<VendorFormState>(initial);
  const [touched, setTouched] = useState(false);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const validationError = touched ? validateForm(form) : null;

  async function handleSave() {
    setTouched(true);
    const err = validateForm(form);
    if (err) return;
    setSaving(true);
    setError(null);
    try {
      await onSave(form);
    } catch (e) {
      setError(e instanceof ApiError ? e.message : "Couldn't save that vendor. Try again.");
    } finally {
      setSaving(false);
    }
  }

  return (
    <div className="card" style={{ marginBottom: 18, maxWidth: 480 }}>
      <h2>{title}</h2>
      {error && <ErrorBanner message={error} onRetry={() => void handleSave()} />}

      <div className="field">
        <label htmlFor="vend-name">Name</label>
        <input
          id="vend-name"
          className="text-input"
          type="text"
          value={form.name}
          onChange={(ev) => setForm((f) => ({ ...f, name: ev.target.value }))}
        />
      </div>
      <div className="field">
        <label htmlFor="vend-email">Email (optional)</label>
        <input
          id="vend-email"
          className="text-input"
          type="text"
          value={form.email}
          onChange={(ev) => setForm((f) => ({ ...f, email: ev.target.value }))}
        />
      </div>
      <div className="field">
        <label htmlFor="vend-phone">Phone (optional)</label>
        <input
          id="vend-phone"
          className="text-input"
          type="text"
          value={form.phone}
          onChange={(ev) => setForm((f) => ({ ...f, phone: ev.target.value }))}
        />
      </div>
      <div className="field">
        <label htmlFor="vend-address">Address (optional)</label>
        <input
          id="vend-address"
          className="text-input"
          type="text"
          value={form.address}
          onChange={(ev) => setForm((f) => ({ ...f, address: ev.target.value }))}
        />
      </div>
      <div className="field">
        <label htmlFor="vend-terms">Payment terms (days, optional — default 30)</label>
        <input
          id="vend-terms"
          className="text-input"
          type="text"
          inputMode="numeric"
          value={form.termsDays}
          onChange={(ev) => setForm((f) => ({ ...f, termsDays: ev.target.value }))}
        />
      </div>
      <label className="field" style={{ flexDirection: "row", alignItems: "center", gap: 8 }}>
        <input
          type="checkbox"
          checked={form.track1099}
          onChange={(ev) => setForm((f) => ({ ...f, track1099: ev.target.checked }))}
        />
        <span>Track for 1099 reporting</span>
      </label>
      {showActiveToggle && (
        <label className="field" style={{ flexDirection: "row", alignItems: "center", gap: 8 }}>
          <input
            type="checkbox"
            checked={form.active}
            onChange={(ev) => setForm((f) => ({ ...f, active: ev.target.checked }))}
          />
          <span>Active</span>
        </label>
      )}
      {validationError && <p className="field-error">{validationError}</p>}

      <div className="wizard-actions">
        <button type="button" className="btn" disabled={saving} onClick={() => void handleSave()}>
          {saving ? "Saving…" : "Save"}
        </button>
        <button type="button" className="acct-link" disabled={saving} onClick={onCancel}>
          Cancel
        </button>
      </div>
    </div>
  );
}

type PanelState = { open: false } | { open: true; vendor: VendorRow | null };

export function VendorsScreen({ navigate }: { navigate: (target: NavTarget) => void }) {
  const { selectedCompanyId } = useCompany();
  const { data, loading, error, retry } = useApiGet<VendorRow[]>("/api/c/vendors", selectedCompanyId);
  const [panel, setPanel] = useState<PanelState>({ open: false });

  async function handleCreate(form: VendorFormState) {
    if (!selectedCompanyId) return;
    await apiPost("/api/c/vendors", buildBody(form), selectedCompanyId);
    setPanel({ open: false });
    retry();
  }

  async function handleUpdate(id: string, form: VendorFormState) {
    if (!selectedCompanyId) return;
    await apiPatch(`/api/c/vendors/${id}`, { ...buildBody(form), active: form.active }, selectedCompanyId);
    setPanel({ open: false });
    retry();
  }

  function goToVendorBills(vendorId: string) {
    setPendingVendorFilter(vendorId);
    navigate("bills");
  }

  return (
    <div className="wrap">
      <header className="top">
        <h1>Vendors</h1>
        {!panel.open && (
          <button type="button" className="btn" onClick={() => setPanel({ open: true, vendor: null })}>
            Add vendor
          </button>
        )}
      </header>

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

      {panel.open && (
        <VendorPanel
          title={panel.vendor ? `Edit ${panel.vendor.name}` : "Add a vendor"}
          initial={panel.vendor ? toFormState(panel.vendor) : BLANK_FORM}
          showActiveToggle={panel.vendor !== null}
          onCancel={() => setPanel({ open: false })}
          onSave={(form) => (panel.vendor ? handleUpdate(panel.vendor.id, form) : handleCreate(form))}
        />
      )}

      {data && data.length === 0 && !panel.open && (
        <div className="empty-state">No vendors yet. Add your first one to start entering bills.</div>
      )}

      {data && data.length > 0 && (
        <table>
          <thead>
            <tr>
              <th>Name</th>
              <th>Contact</th>
              <th>Terms</th>
              <th>1099</th>
              <th className="num">Balance</th>
              <th>Oldest due</th>
            </tr>
          </thead>
          <tbody>
            {data.map((v) => (
              <tr
                key={v.id}
                style={{ cursor: "pointer", opacity: v.active ? 1 : 0.6 }}
                onClick={() => setPanel({ open: true, vendor: v })}
              >
                <td>
                  {v.name}
                  {!v.active && " (inactive)"}
                </td>
                <td>{[v.email, v.phone].filter(Boolean).join(" · ") || "—"}</td>
                <td>Net {v.termsDays}</td>
                <td>{v.track1099 ? "Yes" : "—"}</td>
                <td className="num">
                  {isZeroMoney(v.balance) ? (
                    fmtMoney(v.balance)
                  ) : (
                    <button
                      type="button"
                      className="acct-link"
                      onClick={(ev) => {
                        ev.stopPropagation();
                        goToVendorBills(v.id);
                      }}
                    >
                      {fmtMoney(v.balance)}
                    </button>
                  )}
                </td>
                <td>{v.oldestOpenDueDate ? fmtDate(v.oldestOpenDueDate) : "—"}</td>
              </tr>
            ))}
          </tbody>
        </table>
      )}
    </div>
  );
}
