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

const TEMPLATE = path.join(__dirname, 'main.html');
const FUNCDIR = path.join(__dirname, 'functions');
const OUTFILE = path.join(__dirname, 'index.html');
const FUNCTIONS_LIST_JSON_OUTFILE = 'functions-list.json';

function randomUuid() {
  return crypto.randomBytes(16).toString('hex');
}

function escapeHtml(str) {
  return String(str)
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;');
}

console.log('═══════════════════════════════════════════════');
console.log(' Lava Doc Site Builder - build-single-index.js ');
console.log('═══════════════════════════════════════════════\n');

console.log(`Reading HTML template from: ${TEMPLATE}`);
const template = fs.readFileSync(TEMPLATE, 'utf8');

console.log(`Scanning function/article docs in: ${FUNCDIR}`);
const files = fs.readdirSync(FUNCDIR).filter(f => f.endsWith('.json'));
console.log(`Found ${files.length} documentation files.\n`);

let docs = [];
let failedFiles = [];
let parseErrors = [];

for (const file of files) {
  const fullPath = path.join(FUNCDIR, file);
  try {
    console.log(`Reading: ${file} ...`);
    const raw = fs.readFileSync(fullPath, 'utf8');
    const obj = JSON.parse(raw);
    docs.push({ obj, file });
    console.log(`  ✔ Loaded "${file}" OK.`);
  } catch (e) {
    console.error(`  ✖ Failed to read/parse "${file}": ${e.message}`);
    failedFiles.push(file);
    parseErrors.push({ file, error: e });
  }
}

console.log('\nSorting documentation blocks...');
docs.sort((a, b) => {
  const aId = a.obj.heading?.title?.toLowerCase() || '';
  const bId = b.obj.heading?.title?.toLowerCase() || '';
  return aId.localeCompare(bId);
});

// Partition docs into articles and function docs
const articleDocs = [];
const functionDocs = [];
for (const {obj, file} of docs) {
  const badges = (obj.heading && Array.isArray(obj.heading.badges)) ? obj.heading.badges : [];
  if (badges.includes('ARTICLE')) {
    articleDocs.push({obj, file});
  } else {
    functionDocs.push({obj, file});
  }
}

// Gather components and groups for function docs
const componentSet = new Set();
const groupSet = new Set();
for (const {obj} of functionDocs) {
  if (obj.dataComponent && obj.dataComponent.trim()) {
    componentSet.add(obj.dataComponent.trim());
  }
  if (obj.group && obj.group.trim()) {
    groupSet.add(obj.group.trim());
  }
}
// ensure "core" is present
componentSet.add('core');

// Create group->uuid map
const groupUuidMap = {};
for (const g of groupSet) {
  if (!groupUuidMap[g]) {
    groupUuidMap[g] = randomUuid();
  }
}

// Generate sidebar navigation with filters
console.log('Generating sidebar navigation...');
let navHtml = `
<div class="mb-1rem">
  <label for="component-filter-select" class="bold">Component:</label>
  <select id="component-filter-select" class="full-width mt-03">
    <option value="">All Components</option>
`;
const sortedComps = [...componentSet].sort();
for (const c of sortedComps) {
  navHtml += `    <option value="${escapeHtml(c)}">${escapeHtml(c)}</option>\n`;
}
navHtml += `  </select>
</div>

<div class="mb-1rem">
  <label for="group-filter-select" class="bold">Group:</label>
  <select id="group-filter-select" class="full-width mt-03">
    <option value="">All Groups</option>
`;
const sortedGroups = [...groupSet].sort();
for (const g of sortedGroups) {
  navHtml += `    <option value="${escapeHtml(groupUuidMap[g])}">${escapeHtml(g)}</option>\n`;
}
navHtml += `  </select>
</div>

<div class="search-box">
  <input type="text" placeholder="Filter" id="filter-input" class="w-80" />
</div>
<div class="function-list-container">
  <ul class="function-list">
`;

navHtml += `    <li data-component="core" data-groupUuid="">
      <a href="#core:extend" data-component="core">core:extend</a>
    </li>\n`;

for (const {obj} of functionDocs) {
  const comp = (obj.dataComponent || '').trim();
  const t = obj.heading?.title || '';
  const finalId = `${comp}:${t}`;
  let grpUuid = '';
  if (obj.group && obj.group.trim()) {
    grpUuid = groupUuidMap[obj.group.trim()];
  }
  const linkText = `${comp}:${t}`;
  navHtml += `    <li data-component="${escapeHtml(comp)}" data-groupUuid="${escapeHtml(grpUuid)}">
      <a href="#${escapeHtml(finalId)}" data-component="${escapeHtml(comp)}">
        ${escapeHtml(linkText)}
      </a>
    </li>\n`;
}
navHtml += `  </ul>
</div>
`;

