import { describe, it, expect, vi } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import { filterVendors, vendorLabel, VendorSelect, type VendorOption } from "@/components/ui/vendor-select";

const VENDORS: VendorOption[] = [
  { id: "1", name: "Acme Marine Supplies", vendorId: "V-1001" },
  { id: "2", name: "Bluewater Engineering", vendorId: "V-2002" },
  { id: "3", name: "Coastal Spares", vendorId: null }, // unverified — no code
  { id: "4", name: "Delta Pumps", vendorId: "ACME-99" },
];

// ── Pure filter logic ─────────────────────────────────────────────────────────

describe("filterVendors", () => {
  it("returns all vendors for an empty query", () => {
    expect(filterVendors(VENDORS, "")).toHaveLength(4);
  });

  it("returns all vendors for a whitespace-only query", () => {
    expect(filterVendors(VENDORS, "   ")).toHaveLength(4);
  });

  it("matches by name (case-insensitive)", () => {
    const res = filterVendors(VENDORS, "bluewater");
    expect(res.map((v) => v.id)).toEqual(["2"]);
  });

  it("matches by code (vendorId), case-insensitive", () => {
    const res = filterVendors(VENDORS, "v-2002");
    expect(res.map((v) => v.id)).toEqual(["2"]);
  });

  it("matches on a code substring even when the name does not contain it", () => {
    // "acme" appears in vendor #1's name AND in vendor #4's code (ACME-99)
    const res = filterVendors(VENDORS, "acme");
    expect(res.map((v) => v.id).sort()).toEqual(["1", "4"]);
  });

  it("finds an unverified vendor (null code) by name only", () => {
    expect(filterVendors(VENDORS, "coastal").map((v) => v.id)).toEqual(["3"]);
    // ...and never crashes on the null code
    expect(filterVendors(VENDORS, "9999")).toHaveLength(0);
  });

  it("returns no matches for an unrelated query", () => {
    expect(filterVendors(VENDORS, "zzz")).toHaveLength(0);
  });
});

describe("vendorLabel", () => {
  it("formats a verified vendor as name (CODE)", () => {
    expect(vendorLabel(VENDORS[0])).toBe("Acme Marine Supplies (V-1001)");
  });
  it("formats an unverified vendor as name (unverified)", () => {
    expect(vendorLabel(VENDORS[2])).toBe("Coastal Spares (unverified)");
  });
});

// ── Component behaviour ───────────────────────────────────────────────────────

describe("VendorSelect", () => {
  it("posts a hidden vendorId input with the empty default", () => {
    const { container } = render(<VendorSelect name="vendorId" vendors={VENDORS} />);
    const hidden = container.querySelector('input[name="vendorId"]') as HTMLInputElement;
    expect(hidden).toBeTruthy();
    expect(hidden.value).toBe("");
  });

  it("honours initialValue", () => {
    const { container } = render(<VendorSelect name="vendorId" vendors={VENDORS} initialValue="2" />);
    const hidden = container.querySelector('input[name="vendorId"]') as HTMLInputElement;
    expect(hidden.value).toBe("2");
    // Trigger shows the formatted label
    expect(screen.getByText("Bluewater Engineering (V-2002)")).toBeTruthy();
  });

  it("opens and filters the list by typed query, then selects a vendor", () => {
    const onChange = vi.fn();
    const { container } = render(<VendorSelect name="vendorId" vendors={VENDORS} onChange={onChange} />);
    fireEvent.click(screen.getByRole("button"));
    const search = screen.getByPlaceholderText("Search by name or code…");
    fireEvent.change(search, { target: { value: "v-2002" } });

    // Only the matching vendor option is in the list
    expect(screen.getByText("Bluewater Engineering")).toBeTruthy();
    expect(screen.queryByText("Acme Marine Supplies")).toBeNull();

    fireEvent.mouseDown(screen.getByText("Bluewater Engineering"));
    expect(onChange).toHaveBeenCalledWith("2");
    const hidden = container.querySelector('input[name="vendorId"]') as HTMLInputElement;
    expect(hidden.value).toBe("2");
  });

  it("keeps 'No vendor selected' selectable to clear the choice", () => {
    const onChange = vi.fn();
    const { container } = render(
      <VendorSelect name="vendorId" vendors={VENDORS} initialValue="1" onChange={onChange} />
    );
    // The trigger shows the current selection's label; click it to open.
    fireEvent.click(screen.getByText("Acme Marine Supplies (V-1001)"));
    // The empty option is always present, even before typing
    fireEvent.mouseDown(screen.getByText("No vendor selected"));
    expect(onChange).toHaveBeenLastCalledWith("");
    const hidden = container.querySelector('input[name="vendorId"]') as HTMLInputElement;
    expect(hidden.value).toBe("");
  });

  it("shows an empty-state message when nothing matches", () => {
    render(<VendorSelect name="vendorId" vendors={VENDORS} />);
    fireEvent.click(screen.getByRole("button"));
    fireEvent.change(screen.getByPlaceholderText("Search by name or code…"), {
      target: { value: "zzz" },
    });
    expect(screen.getByText(/No vendors match/)).toBeTruthy();
  });
});
