import { beforeAll, expect, spyOn, test } from "bun:test";
import { join } from "node:path";
import { DuckDBInstance } from "@duckdb/node-api";
import { detectSource, processCsv } from "../src/processor";

beforeAll(() => {
  process.env.STORAGE_DRIVER = "local";
});
const fx = (n: string) => join(import.meta.dir, "fixtures", n);

test("detectSource by header", async () => {
  expect(await detectSource(fx("semrush.csv"))).toBe("semrush");
  expect(await detectSource(fx("mangools.csv"))).toBe("mangools");
  expect(await detectSource(fx("ahrefs.csv"))).toBe("ahrefs");
  expect(await detectSource(fx("seranking.csv"))).toBe("seranking");
});
test("seranking: BOM + letter intents, Competition→density, dedups by slug", async () => {
  const { rows, totals } = await processCsv(
    fx("seranking.csv"),
    "seranking",
    "fr",
    "FR",
  );
  expect(totals.read).toBe(3);
  expect(rows.length).toBe(2); // duplicate "assurance auto" deduped
  const a = rows.find((r) => r.slug === "assurance-auto")!;
  expect(a.term).toBe("assurance auto");
  expect(a.metrics.volume).toBe(1200); // higher-volume duplicate kept
  expect(a.metrics.kd).toBe(40);
  expect(a.metrics.cpc).toBe(3.5);
  expect(a.metrics.competitiveDensity).toBe(0.8); // "Competition" column
  expect(a.metrics.numberOfResults).toBeNull();
  expect(a.intent).toEqual(["commercial", "transactional"]);
  expect(a.serpFeatures).toEqual(["Local Pack", "People Also Ask"]);
  expect(a.country).toBe("FR"); // no Location column → site country param
  expect(a.lang).toBe("fr");
  const m = rows.find((r) => r.slug === "mutuelle-sante")!;
  expect(m.intent).toEqual(["local"]); // letter "L"
});
test("semrush: maps columns, dedups by slug, slugs term", async () => {
  const { rows, totals } = await processCsv(fx("semrush.csv"), "semrush", "en");
  expect(totals.read).toBe(3);
  expect(rows.length).toBe(2);
  const a = rows.find((r) => r.slug === "seo-audit")!;
  expect(a.term).toBe("seo audit");
  expect(a.metrics.volume).toBe(1000);
  expect(a.metrics.kd).toBe(45);
  expect(a.metrics.cpc).toBe(2.5);
  expect(a.metrics.competitiveDensity).toBe(0.3);
  expect(a.metrics.numberOfResults).toBe(1200000);
  expect(a.primarySource).toBe("semrush");
  expect(a.country).toBe("US");
});
test("mangools: growthPct + country from Location", async () => {
  const { rows } = await processCsv(fx("mangools.csv"), "mangools", "en");
  const r = rows[0];
  expect(r.slug).toBe("netlinking");
  expect(r.metrics.volume).toBe(500);
  expect(r.metrics.growthPct).toBe(12.5);
  expect(r.metrics.competitiveDensity).toBeNull();
});
test("a single import opens exactly ONE DuckDB instance", async () => {
  // mangools is the worst case: it sniffs the header (columnNames) AND reads
  // rows (rowsOf) — these used to open a separate instance each (2 per job).
  const spy = spyOn(DuckDBInstance, "create");
  try {
    await processCsv(fx("mangools.csv"), "mangools", "en");
    expect(spy).toHaveBeenCalledTimes(1);
  } finally {
    spy.mockRestore();
  }
});
test("ahrefs: dedups SERP rows per keyword, maps Country + Intents", async () => {
  const { rows, totals } = await processCsv(fx("ahrefs.csv"), "ahrefs", "fr");
  expect(totals.read).toBe(17); // 17 SERP rows in the fixture…
  expect(rows.length).toBe(2); // …deduped to 2 distinct keywords
  const a = rows.find((r) => r.slug === "subvention-eclairage-led-entreprise")!;
  expect(a.term).toBe("subvention éclairage led entreprise");
  expect(a.metrics.volume).toBe(300);
  expect(a.metrics.kd).toBe(0);
  expect(a.metrics.cpc).toBe(1.2);
  expect(a.primarySource).toBe("ahrefs");
  expect(a.country).toBe("FR");
  expect(a.lang).toBe("fr");
  expect(a.intent).toContain("informational");
  expect(a.serpFeatures).toEqual([]);
});
