// @vitest-environment happy-dom
// Pure prop-driven component; match the act() convention used by the
// other ClaimDrawer test files (ClaimDrawerHeader / ClaimDrawerSkeleton /
// ClaimDrawerError / ValidationPanel / ServiceLinesTable / DiagnosesList
// / PartiesGrid / RawSegmentsPanel).
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;

import React, { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { describe, expect, it, vi } from "vitest";
import { MatchedRemitCard } from "./MatchedRemitCard";
import type { ClaimDetailMatchedRemittance } from "@/types";

function renderIntoContainer(element: React.ReactElement): {
  container: HTMLDivElement;
  unmount: () => void;
} {
  const container = document.createElement("div");
  document.body.appendChild(container);
  const root: Root = createRoot(container);
  act(() => {
    root.render(element);
  });
  return {
    container,
    unmount: () => {
      act(() => root.unmount());
      container.remove();
    },
  };
}

function makeMatchedRemittance(
  overrides: Partial<ClaimDetailMatchedRemittance> = {}
): ClaimDetailMatchedRemittance {
  return {
    id: "REM-2026-0001",
    totalPaid: 142.5,
    status: "received",
    receivedAt: "2026-06-12T10:00:00Z",
    ...overrides,
  };
}

describe("MatchedRemitCard", () => {
  it("test_null_prop_returns_no_dom", () => {
    const { container, unmount } = renderIntoContainer(
      <MatchedRemitCard matchedRemittance={null} />
    );

    // No DOM at all — the component returns null before rendering.
    expect(container.innerHTML).toBe("");

    unmount();
  });

  it("test_populated_prop_renders_section_label", () => {
    const { container, unmount } = renderIntoContainer(
      <MatchedRemitCard matchedRemittance={makeMatchedRemittance()} />
    );

    const label = container.querySelector('[data-testid="section-label"]');
    expect(label).not.toBeNull();

    // `uppercase` is applied via Tailwind CSS, so textContent gives the
    // source-case string "Matched Remittance"; assert case-insensitively
    // and confirm the visual transform via the className sniff below.
    const text = (label?.textContent ?? "").toLowerCase();
    expect(text).toContain("matched remittance");

    // Eyebrow style (uppercase + tracking) — sniff the className.
    // The shared `.eyebrow` class in index.css consolidates the
    // eyebrow treatment; tests assert it lands on the section label.
    const cls = label?.className ?? "";
    expect(cls).toContain("eyebrow");

    unmount();
  });

  it("test_renders_id_totalPaid_status_and_receivedAt", () => {
    const { container, unmount } = renderIntoContainer(
      <MatchedRemitCard
        matchedRemittance={makeMatchedRemittance({
          id: "REM-2026-9999",
          totalPaid: 250.0,
          status: "reconciled",
          receivedAt: "2026-06-10T14:30:00Z",
        })}
      />
    );

    // Remit ID rendered in mono.
    const idEl = container.querySelector('[data-testid="matched-remit-id"]');
    expect(idEl).not.toBeNull();
    expect(idEl?.textContent ?? "").toContain("REM-2026-9999");

    // totalPaid formatted via fmt.usdPrecise → "$250.00".
    const totalPaidEl = container.querySelector(
      '[data-testid="matched-remit-total-paid"]'
    );
    expect(totalPaidEl).not.toBeNull();
    expect(totalPaidEl?.textContent ?? "").toContain("$250.00");

    // Status badge.
    const statusEl = container.querySelector(
      '[data-testid="matched-remit-status"]'
    );
    expect(statusEl).not.toBeNull();
    expect(statusEl?.textContent ?? "").toContain("reconciled");

    // receivedAt formatted via fmt.date — the date contains the year at
    // minimum, and `new Date("ISO Z")` is UTC-stable.
    const receivedEl = container.querySelector(
      '[data-testid="matched-remit-received"]'
    );
    expect(receivedEl).not.toBeNull();
    expect(receivedEl?.textContent ?? "").toContain("2026");

    unmount();
  });

  it("test_status_badge_uses_danger_variant_for_rejected_status", () => {
    // The remittance status field is an unconstrained string (per
    // `ClaimDetailMatchedRemittance`), so unknown statuses should fall
    // back to the muted variant rather than throwing.
    const { container, unmount } = renderIntoContainer(
      <MatchedRemitCard
        matchedRemittance={makeMatchedRemittance({ status: "weird" })}
      />
    );

    const statusEl = container.querySelector(
      '[data-testid="matched-remit-status"]'
    );
    expect(statusEl).not.toBeNull();
    // Muted variant (no color) — the badge still renders without error.
    expect(statusEl?.textContent ?? "").toContain("weird");

    unmount();
  });

  it("test_full_match_badge_renders_when_matchedLines_equals_totalLines", () => {
    const { container, unmount } = renderIntoContainer(
      <MatchedRemitCard
        matchedRemittance={makeMatchedRemittance({
          matchedLines: 4,
          totalLines: 4,
        })}
      />
    );
    const badge = container.querySelector(
      '[data-testid="matched-remit-line-counts"]'
    );
    expect(badge).not.toBeNull();
    expect(badge?.textContent ?? "").toMatch(/4\/4 matched/);
    expect(badge?.getAttribute("data-all-matched")).toBe("true");
    unmount();
  });

  it("test_partial_match_badge_renders_unmatched_count", () => {
    const { container, unmount } = renderIntoContainer(
      <MatchedRemitCard
        matchedRemittance={makeMatchedRemittance({
          matchedLines: 3,
          totalLines: 4,
        })}
      />
    );
    const badge = container.querySelector(
      '[data-testid="matched-remit-line-counts"]'
    );
    expect(badge).not.toBeNull();
    expect(badge?.textContent ?? "").toMatch(/3\/4 matched/);
    expect(badge?.textContent ?? "").toMatch(/1 unmatched/);
    expect(badge?.getAttribute("data-all-matched")).toBe("false");
    unmount();
  });

  it("test_badge_omitted_when_line_counts_undefined", () => {
    // Backward compatibility: pre-SP7 claim-detail responses don't
    // include matchedLines / totalLines. The card should still render
    // without the badge.
    const { container, unmount } = renderIntoContainer(
      <MatchedRemitCard
        matchedRemittance={makeMatchedRemittance({
          matchedLines: undefined,
          totalLines: undefined,
        })}
      />
    );
    expect(
      container.querySelector('[data-testid="matched-remit-line-counts"]')
    ).toBeNull();
    unmount();
  });

  it("test_view_remittance_link_sets_window_location_href", () => {
    // Spy on the `href` setter so the click doesn't actually navigate
    // away in the test runner, and so we can assert what was assigned.
    const setHrefSpy = vi.spyOn(window.location, "href", "set");
    setHrefSpy.mockImplementation(() => {
      // No-op — happy-dom would otherwise try to update the URL.
    });

    try {
      const { container, unmount } = renderIntoContainer(
        <MatchedRemitCard
          matchedRemittance={makeMatchedRemittance({ id: "REM-XYZ" })}
        />
      );

      const link = container.querySelector(
        '[data-testid="view-remittance-link"]'
      );
      expect(link).not.toBeNull();
      // The button should advertise the destination via the visible label.
      expect(link?.textContent ?? "").toContain("View remittance");

      act(() => {
        link?.dispatchEvent(
          new MouseEvent("click", { bubbles: true, cancelable: true })
        );
      });

      // The click handler should have assigned to window.location.href
      // exactly once, with the remittance-detail deep link.
      expect(setHrefSpy).toHaveBeenCalledTimes(1);
      expect(setHrefSpy).toHaveBeenCalledWith("/remittances?id=REM-XYZ");

      unmount();
    } finally {
      setHrefSpy.mockRestore();
    }
  });
});
