// @vitest-environment happy-dom
import { describe, expect, it, vi } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import { InboxRow } from "./InboxRow";
import type { InboxClaimRow, InboxCandidateRow } from "@/lib/inbox-api";

const baseClaim: InboxClaimRow = {
  id: "CLP-7741",
  kind: "claim",
  patient_control_number: "PCN-001",
  charge_amount: 1240,
  payer_id: "CO-MCD",
  provider_npi: "1234567890",
  state: "rejected",
  rejection_reason: "999 AK9 R",
  rejected_at: "2026-06-20T09:12:00Z",
  service_date_from: null,
  score: null,
  score_tier: null,
  score_breakdown: null,
};

describe("InboxRow", () => {
  it("renders the claim id, payer, and formatted charge", () => {
    const { container } = render(
      <table>
        <tbody>
          <InboxRow row={baseClaim} accent="oxblood" onClick={() => {}} />
        </tbody>
      </table>,
    );
    expect(container.textContent).toContain("CLP-7741");
    expect(container.textContent).toContain("CO-MCD");
    expect(container.textContent).toContain("$1,240.00");
  });

  it("renders the rejection reason when present", () => {
    const { container } = render(
      <table>
        <tbody>
          <InboxRow row={baseClaim} accent="oxblood" onClick={() => {}} />
        </tbody>
      </table>,
    );
    expect(container.textContent).toContain("999 AK9 R");
  });

  it("calls onClick when the row is clicked", () => {
    const onClick = vi.fn();
    const { container } = render(
      <table>
        <tbody>
          <InboxRow row={baseClaim} accent="oxblood" onClick={onClick} />
        </tbody>
      </table>,
    );
    const row = container.querySelector("tr");
    expect(row).not.toBeNull();
    fireEvent.click(row!);
    expect(onClick).toHaveBeenCalledOnce();
  });

  it("renders the top candidate score for remit rows", () => {
    const candidateRow: InboxCandidateRow = {
      id: "R-1",
      kind: "remit",
      payer_claim_control_number: "PCN-X",
      charge_amount: 500,
      payer_id: "AETNA",
      rendering_provider_npi: "1234567890",
      service_date: null,
      candidates: [
        {
          claim_id: "C-1",
          score: 92,
          tier: "strong",
          breakdown: { patient: 1, date: 1, amount: 1, provider: 1 },
        },
      ],
    };
    const { container } = render(
      <table>
        <tbody>
          <InboxRow row={candidateRow} accent="amber" onClick={() => {}} />
        </tbody>
      </table>,
    );
    expect(container.textContent).toContain("92");
  });

  // ---------------------------------------------------------------------
  // SP29: per-AK2 chip evidence + per-row Resubmit gesture for the
  // rejected-lane drill. The page renders 999 AK2 set-response codes
  // inline on the row so the operator can spot "this batch had R/E/X
  // rejects" without opening the drawer. The per-row Resubmit button
  // downloads a single corrected 837.
  // ---------------------------------------------------------------------
  it("SP29: rejected row renders inline 999 ack evidence chips + Resubmit button", () => {
    // 4 linked 999 AK2 set-responses — 3 will render as chips, the
    // 4th triggers the "+N more" overflow indicator.
    const rejectedRow: InboxClaimRow = {
      ...baseClaim,
      id: "REJ1",
      claim_acks: {
        total: 4,
        rejected: 2,
        items: [
          {
            ack_id: 11,
            set_control_number: "991102989",
            set_accept_reject_code: "A",
            ak2_index: 0,
            linked_at: "2026-07-02T10:03:00Z",
          },
          {
            ack_id: 12,
            set_control_number: "991102989",
            set_accept_reject_code: "R",
            ak2_index: 1,
            linked_at: "2026-07-02T10:02:00Z",
          },
          {
            ack_id: 13,
            set_control_number: "991102989",
            set_accept_reject_code: "E",
            ak2_index: 2,
            linked_at: "2026-07-02T10:01:00Z",
          },
        ],
      },
    };
    const onResubmitOne = vi.fn();
    const { container } = render(
      <table>
        <tbody>
          <InboxRow
            row={rejectedRow}
            accent="oxblood"
            onClick={() => {}}
            onResubmitOne={onResubmitOne}
          />
        </tbody>
      </table>,
    );

    // Chip visible — the operator can read at a glance that the most
    // recent AK2 from this batch was an Accept, then a Reject, then
    // an Error. The "999 · A" / "999 · R" / "999 · E" text comes from
    // <AckCodeChip> rendering "<stcn>·<code>".
    expect(container.textContent).toContain("991102989·A");
    expect(container.textContent).toContain("991102989·R");
    expect(container.textContent).toContain("991102989·E");

    // Overflow "+1 more" — total=4 but only 3 chips fit.
    expect(container.textContent).toContain("+1 more");

    // Resubmit button rendered with the per-row testid.
    const btn = screen.getByTestId("resubmit-REJ1") as HTMLButtonElement;
    expect(btn).toBeTruthy();
    expect(btn.textContent).toBe("Resubmit");

    // Click fires the per-row handler with the claim id; click does
    // NOT bubble to onClick (the row-onClick is for drilldown, the
    // button is a separate download gesture).
    fireEvent.click(btn);
    expect(onResubmitOne).toHaveBeenCalledTimes(1);
    expect(onResubmitOne).toHaveBeenCalledWith("REJ1");
  });

  it("SP29: rejected row with no linked 999 acks shows the '999 not linked' orphan marker", () => {
    // A rejected claim whose 999 ack didn't match any ST02 in the
    // batch — the operator needs to know the drill lacked ack
    // evidence. The "999 not linked" italic line is the marker.
    const rejectedRow: InboxClaimRow = {
      ...baseClaim,
      id: "REJ-ORPH",
      claim_acks: {
        total: 0,
        rejected: 0,
        items: [],
      },
    };
    const onResubmitOne = vi.fn();
    const { container } = render(
      <table>
        <tbody>
          <InboxRow
            row={rejectedRow}
            accent="oxblood"
            onClick={() => {}}
            onResubmitOne={onResubmitOne}
          />
        </tbody>
      </table>,
    );
    expect(container.textContent).toContain("999 not linked");
    // The Resubmit button still renders so the operator can fix the
    // claim without first manually linking the orphan.
    expect(screen.getByTestId("resubmit-REJ-ORPH")).toBeTruthy();
  });
});
