import { afterEach, describe, expect, it, vi } from "vitest";
import type { TenantSummary } from "../../../lib/adminApi";
import {
  buildTenantImportParentOptionGroups,
  buildTenantImportPreview,
  inferTenantImportRootParentSlug,
  parseTenantCSV,
  serializeTenantImportCSV,
} from "./tenantCsvImport";

const tenants: TenantSummary[] = [
  {
    id: "tenant-1",
    type: "COMPANY",
    name: "Hanmac Technology",
    slug: "hanmac",
    description: "",
    status: "active",
    domains: ["hanmac.example.com"],
    memberCount: 0,
    createdAt: "",
    updatedAt: "",
  },
  {
    id: "tenant-2",
    type: "COMPANY",
    name: "Saman Engineering",
    slug: "saman",
    description: "",
    status: "active",
    domains: [],
    memberCount: 0,
    createdAt: "",
    updatedAt: "",
  },
  {
    id: "tenant-3",
    type: "COMPANY_GROUP",
    name: "Hanmac Family",
    slug: "hanmac-family",
    description: "",
    status: "active",
    domains: [],
    memberCount: 0,
    createdAt: "",
    updatedAt: "",
  },
  {
    id: "tenant-4",
    type: "ORGANIZATION",
    name: "기획부",
    slug: "planning",
    description: "",
    status: "active",
    domains: [],
    memberCount: 0,
    createdAt: "",
    updatedAt: "",
  },
];

