/**
 * directives.js - Custom directive parser voor Markdown
 *
 * Parseert custom syntax zoals :::tabs, :::warning, :::accordion etc.
 * en splitst het document in typed blocks die de renderer kan verwerken.
 *
 * Ondersteunde directives:
 * - :::tabs{os}       OS-tabbladen (Mac/Windows)
 * - ::tab[Label]      Tab binnen een tabs-blok
 * - :::accordion[T]   Uitklapbare sectie
 * - :::warning        Waarschuwingsblok (teal)
 * - :::info           Informatieblok (warm)
 * - :::steps          Genummerde stappen met iconen
 * - :::checklist      Checklijst met vinkjes
 * - :::checklist-verify  Verificatie checklijst
 * - :::command[cmd]   Terminal commando met uitleg
 * - :::if{os=value}   Conditionele content
 * - :::image{os=val}  Conditionele afbeelding
 * - :::troubleshoot[T] Probleemoplossing kaart
 */

/**
 * Hoofdfunctie: parseert Markdown met directives naar een block-array.
 *
 * @param {string} markdown - Raw Markdown tekst met directives
 * @returns {{ frontmatter: object, blocks: Array }} Geparsed resultaat
 */
export function parseDocument(markdown) {
  const { frontmatter, body } = extractFrontmatter(markdown);
  const blocks = parseDirectives(body);
  return { frontmatter, blocks };
}

/**
 * Extraheert YAML frontmatter (---) uit de Markdown.
 */
function extractFrontmatter(markdown) {
  const match = markdown.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
  if (!match) return { frontmatter: {}, body: markdown };

  const frontmatter = {};
  match[1].split('\n').forEach(line => {
    const colonIndex = line.indexOf(':');
    if (colonIndex > 0) {
      const key = line.slice(0, colonIndex).trim();
      const value = line.slice(colonIndex + 1).trim();
      frontmatter[key] = value;
    }
  });

  return { frontmatter, body: match[2] };
}

/**
 * Parseert de body-tekst in een array van typed blocks.
 * Werkt als een line-by-line state machine.
 */
function parseDirectives(text) {
  const lines = text.split('\n');
  const blocks = [];
  let i = 0;

  while (i < lines.length) {
    const line = lines[i];

    // :::tabs{id}
    const tabsMatch = line.match(/^:::tabs\{(\w+)\}/);
    if (tabsMatch) {
      const result = parseTabs(lines, i, tabsMatch[1]);
      blocks.push(result.block);
      i = result.nextIndex;
      continue;
    }

    // :::accordion[titel]
    const accordionMatch = line.match(/^:::accordion\[(.+?)\]/);
    if (accordionMatch) {
      const result = parseEnclosed(lines, i);
      blocks.push({
        type: 'accordion',
        title: accordionMatch[1],
        blocks: parseDirectives(result.content),
      });
      i = result.nextIndex;
      continue;
    }

    // :::warning
    if (line.trim() === ':::warning') {
      const result = parseEnclosed(lines, i);
      blocks.push({ type: 'warning', content: result.content });
      i = result.nextIndex;
      continue;
    }

    // :::info
    if (line.trim() === ':::info') {
      const result = parseEnclosed(lines, i);
      blocks.push({ type: 'info', content: result.content });
      i = result.nextIndex;
      continue;
    }

    // :::tip
    if (line.trim() === ':::tip') {
      const result = parseEnclosed(lines, i);
      blocks.push({ type: 'tip', content: result.content });
      i = result.nextIndex;
      continue;
    }

    // :::steps
    if (line.trim() === ':::steps') {
      const result = parseEnclosed(lines, i);
      blocks.push({ type: 'steps', steps: parseStepItems(result.content) });
      i = result.nextIndex;
      continue;
    }

    // :::checklist
    if (line.trim() === ':::checklist') {
      const result = parseEnclosed(lines, i);
      blocks.push({ type: 'checklist', content: result.content });
      i = result.nextIndex;
      continue;
    }

    // :::checklist-verify
    if (line.trim() === ':::checklist-verify') {
      const result = parseEnclosed(lines, i);
      blocks.push({ type: 'checklist-verify', content: result.content });
      i = result.nextIndex;
      continue;
    }

    // :::command[cmd]
    const commandMatch = line.match(/^:::command\[(.+?)\]/);
    if (commandMatch) {
      const result = parseEnclosed(lines, i);
      blocks.push({
        type: 'command',
        command: commandMatch[1],
        content: result.content,
      });
      i = result.nextIndex;
      continue;
    }

    // :::if{os=value}
    const ifMatch = line.match(/^:::if\{(\w+)=(\w+)\}/);
    if (ifMatch) {
      const result = parseEnclosed(lines, i);
      blocks.push({
        type: 'conditional',
        key: ifMatch[1],
        value: ifMatch[2],
        blocks: parseDirectives(result.content),
      });
      i = result.nextIndex;
      continue;
    }

    // :::image{os=value}
    const imageIfMatch = line.match(/^:::image\{(\w+)=(\w+)\}/);
    if (imageIfMatch) {
      const result = parseEnclosed(lines, i);
      blocks.push({
        type: 'conditional-image',
        key: imageIfMatch[1],
        value: imageIfMatch[2],
        content: result.content,
      });
      i = result.nextIndex;
      continue;
    }

    // :::troubleshoot[titel]
    const troubleshootMatch = line.match(/^:::troubleshoot\[(.+?)\]/);
    if (troubleshootMatch) {
      const result = parseEnclosed(lines, i);
      blocks.push({
        type: 'troubleshoot',
        title: troubleshootMatch[1],
        content: result.content,
      });
      i = result.nextIndex;
      continue;
    }

    // Onbekende ::: regel? Behandel als gewone tekst en ga verder.
    // Dit voorkomt een infinite loop bij onvolledige directives (bijv. tijdens typen).
    if (line.match(/^:::/)) {
      blocks.push({ type: 'markdown', content: line });
      i++;
      continue;
    }

    // Gewone Markdown regel - verzamel tot de volgende directive
    const markdownLines = [];
    while (i < lines.length && !lines[i].match(/^:::/)) {
      markdownLines.push(lines[i]);
      i++;
    }
    const content = markdownLines.join('\n').trim();
    if (content) {
      blocks.push({ type: 'markdown', content });
    }
    continue;
  }

  return blocks;
}

