import { describe, expect, it, vi } from "vitest";
import {
  buildOrgChartModel,
  createOrgContextClient,
  type OrgContextResponse,
  renderOrgChart,
  renderOrgPicker,
} from "./index";

const sampleOrgContext: OrgContextResponse = {
  schemaVersion: "baron.org-context.v1",
  issuedAt: "2026-05-15T00:00:00Z",
  scope: {
    tenantId: "root",
    tenantSlug: "hanmac-family",
  },
  tree: {
    id: "root",
    type: "COMPANY_GROUP",
    name: "한맥가족",
    slug: "hanmac-family",
    status: "active",
    description: "",
    domains: [],
    memberCount: 0,
    visibility: "public",
    createdAt: "2026-05-15T00:00:00Z",
    updatedAt: "2026-05-15T00:00:00Z",
    members: [],
    children: [
      {
        id: "company-baron",
        type: "COMPANY",
        name: "Baron",
        slug: "baron",
        parentId: "root",
        status: "active",
        description: "",
        domains: ["baron.example"],
        memberCount: 1,
        visibility: "public",
        createdAt: "2026-05-15T00:00:00Z",
        updatedAt: "2026-05-15T00:00:00Z",
        members: [
          {
            email: "leader@example.com",
            name: "Leader",
            grade: "책임",
            position: "팀장",
            isLeader: true,
            isOwner: true,
            isPrimary: true,
          },
        ],
        children: [
          {
            id: "team-platform",
            type: "USER_GROUP",
            name: "Platform",
            slug: "platform",
            parentId: "company-baron",
            status: "active",
            description: "",
            domains: [],
            memberCount: 1,
            visibility: "internal",
            orgUnitType: "팀",
            createdAt: "2026-05-15T00:00:00Z",
            updatedAt: "2026-05-15T00:00:00Z",
            members: [
              {
                email: "engineer@example.com",
                name: "Engineer",
                jobTitle: "Frontend Engineer",
                isLeader: false,
                isOwner: false,
                isPrimary: false,
              },
            ],
            children: [],
          },
        ],
      },
    ],
  },
  tenants: [],
};

