import { describe, expect, it } from "vitest";
import {
  API_BATCH_SIZE,
  batchCount,
  importTriggerSchema,
  keywordListsSchema,
  listPreviewOutSchema,
  parseKeywordLines,
  quotaSchema,
} from "./integrations";

describe("parseKeywordLines", () => {
  it("garde un mot-clé par ligne, dans l'ordre de saisie", () => {
    expect(parseKeywordLines("chaise de bureau\nfauteuil")).toEqual([
      "chaise de bureau",
      "fauteuil",
    ]);
  });

  it("écarte les lignes vides et les espaces, qui ne sont pas des mots-clés", () => {
    expect(parseKeywordLines("  chaise  \n\n   \nfauteuil\n")).toEqual(["chaise", "fauteuil"]);
  });

  it("dédoublonne : demander deux fois le même mot-clé le compterait deux fois", () => {
    expect(parseKeywordLines("chaise\nfauteuil\nchaise")).toEqual(["chaise", "fauteuil"]);
  });

  it("rend une liste vide plutôt que [''] sur une saisie vide", () => {
    expect(parseKeywordLines("")).toEqual([]);
    expect(parseKeywordLines("\n \n")).toEqual([]);
  });
});

describe("batchCount", () => {
  it("compte des requêtes, pas des mots-clés — c'est ce que le quota décompte", () => {
    expect(batchCount(1)).toBe(1);
    expect(batchCount(API_BATCH_SIZE)).toBe(1);
    //  Le point que le récapitulatif doit rendre visible : 200 mots-clés ne coûtent pas 200.
    expect(batchCount(200)).toBe(2);
    expect(batchCount(API_BATCH_SIZE + 1)).toBe(2);
  });

  it("ne descend jamais sous une requête, même sans mot-clé", () => {
    expect(batchCount(0)).toBe(1);
  });
});

describe("quotaSchema", () => {
  it("accepte un quota inconnu : le fournisseur peut ne pas l'avoir dit", () => {
    const parsed = quotaSchema.parse({
      provider: "mangools",
      resource: "related-keywords",
      limit: null,
      remaining: null,
      error: "API Mangools injoignable",
    });
    expect(parsed.remaining).toBeNull();
    expect(parsed.error).toBe("API Mangools injoignable");
  });

  it("lit le reste de la ressource qui décompte", () => {
    const parsed = quotaSchema.parse({
      provider: "mangools",
      resource: "related-keywords",
      limit: 1200,
      remaining: 1192,
      error: null,
    });
    expect(parsed).toMatchObject({ limit: 1200, remaining: 1192 });
  });
});

describe("keywordListsSchema", () => {
  it("lit une liste du compte, dates comprises", () => {
    const parsed = keywordListsSchema.parse({
      items: [
        {
          id: "6a589821eefecfa46ad01f2e",
          name: "ADVMFR USA Brand",
          keyword_count: 2,
          created_at: "2026-07-16T08:36:49Z",
          updated_at: "2026-07-16T08:36:49Z",
        },
      ],
    });
    expect(parsed.items[0]).toMatchObject({ name: "ADVMFR USA Brand", keyword_count: 2 });
  });

  it("accepte des dates absentes : le fournisseur peut ne pas les avoir dites", () => {
    const parsed = keywordListsSchema.parse({
      items: [{ id: "a", name: "A", keyword_count: 0, created_at: null, updated_at: null }],
    });
    expect(parsed.items[0]?.updated_at).toBeNull();
  });
});

describe("listPreviewOutSchema", () => {
  it("rend le recensement par liste et en agrégat", () => {
    const parsed = listPreviewOutSchema.parse({
      items: [
        {
          list_id: "a",
          name: "Liste A",
          keywords_total: 3,
          countries: [
            {
              raw: "United States",
              code: "US",
              label: "États-Unis",
              rows: 2,
              suggested_language: "en",
              target_ids: [],
            },
          ],
        },
      ],
      countries: [
        {
          raw: "New York",
          code: null,
          label: "New York",
          rows: 1,
          suggested_language: null,
          target_ids: [],
        },
      ],
    });
    expect(parsed.items[0]?.countries[0]?.code).toBe("US");
    //  Un libellé non résolu garde un `label` non nul : c'est le contrat avec l'écran.
    expect(parsed.countries[0]).toMatchObject({ code: null, label: "New York" });
  });

  it("tolère une liste sans marché : `countries` a un défaut", () => {
    const parsed = listPreviewOutSchema.parse({
      items: [{ list_id: "a", name: "A", keywords_total: 0 }],
    });
    expect(parsed.items[0]?.countries).toEqual([]);
    expect(parsed.countries).toEqual([]);
  });
});

describe("importTriggerSchema", () => {
  it("lit l'enveloppe : un déclenchement peut enfiler plusieurs imports", () => {
    const parsed = importTriggerSchema.parse({
      items: [
        {
          import_id: "01a0608d-34b0-7dad-9a9f-762bb25bb6df",
          job_id: "01a0608d-34b0-7dad-9a9f-762bb25bb6de",
          created: true,
          list_id: "a",
          list_name: "Liste A",
        },
        {
          import_id: "01a0608d-34b0-7dad-9a9f-762bb25bb6dd",
          job_id: "01a0608d-34b0-7dad-9a9f-762bb25bb6dc",
          created: false,
          list_id: "b",
          list_name: "Liste B",
        },
      ],
    });
    expect(parsed.items.map((item) => item.list_name)).toEqual(["Liste A", "Liste B"]);
    //  Faux = un import de la même période était déjà en vol, l'appel a rendu l'existant.
    expect(parsed.items[1]?.created).toBe(false);
  });

  it("accepte un import sans liste : les deux modes dormants n'en ont pas", () => {
    const parsed = importTriggerSchema.parse({
      items: [
        {
          import_id: "01a0608d-34b0-7dad-9a9f-762bb25bb6df",
          job_id: "01a0608d-34b0-7dad-9a9f-762bb25bb6de",
          created: true,
          list_id: null,
          list_name: null,
        },
      ],
    });
    expect(parsed.items[0]?.list_id).toBeNull();
  });
});
