// @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).
(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 } from "vitest";
import { PartiesGrid } from "./PartiesGrid";
import type {
  ClaimDetailAddress,
  ClaimDetailParties,
} 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 makeAddress(
  overrides: Partial<ClaimDetailAddress> = {}
): ClaimDetailAddress {
  return {
    line1: "100 Main St",
    line2: null,
    city: "Springfield",
    state: "IL",
    zip: "62701",
    ...overrides,
  };
}

function makeParties(
  overrides: Partial<ClaimDetailParties> = {}
): ClaimDetailParties {
  return {
    billingProvider: {
      name: "Acme Medical Group",
      npi: "1234567890",
      taxId: "12-3456789",
      address: makeAddress(),
    },
    subscriber: {
      firstName: "Jane",
      lastName: "Doe",
      memberId: "MEM12345",
      dob: "1980-05-15",
      gender: "F",
    },
    payer: {
      name: "Aetna",
      id: "PAYER01",
    },
    ...overrides,
  };
}

describe("PartiesGrid", () => {
  it("test_section_label_is_parties", () => {
    const { container, unmount } = renderIntoContainer(
      <PartiesGrid parties={makeParties()} />
    );

    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 "Parties"; assert case-insensitively and
    // confirm the visual transform via the className sniff below.
    const text = (label?.textContent ?? "").toLowerCase();
    expect(text).toContain("parties");

    // Eyebrow style (uppercase + tracking) — sniff the className.
    const cls = label?.className ?? "";
    expect(cls).toContain("uppercase");
    expect(cls).toContain("tracking-[0.18em]");

    unmount();
  });

  it("test_three_cards_rendered_for_each_party", () => {
    const { container, unmount } = renderIntoContainer(
      <PartiesGrid parties={makeParties()} />
    );

    const billing = container.querySelector('[data-testid="party-billing-provider"]');
    const subscriber = container.querySelector('[data-testid="party-subscriber"]');
    const payer = container.querySelector('[data-testid="party-payer"]');

    expect(billing).not.toBeNull();
    expect(subscriber).not.toBeNull();
    expect(payer).not.toBeNull();

    unmount();
  });

  it("test_billing_provider_card_shows_name_npi_taxId_and_address", () => {
    const { container, unmount } = renderIntoContainer(
      <PartiesGrid parties={makeParties()} />
    );

    const card = container.querySelector(
      '[data-testid="party-billing-provider"]'
    );
    expect(card).not.toBeNull();

    const text = card?.textContent ?? "";
    expect(text).toContain("Acme Medical Group");
    expect(text).toContain("1234567890");
    expect(text).toContain("12-3456789");
    // Address components.
    expect(text).toContain("100 Main St");
    expect(text).toContain("Springfield");
    expect(text).toContain("IL");
    expect(text).toContain("62701");

    unmount();
  });

  it("test_subscriber_card_shows_first_last_memberId_and_gender", () => {
    const { container, unmount } = renderIntoContainer(
      <PartiesGrid parties={makeParties()} />
    );

    const card = container.querySelector('[data-testid="party-subscriber"]');
    expect(card).not.toBeNull();

    const text = card?.textContent ?? "";
    expect(text).toContain("Jane");
    expect(text).toContain("Doe");
    expect(text).toContain("MEM12345");
    expect(text).toContain("F");
    // DOB is also present in this fixture.
    expect(text).toContain("1980");

    unmount();
  });

  it("test_subscriber_card_omits_dob_when_null", () => {
    const { container, unmount } = renderIntoContainer(
      <PartiesGrid
        parties={makeParties({
          subscriber: {
            firstName: "John",
            lastName: "Smith",
            memberId: "MEM99999",
            dob: null,
            gender: "M",
          },
        })}
      />
    );

    const card = container.querySelector('[data-testid="party-subscriber"]');
    expect(card).not.toBeNull();

    const text = (card?.textContent ?? "").toLowerCase();
    // Still renders the identity pieces.
    expect(text).toContain("john");
    expect(text).toContain("smith");
    expect(text).toContain("mem99999");
    expect(text).toContain("m");
    // No "undefined" or "null" stringification for the absent DOB.
    expect(text).not.toContain("undefined");
    expect(text).not.toContain("null");

    unmount();
  });

  it("test_payer_card_shows_name_and_id", () => {
    const { container, unmount } = renderIntoContainer(
      <PartiesGrid parties={makeParties()} />
    );

    const card = container.querySelector('[data-testid="party-payer"]');
    expect(card).not.toBeNull();

    const text = card?.textContent ?? "";
    expect(text).toContain("Aetna");
    expect(text).toContain("PAYER01");

    unmount();
  });

  it("test_billing_provider_address_line2_rendered_when_present", () => {
    const { container, unmount } = renderIntoContainer(
      <PartiesGrid
        parties={makeParties({
          billingProvider: {
            name: "Suite Clinic",
            npi: "1111111111",
            taxId: "99-9999999",
            address: makeAddress({
              line1: "200 Oak Ave",
              line2: "Suite 300",
              city: "Portland",
              state: "OR",
              zip: "97201",
            }),
          },
        })}
      />
    );

    const card = container.querySelector(
      '[data-testid="party-billing-provider"]'
    );
    const text = card?.textContent ?? "";
    expect(text).toContain("200 Oak Ave");
    expect(text).toContain("Suite 300");
    expect(text).toContain("Portland");
    expect(text).toContain("OR");
    expect(text).toContain("97201");

    unmount();
  });

  it("test_empty_address_object_does_not_render_garbage", () => {
    // The backend can return `{}` for a missing address (per the
    // ClaimDetailBillingProvider type's `Record<string, never>` branch).
    // The component must not stringify an empty object.
    const { container, unmount } = renderIntoContainer(
      <PartiesGrid
        parties={makeParties({
          billingProvider: {
            name: "Addrless Clinic",
            npi: "2222222222",
            taxId: "11-1111111",
            address: {},
          },
        })}
      />
    );

    const card = container.querySelector(
      '[data-testid="party-billing-provider"]'
    );
    const text = (card?.textContent ?? "").toLowerCase();
    expect(text).toContain("addrless clinic");
    expect(text).toContain("2222222222");
    expect(text).not.toContain("[object object]");
    expect(text).not.toContain("undefined");
    expect(text).not.toContain("null");

    unmount();
  });

  it("test_responsive_grid_uses_3_columns_on_desktop", () => {
    const { container, unmount } = renderIntoContainer(
      <PartiesGrid parties={makeParties()} />
    );

    // The section follows the established `flex flex-col gap-3 px-6 py-4`
    // pattern; the responsive grid is the inner wrapper that holds the
    // three party cards. Sniff its className.
    const grid = container.querySelector('[data-testid="parties-grid-inner"]');
    expect(grid).not.toBeNull();
    const cls = grid?.className ?? "";
    expect(cls).toContain("grid");
    expect(cls).toContain("grid-cols-1");
    expect(cls).toContain("md:grid-cols-3");
    expect(cls).toContain("gap-4");

    unmount();
  });
});