describe("org-context chart SDK", () => {
  it("builds chart and lookup models from org-context v1", () => {
    const model = buildOrgChartModel(sampleOrgContext);

    expect(model.root.name).toBe("한맥가족");
    expect(model.nodes).toHaveLength(3);
    expect(model.tenantsBySlug.get("platform")?.orgUnitType).toBe("팀");
    expect(model.membersByEmail.get("engineer@example.com")?.tenantIds).toEqual(
      ["team-platform"],
    );
  });

  it("fetches org-context through authenticated API headers", async () => {
    const fetcher = vi.fn(async () => {
      return new Response(JSON.stringify(sampleOrgContext), {
        headers: { "content-type": "application/json" },
        status: 200,
      });
    });
    const client = createOrgContextClient({
      baseUrl: "https://sso.example.com",
      credentials: {
        keyId: "client-id",
        keySecret: "client-secret",
      },
      fetch: fetcher,
    });

    await client.fetchOrgContext({
      tenantSlug: "baron",
      includeUsers: true,
      includeUserIds: false,
    });

    const [url, init] = fetcher.mock.calls[0];
    expect(String(url)).toBe(
      "https://sso.example.com/api/v1/integrations/org-context?tenantSlug=baron&includeUsers=true&includeUserIds=false",
    );
    expect(init.headers).toMatchObject({
      "X-Baron-Key-ID": "client-id",
      "X-Baron-Key-Secret": "client-secret",
    });
  });

  it("renders chart and picker DOM with selection events", () => {
    const model = buildOrgChartModel(sampleOrgContext);
    const chartContainer = document.createElement("div");
    const pickerContainer = document.createElement("div");
    const onChange = vi.fn();

    renderOrgChart(chartContainer, model);
    const picker = renderOrgPicker(pickerContainer, model, {
      mode: "multiple",
      selectable: "both",
      onChange,
    });

    expect(
      chartContainer.querySelectorAll("[data-baron-org-node]"),
    ).toHaveLength(3);
    expect(chartContainer.textContent).toContain("Leader · 팀장 · 조직장");
    const platformCheckbox = pickerContainer.querySelector<HTMLInputElement>(
      'input[value="tenant:team-platform"]',
    );
    expect(platformCheckbox).not.toBeNull();

    platformCheckbox?.click();

    expect(picker.getSelection()).toEqual([
      {
        id: "team-platform",
        name: "Platform",
        type: "tenant",
      },
    ]);
    expect(onChange).toHaveBeenCalledWith([
      {
        id: "team-platform",
        name: "Platform",
        type: "tenant",
      },
    ]);
  });

  it("packages default picker UX and styles with search and descendant selection", () => {
    const model = buildOrgChartModel(sampleOrgContext);
    const pickerContainer = document.createElement("div");
    const onChange = vi.fn();

    const picker = renderOrgPicker(pickerContainer, model, {
      mode: "multiple",
      selectable: "both",
      onChange,
    });

    expect(
      document.head.querySelector(
        'style[data-baron-org-context-chart-style="default"]',
      ),
    ).not.toBeNull();
    expect(
      pickerContainer.querySelector<HTMLInputElement>(
        'input[type="search"][data-baron-org-picker-search]',
      ),
    ).not.toBeNull();
    expect(
      pickerContainer.querySelector<HTMLInputElement>(
        'input[type="checkbox"][data-baron-org-picker-descendants]',
      ),
    ).not.toBeNull();
    expect(
      pickerContainer.querySelector("[data-baron-org-picker-summary]")
        ?.textContent,
    ).toContain("0 selected");

    const search = pickerContainer.querySelector<HTMLInputElement>(
      'input[type="search"][data-baron-org-picker-search]',
    );
    expect(search).not.toBeNull();
    if (!search) return;
    search.value = "platform";
    search.dispatchEvent(new Event("input", { bubbles: true }));

    expect(pickerContainer.textContent).toContain("Platform");
    expect(pickerContainer.textContent).not.toContain(
      "Leader (leader@example.com)",
    );

    search.value = "";
    search.dispatchEvent(new Event("input", { bubbles: true }));

    const descendantToggle = pickerContainer.querySelector<HTMLInputElement>(
      'input[type="checkbox"][data-baron-org-picker-descendants]',
    );
    expect(descendantToggle).not.toBeNull();
    descendantToggle?.click();
    const companyBaron = pickerContainer.querySelector<HTMLInputElement>(
      'input[value="tenant:company-baron"]',
    );
    expect(companyBaron).not.toBeNull();
    companyBaron?.click();

    expect(picker.getSelection()).toEqual([
      { id: "company-baron", name: "Baron", type: "tenant" },
      { id: "team-platform", name: "Platform", type: "tenant" },
      {
        id: "team-platform:engineer@example.com",
        name: "Engineer",
        type: "user",
      },
    ]);
    expect(
      pickerContainer.querySelector("[data-baron-org-picker-summary]")
        ?.textContent,
    ).toContain("3 selected");
    expect(onChange).toHaveBeenLastCalledWith([
      { id: "company-baron", name: "Baron", type: "tenant" },
      { id: "team-platform", name: "Platform", type: "tenant" },
      {
        id: "team-platform:engineer@example.com",
        name: "Engineer",
        type: "user",
      },
    ]);
  });

  it("renders the orgfront-compatible picker UX", () => {
    const model = buildOrgChartModel(sampleOrgContext);
    const pickerContainer = document.createElement("div");
    const onChange = vi.fn();
    const onConfirm = vi.fn();
    const onCancel = vi.fn();

    const picker = renderOrgPicker(pickerContainer, model, {
      mode: "single",
      selectable: "tenant",
      variant: "orgfront",
      showDescendantToggle: false,
      onCancel,
      onChange,
      onConfirm,
    });

    expect(
      pickerContainer.classList.contains("baron-org-picker--orgfront"),
    ).toBe(true);
    expect(
      pickerContainer.querySelector<HTMLInputElement>(
        'input[type="radio"][value="tenant:company-baron"]',
      ),
    ).toBeNull();
    expect(
      pickerContainer.querySelector("[data-baron-org-picker-search-icon]"),
    ).not.toBeNull();
    expect(
      pickerContainer.querySelector<HTMLInputElement>(
        "[data-baron-org-picker-search]",
      )?.placeholder,
    ).toBe("ID, 이름, 이메일, 메타데이터");
    expect(
      pickerContainer.querySelector("[data-baron-org-picker-descendants]"),
    ).toBeNull();
    expect(
      pickerContainer.querySelector("[data-baron-org-picker-footer]"),
    ).not.toBeNull();

    const companyButton = pickerContainer.querySelector<HTMLButtonElement>(
      'button[data-baron-org-picker-value="tenant:company-baron"]',
    );
    expect(companyButton).not.toBeNull();
    companyButton?.click();

    expect(onChange).toHaveBeenCalledWith([
      { id: "company-baron", name: "Baron", type: "tenant" },
    ]);
    expect(picker.getSelection()).toEqual([
      { id: "company-baron", name: "Baron", type: "tenant" },
    ]);

    const collapse = pickerContainer.querySelector<HTMLButtonElement>(
      'button[data-baron-org-picker-toggle="tenant:company-baron"]',
    );
    expect(collapse).not.toBeNull();
    expect(collapse?.textContent).toBe("");
    expect(
      collapse?.querySelector("[data-baron-org-picker-chevron]"),
    ).not.toBeNull();
    collapse?.click();
    const collapsed = pickerContainer.querySelector<HTMLButtonElement>(
      'button[data-baron-org-picker-toggle="tenant:company-baron"]',
    );
    expect(
      collapsed
        ?.querySelector("[data-baron-org-picker-chevron]")
        ?.classList.contains("baron-org-picker__chevron--open"),
    ).toBe(false);
    expect(
      pickerContainer.querySelector(
        'button[data-baron-org-picker-value="tenant:team-platform"]',
      ),
    ).toBeNull();

    const confirm = pickerContainer.querySelector<HTMLButtonElement>(
      "[data-baron-org-picker-confirm]",
    );
    expect(confirm?.disabled).toBe(false);
    confirm?.click();
    expect(onConfirm).toHaveBeenCalledWith([
      { id: "company-baron", name: "Baron", type: "tenant" },
    ]);

    pickerContainer
      .querySelector<HTMLButtonElement>("[data-baron-org-picker-cancel]")
      ?.click();
    expect(onCancel).toHaveBeenCalled();

    picker.destroy();
  });
});