console.log('Rendering documentation blocks...');
let renderedIds = [];
let renderFailures = [];
function buildDocBlockHTML(obj, file, groupUuidMap) {
  try {
    const comp = obj.dataComponent || '';
    const title = obj.heading?.title || '(No title)';
    const id = comp && title ? `${comp}:${title}` : 'unknown';
    let docGroupUuid = '';
    if (obj.group && obj.group.trim()) {
      if (!groupUuidMap[obj.group]) {
        groupUuidMap[obj.group] = randomUuid();
      }
      docGroupUuid = groupUuidMap[obj.group];
    }

    // Badges
    const badges = Array.isArray(obj.heading?.badges) ? obj.heading.badges : [];
    const badgeHtml = badges.map(b => `<span class="category-badge">${escapeHtml(b)}</span>`).join(' ');
    const compBadge = comp ? `<span class="component-badge">:${escapeHtml(comp)}</span>` : '';

    const h1 = `<h1>${escapeHtml(title)} ${compBadge} ${badgeHtml}</h1>`;

    // Synopsis
    let synopsisHtml = '';
    if (obj.synopsis && obj.synopsis.trim()) {
      synopsisHtml = `
<div class="description-block bg-orange">
  ${escapeHtml(obj.synopsis)}
</div>`;
    }

    // Code blocks
    let codeBlocksHtml = '';
    if (Array.isArray(obj.codeBlocks)) {
      for (const block of obj.codeBlocks) {
        codeBlocksHtml += `<div class="code-block"><pre><code>${escapeHtml(block.replace(/\\n/g, '\n'))}</code></pre></div>\n`;
      }
    }

    // Notes
    let notesHtml = '';
    if (Array.isArray(obj.notes) && obj.notes.length > 0) {
      const lines = obj.notes.map(line => `<p>${escapeHtml(line)}</p>`).join('');
      notesHtml = `<div class="notes-block">${lines}</div>`;
    }

    renderedIds.push(id);
    console.log(`✔ Rendered: ${id}`);
    // Add HTML comment for easy debugging
    return `<!-- rendered: ${id} -->\n<div class="doc-block" id="${escapeHtml(id)}" data-component="${escapeHtml(comp)}" data-groupUuid="${escapeHtml(docGroupUuid)}">
${h1}
${synopsisHtml}
${codeBlocksHtml}
${notesHtml}
</div>`;
  } catch (e) {
    const id = obj && obj.heading && obj.heading.title ? `${obj.dataComponent || ''}:${obj.heading.title}` : file;
    renderFailures.push(id);
    console.error(`✖ Failed to render doc block for "${id}": ${e.message}`);
    return `<!-- Failed to render: ${id} -->`;
  }
}

let docBlocksHtml = '';
for (const {obj, file} of articleDocs) {
  docBlocksHtml += buildDocBlockHTML(obj, file, {});
}
for (const {obj, file} of functionDocs) {
  docBlocksHtml += buildDocBlockHTML(obj, file, groupUuidMap);
}

// Append a summary block to the HTML for diagnostics
let summaryHtml = `
<!-- Build summary -->
<div style="font-size:0.9em;color:#666;margin:2em 0 0 0;">
  <b>Rendered ${renderedIds.length} docs:</b> ${renderedIds.join(', ') || '(none)'}<br/>
  ${failedFiles.length + renderFailures.length
    ? `<b>Failed files:</b> ${(failedFiles.concat(renderFailures)).join(', ')}`
    : 'All files rendered successfully.'}
</div>
`;

console.log('Inserting generated content into template...');
let result = template;
result = result.replace('<!--FUNCTION_NAV-->', navHtml);
result = result.replace('<!--DOC_BLOCKS-->', docBlocksHtml + summaryHtml);

console.log(`Writing output to: ${OUTFILE}`);
fs.writeFileSync(OUTFILE, result, 'utf8');
console.log('✔ index.html generated successfully!\n');

const functionList = files.map(full => full.replace(/\\/g, '/'));
fs.writeFileSync(FUNCTIONS_LIST_JSON_OUTFILE, JSON.stringify(functionList, null, 2), 'utf8');
console.log(`Wrote '${FUNCTIONS_LIST_JSON_OUTFILE}' with an array of filenames only.`);

if (failedFiles.length || renderFailures.length) {
  console.error(`There were ${failedFiles.length + renderFailures.length} file(s) with errors:`);
  for (const fname of failedFiles) {
    console.error(` - Failed to load: ${fname}`);
  }
  for (const rid of renderFailures) {
    console.error(` - Failed to render: ${rid}`);
  }
} else {
  console.log('All documentation files loaded and rendered with no errors.');
}

console.log('\nDone. You can now open index.html in your browser.');