/**
 * Parseert een enclosed blok (:::open ... :::close).
 * Houdt rekening met geneste directives door een depth counter.
 */
function parseEnclosed(lines, startIndex) {
  let depth = 1;
  let i = startIndex + 1;
  const contentLines = [];

  while (i < lines.length && depth > 0) {
    const line = lines[i];

    // Sluitende :::
    if (line.trim() === ':::') {
      depth--;
      if (depth === 0) {
        i++;
        break;
      }
      contentLines.push(line);
      i++;
      continue;
    }

    // Openende ::: (genest)
    if (line.match(/^:::[a-z]/)) {
      depth++;
    }

    contentLines.push(line);
    i++;
  }

  return {
    content: contentLines.join('\n').trim(),
    nextIndex: i,
  };
}

/**
 * Parseert een :::tabs{id} blok met ::tab[Label] sub-tabs.
 */
function parseTabs(lines, startIndex, tabId) {
  let depth = 1;
  let i = startIndex + 1;
  const tabs = [];
  let currentTab = null;
  let currentLines = [];

  while (i < lines.length && depth > 0) {
    const line = lines[i];

    // Sluitende :::
    if (line.trim() === ':::') {
      depth--;
      if (depth === 0) {
        // Sla laatste tab op
        if (currentTab) {
          tabs.push({
            label: currentTab,
            blocks: parseDirectives(currentLines.join('\n').trim()),
          });
        }
        i++;
        break;
      }
      currentLines.push(line);
      i++;
      continue;
    }

    // Nieuwe tab (depth 1)
    const tabMatch = depth === 1 && line.match(/^::tab\[(.+?)\]/);
    if (tabMatch) {
      // Sla vorige tab op
      if (currentTab) {
        tabs.push({
          label: currentTab,
          blocks: parseDirectives(currentLines.join('\n').trim()),
        });
      }
      currentTab = tabMatch[1];
      currentLines = [];
      i++;
      continue;
    }

    // Geneste opening
    if (line.match(/^:::[a-z]/)) {
      depth++;
    }

    currentLines.push(line);
    i++;
  }

  return {
    block: { type: 'tabs', id: tabId, tabs },
    nextIndex: i,
  };
}

/**
 * Parseert de inhoud van een :::steps blok in individuele stappen.
 * Elke stap heeft een nummer, eerste-regel tekst, en geneste blocks.
 *
 * Voorbeeld input:
 *   1. **Open de app** -- Beschrijving
 *   :::image{os=mac}
 *   ![alt](pad.png)
 *   :::
 *   2. Volgende stap
 *
 * Resultaat: [{ number: '1', text: '**Open de app** -- Beschrijving', blocks: [...] }, ...]
 */
function parseStepItems(content) {
  const lines = content.split('\n');
  const steps = [];
  let currentStep = null;
  let currentLines = [];

  for (const line of lines) {
    const stepMatch = line.match(/^(\d+)\.\s+(.*)/);
    if (stepMatch) {
      // Sla de vorige stap op
      if (currentStep) {
        steps.push({
          number: currentStep.number,
          text: currentStep.text,
          blocks: parseDirectives(currentLines.join('\n').trim()),
        });
      }
      currentStep = { number: stepMatch[1], text: stepMatch[2] };
      currentLines = [];
    } else if (currentStep) {
      currentLines.push(line);
    }
  }

  // Sla de laatste stap op
  if (currentStep) {
    steps.push({
      number: currentStep.number,
      text: currentStep.text,
      blocks: parseDirectives(currentLines.join('\n').trim()),
    });
  }

  return steps;
}
