import { getPizZip } from '@/lib/pizzipClient';
import type { TemplatePlaceholder } from './templateTypes';

/**
 * Scan word/document.xml for docxtemplater-style placeholders.
 * Supports `{scalar}` and `{#loop}…{/loop}` with inner `{field}` tags.
 */
export async function detectPlaceholders(buffer: ArrayBuffer): Promise<TemplatePlaceholder[]> {
  const PizZip = await getPizZip();
  const zip = new PizZip(buffer);
  const file = zip.file('word/document.xml');
  if (!file) {
    throw new Error('Invalid DOCX: missing word/document.xml');
  }
  const xml = file.asText();
  return parsePlaceholdersFromDocumentXml(xml);
}

function parsePlaceholdersFromDocumentXml(xml: string): TemplatePlaceholder[] {
  const result: TemplatePlaceholder[] = [];
  const seenScalar = new Set<string>();
  const seenLoop = new Set<string>();

  const loopHeader = /\{#([\w.]+)\}/g;
  let m: RegExpExecArray | null;
  while ((m = loopHeader.exec(xml)) !== null) {
    const loopName = m[1];
    if (seenLoop.has(loopName)) continue;

    const closeTag = `{/${loopName}}`;
    const startIdx = m.index + m[0].length;
    const endIdx = xml.indexOf(closeTag, startIdx);
    if (endIdx === -1) continue;

    const innerXml = xml.slice(startIdx, endIdx);
    const innerTags = extractInnerFieldNames(innerXml);
    seenLoop.add(loopName);
    result.push({ kind: 'loop', name: loopName, innerTags });
  }

  const scalarRe = /\{([^{}#/][^}]*)\}/g;
  while ((m = scalarRe.exec(xml)) !== null) {
    const raw = m[1].trim();
    const name = raw.split(/\s/)[0]?.replace(/[:@].*$/, '') ?? raw;
    if (!name || name.startsWith('#') || name.startsWith('/') || name.startsWith('^')) continue;
    if (seenScalar.has(name) || seenLoop.has(name)) continue;
    seenScalar.add(name);
    result.push({ kind: 'scalar', name });
  }

  return result;
}

function extractInnerFieldNames(fragment: string): string[] {
  const inner = new Set<string>();
  const re = /\{([^{}#/][^}]*)\}/g;
  let m: RegExpExecArray | null;
  while ((m = re.exec(fragment)) !== null) {
    const raw = m[1].trim();
    const name = raw.split(/\s/)[0]?.replace(/[:@].*$/, '') ?? raw;
    if (name && !name.startsWith('^')) inner.add(name);
  }
  return Array.from(inner);
}
