#!/usr/bin/env node

/**
 * Generates shared/config/urlParameters.js from parameters.md.
 *
 * The resulting module exports structured data about URL parameters so that
 * documentation pages and the popup can share a single source of truth.
 */

const fs = require('fs');
const path = require('path');

const repoRoot = path.resolve(__dirname, '..');
const sourcePath = path.join(repoRoot, 'parameters.md');
const targetPath = path.join(repoRoot, 'shared', 'config', 'urlParameters.js');

const markdown = fs.readFileSync(sourcePath, 'utf8');
const lines = markdown.split(/\r?\n/);

function slugify(value) {
  return value
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '');
}

function cleanCell(value) {
  return value
    .replace(/`/g, '')
    .replace(/\*\*/g, '')
    .replace(/\\\|/g, '|')
    .replace(/\[(.*?)\]\(.*?\)/g, '$1')
    .trim();
}

function parseParameterNames(value) {
  const cleaned = cleanCell(value).replace(/\s+/g, ' ').trim();
  if (!cleaned) {
    return [];
  }
  return cleaned
    .split(/\s+or\s+|\/|,\s*|aka\s+/i)
    .map(name => name.replace(/[^-\w]/g, '').trim())
    .filter(Boolean);
}

function flushParagraph(buffer, target, group) {
  if (!buffer.length) {
    return;
  }
  const text = buffer
    .map(line => line.trim())
    .filter(Boolean)
    .join(' ')
    .replace(/\s+/g, ' ');

  if (!text) {
    buffer.length = 0;
    return;
  }

  if (group) {
    group.description = group.description ? `${group.description} ${text}` : text;
  } else if (target) {
    target.description = target.description ? `${target.description} ${text}` : text;
  }

  buffer.length = 0;
}

const targets = [];
let currentTarget = null;
let currentGroup = null;
const paragraphBuffer = [];

function ensureGroup() {
  if (!currentTarget) {
    throw new Error('Encountered table without a parent target heading.');
  }
  if (!currentGroup) {
    currentGroup = {
      title: 'General Parameters',
      slug: 'general-parameters',
      description: '',
      items: []
    };
    currentTarget.sections.push(currentGroup);
  }
  return currentGroup;
}

for (let index = 0; index < lines.length; index += 1) {
  const line = lines[index];

  if (line.startsWith('## ')) {
    flushParagraph(paragraphBuffer, currentTarget, currentGroup);
    const title = line.replace(/^##\s+/, '').trim();
    currentTarget = {
      title,
      slug: slugify(title),
      description: '',
      sections: []
    };
    targets.push(currentTarget);
    currentGroup = null;
    continue;
  }

  if (line.startsWith('### ')) {
    flushParagraph(paragraphBuffer, currentTarget, currentGroup);
    if (!currentTarget) {
      throw new Error(`Found subsection "${line}" before any ## heading.`);
    }
    const title = line.replace(/^###\s+/, '').trim();
    currentGroup = {
      title,
      slug: slugify(title),
      description: '',
      items: []
    };
    currentTarget.sections.push(currentGroup);
    continue;
  }

  if (line.trim().startsWith('| Parameter')) {
    flushParagraph(paragraphBuffer, currentTarget, currentGroup);

    // Skip the alignment row
    index += 1;

    let rowIndex = index + 1;
    while (rowIndex < lines.length) {
      const row = lines[rowIndex];
      if (!row.trim().startsWith('|')) {
        break;
      }

      const cells = row.split('|').slice(1, -1).map(cleanCell);
      if (cells.length < 3) {
        rowIndex += 1;
        continue;
      }

      const [parameterName, values, description] = cells;
      const aliases = parseParameterNames(parameterName);
      if (!aliases.length) {
        rowIndex += 1;
        continue;
      }

      const entry = {
        key: aliases[0],
        displayName: parameterName,
        aliases,
        values,
        description
      };

      const group = ensureGroup();
      group.items.push(entry);

      rowIndex += 1;
    }

    index = rowIndex - 1;
    continue;
  }

  if (line.startsWith('```')) {
    flushParagraph(paragraphBuffer, currentTarget, currentGroup);
    // Skip code blocks entirely.
    index += 1;
    while (index < lines.length && !lines[index].startsWith('```')) {
      index += 1;
    }
    continue;
  }

  paragraphBuffer.push(line);
}

flushParagraph(paragraphBuffer, currentTarget, currentGroup);

if (!targets.length) {
  throw new Error('No targets were parsed from parameters.md.');
}

const serialized = JSON.stringify(targets, null, 2);

const fileContent = `// Auto-generated by scripts/generate-url-parameters.js
// Source: parameters.md

function createLookup(groups) {
  const entries = new Map();
  groups.forEach(target => {
    target.sections.forEach(section => {
      section.items.forEach(item => {
        item.aliases.forEach(alias => {
          const key = alias.toLowerCase();
          if (!entries.has(key)) {
            entries.set(key, {
              target: target.title,
              section: section.title,
              ...item
            });
          }
        });
      });
    });
  });
  return Object.freeze(Object.fromEntries(entries));
}

export const URL_PARAMETER_GROUPS = Object.freeze(${serialized});
export const URL_PARAMETER_LOOKUP = createLookup(URL_PARAMETER_GROUPS);

export function findUrlParameter(name) {
  if (!name) {
    return null;
  }
  const key = String(name).trim().toLowerCase();
  return URL_PARAMETER_LOOKUP[key] || null;
}

export default URL_PARAMETER_GROUPS;
`;

fs.mkdirSync(path.dirname(targetPath), { recursive: true });
fs.writeFileSync(targetPath, fileContent);

console.log(`Generated ${path.relative(repoRoot, targetPath)} with ${targets.length} target group(s).`);
