import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import { normalizeCode, normalizeText } from "./normalize.js";
import type { CpvEntry, RawCpvDataset, SynonymMap } from "./types.js";

let entriesPromise: Promise<CpvEntry[]> | null = null;
let synonymsPromise: Promise<SynonymMap> | null = null;

export function loadCpvEntries(): Promise<CpvEntry[]> {
  if (!entriesPromise) {
    entriesPromise = readJsonFile<RawCpvDataset>("../cpv.json")
      .then((raw) => raw.CPV_CODE.CPV.map(toCpvEntry))
      .catch((error) => {
        entriesPromise = null;
        throw error;
      });
  }

  return entriesPromise;
}

export function loadSynonyms(): Promise<SynonymMap> {
  if (!synonymsPromise) {
    synonymsPromise = readJsonFile<SynonymMap>("../synonyms.json").catch(
      (error) => {
        synonymsPromise = null;
        throw error;
      },
    );
  }

  return synonymsPromise;
}

async function readJsonFile<T>(relativePath: string): Promise<T> {
  const filePath = fileURLToPath(new URL(relativePath, import.meta.url));
  const source = await readFile(filePath, "utf8");
  return JSON.parse(source) as T;
}

function toCpvEntry(entry: RawCpvDataset["CPV_CODE"]["CPV"][number]): CpvEntry {
  const text = entry.TEXT.replace(/\u00a0/g, " ").trim();
  const code = entry.CODE.trim();

  return {
    code,
    text,
    normalizedCode: normalizeCode(code),
    normalizedText: normalizeText(text),
    normalizedSearch: `${normalizeCode(code)} ${normalizeText(text)}`.trim(),
  };
}
