import { promises as fs } from "node:fs";
import path from "node:path";

const DIST_DIR = path.resolve("dist");

/** @param {string} dir */
async function walkHtml(dir) {
  /** @type {string[]} */
  const out = [];
  const entries = await fs.readdir(dir, { withFileTypes: true });
  for (const e of entries) {
    const p = path.join(dir, e.name);
    if (e.isDirectory()) out.push(...(await walkHtml(p)));
    else if (e.isFile() && p.endsWith(".html")) out.push(p);
  }
  return out;
}

/** @param {string} attrs */
function getClass(attrs) {
  const m = attrs.match(/\bclass="([^"]*)"/i);
  return m ? m[1] : "";
}

/** @param {{tag:string,id:string,cls:string}} occ */
function score(occ) {
  // plus petit = mieux (on garde)
  if (occ.tag === "span" && /\bdetails-anchor\b/.test(occ.cls)) return 0;
  if (/^h[1-6]$/.test(occ.tag)) return 1;
  if (occ.tag === "p" && occ.id.startsWith("p-")) return 2;
  return 10; // tout le reste (toc, nav, etc.)
}

async function main() {
  let changedFiles = 0;
  let removed = 0;

  const files = await walkHtml(DIST_DIR);

  for (const file of files) {
    let html = await fs.readFile(file, "utf8");

    // capture: <tag ... id="X" ...>
    const re = /<([A-Za-z][\w:-]*)([^>]*?)\s+id="([^"]+)"([^>]*?)>/g;

    /** @type {Array<{id:string,tag:string,pre:string,post:string,start:number,end:number,cls:string,idx:number}>} */
    const occs = [];
    let m;
    let idx = 0;

    while ((m = re.exec(html)) !== null) {
      const tag = m[1].toLowerCase();
      const pre = m[2] || "";
      const id = m[3] || "";
      const post = m[4] || "";
      const fullAttrs = `${pre}${post}`;
      const cls = getClass(fullAttrs);

      occs.push({
        id,
        tag,
        pre,
        post,
        start: m.index,
        end: m.index + m[0].length,
        cls,
        idx: idx++,
      });
    }

    if (occs.length === 0) continue;

    /** @type {Map<string, Array<typeof occs[number]>>} */
    const byId = new Map();
    for (const o of occs) {
      if (!o.id) continue;
      const arr = byId.get(o.id) || [];
      arr.push(o);
      byId.set(o.id, arr);
    }

    /** @type {Array<{start:number,end:number,repl:string}>} */
    const edits = [];

    for (const [id, arr] of byId.entries()) {
      if (arr.length <= 1) continue;

      // choisir le “meilleur” porteur d’id : details-anchor > h2/h3... > p-... > reste
      const sorted = [...arr].sort((a, b) => {
        const sa = score(a);
        const sb = score(b);
        if (sa !== sb) return sa - sb;
        return a.idx - b.idx; // stable: premier
      });

      const keep = sorted[0];

      for (const o of sorted.slice(1)) {
        // remplacer l’ouverture de tag en supprimant l’attribut id
        // <tag{pre} id="X"{post}>  ==>  <tag{pre}{post}>
        const repl = `<${o.tag}${o.pre}${o.post}>`;
        edits.push({ start: o.start, end: o.end, repl });
        removed++;
      }

      // sécurité: on “force” l'id sur le keep (au cas où il aurait été modifié plus haut)
      // (on ne touche pas au keep ici, juste on ne le retire pas)
      void keep;
      void id;
    }

    if (edits.length === 0) continue;

    // appliquer de la fin vers le début
    edits.sort((a, b) => b.start - a.start);
    for (const e of edits) {
      html = html.slice(0, e.start) + e.repl + html.slice(e.end);
    }

    await fs.writeFile(file, html, "utf8");
    changedFiles++;
  }

  if (changedFiles > 0) {
    console.log(`✅ dedupe-ids-dist: files_changed=${changedFiles} ids_removed=${removed}`);
  } else {
    console.log("ℹ️  dedupe-ids-dist: no duplicates found");
  }
}

main().catch((err) => {
  console.error("❌ dedupe-ids-dist failed:", err);
  process.exit(1);
});