describe("tenantCsvImport", () => {
  afterEach(() => {
    vi.unstubAllGlobals();
  });

  it("parses tenant CSV rows with the supported import columns", () => {
    const rows = parseTenantCSV(
      "tenant_id,name,type,parent_tenant_id,slug,memo,email_domain,visibility,org_unit_type\n,Hanmac Tech,COMPANY,,hanmac-tech,Memo,hanmac-tech.example.com,internal,센터\n",
    );

    expect(rows).toEqual([
      {
        rowNumber: 2,
        tenantId: "",
        name: "Hanmac Tech",
        type: "COMPANY",
        parentTenantId: "",
        parentTenantSlug: "",
        slug: "hanmac-tech",
        memo: "Memo",
        emailDomain: "hanmac-tech.example.com",
        visibility: "internal",
        orgUnitType: "센터",
      },
    ]);
  });

  it("puts tenant_id-less rows with exact or similar matches first", () => {
    const rows = parseTenantCSV(
      "tenant_id,name,type,parent_tenant_id,slug,memo,email_domain\n,New Tenant,COMPANY,,new-tenant,,\n,Hanmac Tech,COMPANY,,hanmac-tech,,\n,Saman Engineering,COMPANY,,saman-copy,,\n",
    );

    const preview = buildTenantImportPreview(rows, tenants);

    expect(preview.map((row) => row.row.name)).toEqual([
      "Saman Engineering",
      "Hanmac Tech",
      "New Tenant",
    ]);
    expect(preview[0].candidates[0]).toMatchObject({
      tenantId: "tenant-2",
      reason: "exact_name",
    });
    expect(preview[1].candidates[0]).toMatchObject({
      tenantId: "tenant-1",
      reason: "similar_name",
    });
    expect(preview[2].candidates).toEqual([]);
  });

  it("serializes selected matches by filling tenant_id before upload", () => {
    const rows = parseTenantCSV(
      "tenant_id,name,type,parent_tenant_id,slug,memo,email_domain,visibility,org_unit_type\n,Hanmac Tech,COMPANY,,hanmac-tech,Memo,hanmac-tech.example.com,private,팀\n",
    );
    const preview = buildTenantImportPreview(rows, tenants);
    const csv = serializeTenantImportCSV(preview, {
      2: "tenant-1",
    });

    expect(csv.split("\n")[0]).toBe(
      "tenant_id,name,type,parent_tenant_id,parent_tenant_slug,slug,memo,email_domain,visibility,org_unit_type",
    );
    expect(csv).toContain(
      "tenant-1,Hanmac Tech,COMPANY,,,hanmac-tech,Memo,hanmac-tech.example.com,private,팀",
    );
  });

  it("serializes create resolutions by resetting external tenant id and conflicting slug", () => {
    const rows = parseTenantCSV(
      "tenant_id,name,type,parent_tenant_id,slug,memo,email_domain\nlocal-tenant-id,Hanmac Technology,COMPANY,,hanmac,Memo,hanmac.example.com\n",
    );
    const preview = buildTenantImportPreview(rows, tenants);

    expect(preview[0].conflicts).toEqual(
      expect.arrayContaining(["external_tenant_id", "slug_exists"]),
    );

    const csv = serializeTenantImportCSV(preview, {
      2: {
        mode: "create",
        tenantId: "staging-new-tenant-id",
        slug: "hanmac-imported",
      },
    });

    expect(csv).toContain(
      "staging-new-tenant-id,Hanmac Technology,COMPANY,,,hanmac-imported,Memo,hanmac.example.com",
    );
    expect(csv).not.toContain("local-tenant-id");
  });

  it("remaps child parent_tenant_id from source ids to selected staging ids", () => {
    const rows = parseTenantCSV(
      [
        "tenant_id,name,type,parent_tenant_id,slug,memo,email_domain",
        "local-parent-id,Parent Tenant,COMPANY,,parent-local,,",
        "local-child-id,Child Tenant,ORGANIZATION,local-parent-id,child-local,,",
      ].join("\n"),
    );
    const preview = buildTenantImportPreview(rows, tenants);
    const csv = serializeTenantImportCSV(preview, {
      2: {
        mode: "create",
        tenantId: "staging-parent-id",
        slug: "parent-staging",
      },
      3: {
        mode: "create",
        tenantId: "staging-child-id",
        slug: "child-staging",
      },
    });

    expect(csv).toContain(
      "staging-parent-id,Parent Tenant,COMPANY,,,parent-staging,,",
    );
    expect(csv).toContain(
      "staging-child-id,Child Tenant,ORGANIZATION,staging-parent-id,,child-staging,,",
    );
    expect(csv).not.toContain("local-parent-id");
    expect(csv).not.toContain("local-child-id");
  });

  it("parses parent_tenant_slug and remaps it to selected staging ids", () => {
    const rows = parseTenantCSV(
      [
        "name,type,parent_tenant_slug,slug,memo,email_domain",
        "Parent Tenant,COMPANY,,parent-slug,,",
        "Child Tenant,ORGANIZATION,parent-slug,child-slug,,",
      ].join("\n"),
    );
    const preview = buildTenantImportPreview(rows, tenants);
    const csv = serializeTenantImportCSV(preview, {
      2: {
        mode: "create",
        tenantId: "staging-parent-id",
        slug: "parent-slug",
      },
      3: {
        mode: "create",
        tenantId: "staging-child-id",
        slug: "child-slug",
      },
    });

    expect(rows[1].parentTenantSlug).toBe("parent-slug");
    expect(csv).toContain(
      "staging-child-id,Child Tenant,ORGANIZATION,staging-parent-id,parent-slug,child-slug,,",
    );
  });

  it("keeps parent_tenant_slug in the serialized CSV as a fallback for hierarchy import", () => {
    const rows = parseTenantCSV(
      [
        "name,type,parent_tenant_slug,slug,memo,email_domain",
        "Parent Tenant,COMPANY,,parent-slug,,",
        "Child Tenant,ORGANIZATION,parent-slug,child-slug,,",
      ].join("\n"),
    );
    const preview = buildTenantImportPreview(rows, tenants);
    const csv = serializeTenantImportCSV(preview, {
      2: {
        mode: "create",
        tenantId: "staging-parent-id",
        slug: "parent-slug",
      },
      3: {
        mode: "create",
        tenantId: "staging-child-id",
        slug: "child-slug",
      },
    });

    expect(csv.split("\n")[0]).toBe(
      "tenant_id,name,type,parent_tenant_id,parent_tenant_slug,slug,memo,email_domain,visibility,org_unit_type",
    );
    expect(csv).toContain(
      "staging-child-id,Child Tenant,ORGANIZATION,staging-parent-id,parent-slug,child-slug,,",
    );
  });

  it("parses Naver Works organization CSV columns into tenant import rows", () => {
    const rows = parseTenantCSV(
      [
        '"조직명","멤버 수","조직장","조직 다국어명","설명","메일링 리스트","상위 조직"',
        '"기술개발센터","1","","","","tdc@samaneng.com",""',
        '"기획부","1","","","","planning@samaneng.com","기술개발센터(tdc@samaneng.com)"',
        '"업무팀","0","","","","t_226wn@samaneng.com","기획부(planning@samaneng.com)"',
      ].join("\n"),
      { rootParentSlug: "saman" },
    );

    expect(rows).toMatchObject([
      {
        name: "기술개발센터",
        type: "ORGANIZATION",
        slug: "tdc",
        parentTenantSlug: "saman",
      },
      {
        name: "기획부",
        type: "ORGANIZATION",
        slug: "planning",
        parentTenantSlug: "tdc",
      },
      {
        name: "업무팀",
        type: "ORGANIZATION",
        slug: "t-226wn",
        parentTenantSlug: "planning",
      },
    ]);
  });

  it("infers root parent slug from an organization CSV file prefix that matches an existing slug", () => {
    expect(inferTenantImportRootParentSlug("saman_org.csv", tenants)).toBe(
      "saman",
    );
    expect(
      inferTenantImportRootParentSlug("/tmp/hanmac-family_org.csv", tenants),
    ).toBe("hanmac-family");
    expect(
      inferTenantImportRootParentSlug("saman_org_slugged.csv", tenants),
    ).toBe("saman");
    expect(inferTenantImportRootParentSlug("unknown_org.csv", tenants)).toBe(
      "",
    );
    expect(inferTenantImportRootParentSlug("tenant-import.csv", tenants)).toBe(
      "",
    );
  });

  it("groups existing parent candidates by company group, company, and organization", () => {
    const groups = buildTenantImportParentOptionGroups(tenants);

    expect(groups.map((group) => group.type)).toEqual([
      "COMPANY_GROUP",
      "COMPANY",
      "ORGANIZATION",
    ]);
    expect(
      groups.map((group) => group.tenants.map((tenant) => tenant.id)),
    ).toEqual([["tenant-3"], ["tenant-1", "tenant-2"], ["tenant-4"]]);
  });

  it("keeps generated ids stable and follows edited parent slugs for child rows", () => {
    const randomUUID = vi
      .fn()
      .mockReturnValueOnce("parent-generated-id")
      .mockReturnValueOnce("child-generated-id");
    vi.stubGlobal("crypto", { randomUUID });

    const rows = parseTenantCSV(
      [
        "name,type,parent_tenant_slug,slug,memo,email_domain",
        "기술개발센터,ORGANIZATION,saman,t-536fc,,",
        "일반구조물 div,ORGANIZATION,t-536fc,t-568cz,,",
      ].join("\n"),
    );
    const preview = buildTenantImportPreview(rows, tenants);
    const csv = serializeTenantImportCSV(preview, {
      2: { mode: "create", slug: "tech-center" },
      3: { mode: "create", slug: "structure-div" },
    });

    expect(csv).toContain(
      "parent-generated-id,기술개발센터,ORGANIZATION,,saman,tech-center,,",
    );
    expect(csv).toContain(
      "child-generated-id,일반구조물 div,ORGANIZATION,parent-generated-id,tech-center,structure-div,,",
    );
  });

  it("serializes explicit parent tenant selections from the import preview", () => {
    const rows = parseTenantCSV(
      [
        "name,type,parent_tenant_slug,slug,memo,email_domain",
        "기술개발센터,ORGANIZATION,saman,t-536fc,,",
        "일반구조물 div,ORGANIZATION,t-536fc,t-568cz,,",
      ].join("\n"),
    );
    const preview = buildTenantImportPreview(rows, tenants);
    const csv = serializeTenantImportCSV(preview, {
      2: {
        mode: "create",
        slug: "tech-center",
        parentTenantId: "tenant-2",
        parentTenantSlug: "",
      },
      3: {
        mode: "create",
        slug: "structure-div",
        parentTenantSlug: "tech-center",
      },
    });

    expect(csv).toContain("기술개발센터,ORGANIZATION,tenant-2,,tech-center,,");
    expect(csv).toContain(",일반구조물 div,ORGANIZATION,");
    expect(csv).toContain(",tech-center,structure-div,,");
  });
});
