import { render } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import { HpoVisualizer } from "../HpoVisualizer";
import type { OrganId } from "../types";

describe("HpoVisualizer rendering order", () => {
  /**
   * Helper function to get rendered organ IDs in DOM order.
   * OrganSvg elements are now <g> elements with aria-label attribute.
   * Only includes visible organs (opacity !== 0).
   */
  const getRenderedOrganOrder = (container: HTMLElement): string[] => {
    // Find all OrganSvg elements (they are <g> elements with aria-label)
    const organElements = container.querySelectorAll("g[aria-label]");
    return Array.from(organElements)
      .filter((el) => {
        // Filter out hidden organs (opacity: 0)
        // OrganSvg sets opacity as an attribute, not a style property
        const opacity = el.getAttribute("opacity");
        return opacity !== "0";
      })
      .map((el) => el.getAttribute("aria-label") || "");
  };

  it("should render organs in ORGAN_POSITIONS key order regardless of organs array order", () => {
    // Provide organs in reverse alphabetical order
    const organs: { id: OrganId }[] = [
      { id: "voice" },
      { id: "thoracicCavity" },
      { id: "lung" },
      { id: "heart" },
      { id: "head" },
      { id: "eye" },
      { id: "ear" },
    ];

    const { container } = render(<HpoVisualizer organs={organs} />);

    const renderedOrder = getRenderedOrganOrder(container);

    // ORGAN_RENDER_ORDER starts with thoracicCavity -> lung -> ... -> head -> eye -> ear -> voice
    // Expected order should follow ORGAN_RENDER_ORDER for the given organs
    expect(renderedOrder).toEqual([
      "thoracicCavity",
      "lung",
      "heart",
      "head",
      "eye",
      "ear",
      "voice",
    ]);
  });

  it("should render selectedOrgan after other organs to appear on top", () => {
    const organs: { id: OrganId }[] = [
      { id: "head" },
      { id: "eye" },
      { id: "ear" },
      { id: "lung" },
      { id: "heart" },
    ];

    // Select 'head'
    const { container } = render(<HpoVisualizer organs={organs} selectedOrgan="head" />);

    const renderedOrder = getRenderedOrganOrder(container);
    // 'head' should be rendered last since it's selected
    expect(renderedOrder.at(-1)).toBe("head");
  });

  it("should render selectedOrgan last even when it would normally be in the middle", () => {
    const organs: { id: OrganId }[] = [
      { id: "head" },
      { id: "lung" },
      { id: "heart" },
      { id: "digestive" },
      { id: "kidney" },
    ];

    // Select 'heart' which is in the middle of ORGAN_POSITIONS order
    const { container } = render(<HpoVisualizer organs={organs} selectedOrgan="heart" />);

    const renderedOrder = getRenderedOrganOrder(container);
    expect(renderedOrder.at(-1)).toBe("heart");
    expect(renderedOrder.slice(0, -1)).toEqual(["lung", "digestive", "kidney", "head"]);
  });

  it("should render selected organ last while preserving order for others", () => {
    const organs: { id: OrganId }[] = [{ id: "head" }, { id: "eye" }, { id: "ear" }];

    const { container } = render(<HpoVisualizer organs={organs} selectedOrgan="eye" />);

    const renderedOrder = getRenderedOrganOrder(container);

    expect(renderedOrder).toEqual(["head", "ear", "eye"]);
  });

  it("should not render selectedOrgan if it is not in organs array", () => {
    const organs: { id: OrganId }[] = [{ id: "head" }, { id: "eye" }];

    // Select 'heart' which is not in the organs array
    const { container } = render(<HpoVisualizer organs={organs} selectedOrgan="heart" />);

    const renderedOrder = getRenderedOrganOrder(container);

    // 'heart' should not be rendered since it's not in the organs array
    expect(renderedOrder).toEqual(["head", "eye"]);
    expect(renderedOrder).not.toContain("heart");
  });

  it("should maintain correct order with visibleOrgans prop", () => {
    // Using visibleOrgans instead of organs
    const visibleOrgans: OrganId[] = ["kidney", "heart", "lung", "head"];

    const { container } = render(<HpoVisualizer visibleOrgans={visibleOrgans} />);

    const renderedOrder = getRenderedOrganOrder(container);

    // Should follow ORGAN_RENDER_ORDER: lung, heart, kidney, head
    expect(renderedOrder).toEqual(["lung", "heart", "kidney", "head"]);
  });

  it("should return deselected organ to normal order immediately", () => {
    const organs: { id: OrganId }[] = [{ id: "head" }, { id: "eye" }, { id: "ear" }];
    const { container, rerender } = render(<HpoVisualizer organs={organs} selectedOrgan="eye" />);

    expect(getRenderedOrganOrder(container)).toEqual(["head", "ear", "eye"]);

    rerender(<HpoVisualizer organs={organs} selectedOrgan={null} />);

    expect(getRenderedOrganOrder(container)).toEqual(["head", "eye", "ear"]);
  });
});
