import type { XmlGeneratorMode, XmlCategory, GeneratedOutput } from "../types";

function sanitizeName(name: string): string | null {
  const trimmed = name.trim();
  if (!trimmed) return null;
  let n = trimmed.replace(/\s+/g, "_").replace(/[^A-Za-z0-9_.-]/g, "");
  if (!/^[A-Za-z_]/.test(n)) n = "_" + n;
  return n || null;
}

function getCategoryNamespace(baseNs: string, category: string): string {
  const safeCat = sanitizeName(category) || category;
  return baseNs.replace(/\/+$/, "") + "/" + safeCat;
}

function getCategoryRoot(category: string): string {
  const safeCat = sanitizeName(category) || category;
  return safeCat + "Data";
}

interface FieldEntry {
  label: string;
  baseName: string;
  variants: string[];
}

export function generateCategoryXml(
  category: string,
  catData: XmlCategory,
  baseNamespace: string,
  mode: XmlGeneratorMode,
): GeneratedOutput {
  const raw = catData.fieldsText
    .split(/\r?\n/)
    .map((l) => l.trim())
    .filter((l) => l.length > 0);

  if (raw.length === 0) return { xml: "", xpaths: "" };

  const ns = getCategoryNamespace(baseNamespace, category);
  const root = getCategoryRoot(category);

  const usedNames = new Set<string>();
  const fields: FieldEntry[] = [];

  for (const label of raw) {
    const base = sanitizeName(label);
    if (!base) continue;

    let baseName = base;
    let idx = 2;
    while (usedNames.has(baseName)) {
      baseName = base + "_" + idx;
      idx++;
    }
    usedNames.add(baseName);

    const variants = [baseName];
    if (mode === "advanced") {
      const suffixes = ["Short", "Upper", "Lower", "Initials", "First"];
      for (const suffix of suffixes) {
        let vn = baseName + suffix;
        let k = 2;
        while (usedNames.has(vn)) {
          vn = baseName + suffix + "_" + k;
          k++;
        }
        usedNames.add(vn);
        variants.push(vn);
      }
    }

    fields.push({ label, baseName, variants });
  }

  const allFields = fields;

  // Build XML
  let xml = '<?xml version="1.0" encoding="UTF-8"?>\n';
  xml += `<${root} xmlns="${ns}">\n`;
  for (const f of allFields) {
    for (const v of f.variants) {
      xml += `  <${v}></${v}>\n`;
    }
  }
  xml += `</${root}>\n`;

  // Build XPaths
  let xp = `Categorie: ${category}\nNamespace: ${ns}\nRoot: /${root}\n\n`;
  for (const f of fields) {
    xp += `# ${f.label}\n`;
    for (const v of f.variants) {
      xp += `/${root}/${v}\n`;
    }
    xp += "\n";
  }
  return { xml, xpaths: xp };
}

export function generateAllCategories(
  categories: Record<string, XmlCategory>,
  baseNamespace: string,
  mode: XmlGeneratorMode,
): Record<string, GeneratedOutput> {
  const results: Record<string, GeneratedOutput> = {};
  for (const cat of Object.keys(categories)) {
    const catData = categories[cat];
    if (!catData) continue;
    results[cat] = generateCategoryXml(cat, catData, baseNamespace, mode);
  }
  return results;
}

export function downloadXmlFile(xml: string, filename: string): void {
  const blob = new Blob([xml], { type: "application/xml" });
  const a = document.createElement("a");
  a.href = URL.createObjectURL(blob);
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(a.href);
}

export async function downloadZipAll(
  categories: Record<string, XmlCategory>,
  baseNamespace: string,
  mode: XmlGeneratorMode,
): Promise<void> {
  const JSZip = (await import("jszip")).default;
  const results = generateAllCategories(categories, baseNamespace, mode);

  const zip = new JSZip();
  const folder = zip.folder("customXmlParts")!;

  let hasAny = false;
  for (const cat of Object.keys(results)) {
    const output = results[cat];
    if (!output?.xml) continue;
    const { xml } = output;
    hasAny = true;
    const safeCat = sanitizeName(cat) || cat;
    folder.file(`${safeCat}Data.xml`, xml);
  }

  if (!hasAny) return;

  const content = await zip.generateAsync({ type: "blob" });
  const a = document.createElement("a");
  a.href = URL.createObjectURL(content);
  a.download = "beletage_custom_xml_parts.zip";
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(a.href);
}
