// src/lib/keywords/serp-store.ts — stockage d'un snapshot SERP sur un mot-clé (partagé action / upload route).
import "server-only";
import { eq, sql } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { db } from "@/lib/db/client";
import { keywords } from "@/lib/db/domain-schema";
import { parseSerpExport } from "./serp-import";
import type { SerpSnapshot } from "./serp-types";

export async function importSerpSnapshot(
  keywordId: string,
  csvText: string,
): Promise<{ ok: boolean; locale?: string; error?: string }> {
  const [row] = await db
    .select({ country: keywords.country })
    .from(keywords)
    .where(eq(keywords.id, keywordId));
  if (!row) return { ok: false, error: "Mot-clé introuvable" };

  let snapshot: SerpSnapshot;
  try {
    snapshot = parseSerpExport(csvText, new Date().toISOString());
  } catch (e) {
    return {
      ok: false,
      error: e instanceof Error ? e.message : "Parse échoué",
    };
  }
  if (snapshot.competitors.length === 0) {
    // The parser handles both the SE-Ranking and Mangools/SerpChecker layouts (the
    // latter behind a metric preamble), so 0 competitors now means one of two things:
    // a recognised export with no organic result, or a file that isn't a SERP-URLs
    // export at all. Sniff the first lines (past any preamble) for a url + position
    // header so the message is actionable instead of misleading.
    const looksLikeSerpUrls = csvText
      .split(/\r?\n/, 12)
      .some(
        (line) =>
          /(^|,)\s*"?url"?\s*(,|$)/i.test(line) &&
          /(^|,)\s*"?position"?\s*(,|$)/i.test(line),
      );
    return {
      ok: false,
      error: looksLikeSerpUrls
        ? "Aucun concurrent organique dans l'export."
        : "CSV non reconnu : attendu un export « SERP URLs » (SE Ranking ou SerpChecker) avec les colonnes position et url. Réexporte la liste des résultats.",
    };
  }

  const locale = row.country || "US";
  // SQL-side jsonb merge (mirrors the gscByCountry `col || patch` pattern in
  // gsc/sync.ts): merge only this locale's key instead of read-modify-writing the
  // whole `serp` object, so a concurrent write to a different locale isn't clobbered.
  await db
    .update(keywords)
    .set({
      serp: sql`coalesce(${keywords.serp}, '{}'::jsonb) || ${JSON.stringify({ [locale]: snapshot })}::jsonb`,
    })
    .where(eq(keywords.id, keywordId));
  revalidatePath("/content/planning");
  revalidatePath("/keywords/planning");
  revalidatePath(`/keywords/dispatch/${keywordId}`);
  return { ok: true, locale };
}
