#!/usr/bin/env node
/**
 * generate-resume.js
 * Generates a resume PDF from a profile's resume.md
 *
 * Usage: node generate-resume.js
 * Output: data/resume.pdf
 */

'use strict';

const fs = require('fs');
const path = require('path');
const puppeteer = require('puppeteer-core');

const CHROME_PATH = process.env.PUPPETEER_EXECUTABLE_PATH || '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
const { baseDir: profileDir } = require('../config/paths');
const RESUME_SCALE = parseFloat(process.env.RESUME_SCALE) || 0.96;


function loadProfileCss(dir = profileDir) {
  const profileCssPath = path.join(dir, 'resume.css');
  return fs.existsSync(profileCssPath) ? fs.readFileSync(profileCssPath, 'utf8') : '';
}

// ---------------------------------------------------------------------------
// Parse resume.md into structured sections
// ---------------------------------------------------------------------------

function parseResume(md) {
  const lines = md.split('\n');
  const resume = { name: '', contact: '', sections: [] };
  let current = null;
  let i = 0;

  // First line: # Name
  while (i < lines.length && !lines[i].trim()) i++;
  resume.name = lines[i++].replace(/^#\s*/, '').trim();

  // Second non-empty line: contact
  while (i < lines.length && !lines[i].trim()) i++;
  resume.contact = lines[i++].trim();

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

    // H2 = section header (## Summary, ## Experience, etc.)
    if (/^##\s/.test(line)) {
      current = { title: line.replace(/^##\s*/, '').trim().toUpperCase(), entries: [], type: 'section' };
      resume.sections.push(current);
      continue;
    }

    if (!current) continue;

    // H3 = job header (### Title — Company / Location)
    if (/^###\s/.test(line)) {
      const raw = line.replace(/^###\s*/, '').trim();
      // "Title — Company / Location"
      const dashMatch = raw.match(/^(.+?)\s+[—–-]+\s+(.+)$/);
      current.entries.push({
        type: 'job',
        raw,
        title: dashMatch ? dashMatch[1].trim() : raw,
        company: dashMatch ? dashMatch[2].trim() : '',
        date: '',
        subtitle: '',
        bullets: [],
      });
      continue;
    }

    const lastEntry = current.entries[current.entries.length - 1];

    // Sub-role line: **Title** | Date  (must check before the date check)
    const subroleMatch = line.match(/^\*\*(.+?)\*\*\s*\|\s*(.+)$/);
    if (subroleMatch) {
      if (lastEntry && lastEntry.type === 'job') {
        if (!lastEntry.subroles) lastEntry.subroles = [];
        lastEntry.subroles.push({ title: subroleMatch[1].trim(), date: subroleMatch[2].trim(), bullets: [] });
      }
      continue;
    }

    // **Date** line (bold date after job header)
    if (/^\*\*[A-Z][a-z]/.test(line) || /^\*\*[A-Z][a-z0-9 –-]+\*\*$/.test(line)) {
      if (lastEntry && lastEntry.type === 'job') {
        lastEntry.date = line.replace(/\*\*/g, '').trim();
        continue;
      }
    }

    // *subtitle* line (italic)
    if (/^\*[^*]/.test(line) && line.endsWith('*') && !line.startsWith('**')) {
      if (lastEntry && lastEntry.type === 'job') {
        lastEntry.subtitle = line.replace(/^\*|\*$/g, '').trim();
        continue;
      }
    }

    // Bullet point
    if (/^[-*]\s/.test(line)) {
      const text = line.replace(/^[-*]\s/, '').trim();
      if (lastEntry && lastEntry.type === 'job') {
        const subroles = lastEntry.subroles;
        if (subroles && subroles.length > 0) {
          subroles[subroles.length - 1].bullets.push(text);
        } else {
          lastEntry.bullets.push(text);
        }
      } else {
        // Bullets directly in section (e.g., Summary isn't really bullets but just in case)
        current.entries.push({ type: 'bullet', text });
      }
      continue;
    }

    // Plain text (Summary paragraph, Skills lines, Education)
    if (line.trim() && line !== '---') {
      // Skills lines: **Label:** content
      if (/^\*\*[A-Za-z/& ]+:\*\*/.test(line)) {
        current.entries.push({ type: 'skill', text: line.trim() });
      } else if (current.entries.length > 0 && current.entries[current.entries.length - 1].type === 'paragraph') {
        current.entries[current.entries.length - 1].text += ' ' + line.trim();
      } else {
        current.entries.push({ type: 'paragraph', text: line.trim() });
      }
    }
  }

  return resume;
}

// ---------------------------------------------------------------------------
// Render inline markdown (bold/italic) to HTML
// ---------------------------------------------------------------------------

function inlineMd(text) {
  return text
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/`([^`]+)`/g, '<code>$1</code>')
    .replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
    .replace(/\*([^*]+)\*/g, '<em>$1</em>');
}

// ---------------------------------------------------------------------------
// Build HTML
// ---------------------------------------------------------------------------

function buildHtml(resume, profileCss = loadProfileCss()) {
  let html = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body {
    font-family: 'Times New Roman', Times, serif;
    font-size: 8.6pt;
    line-height: 1.26;
    color: #222;
    padding: 0.34in 0.48in 0.2in 0.48in;
  }

  /* Header */
  .name {
    font-size: 19pt;
    font-weight: bold;
    text-align: center;
    letter-spacing: 0.5px;
  }
  .contact {
    font-size: 8.3pt;
    text-align: center;
    color: #444;
    margin-top: 2px;
    margin-bottom: 5px;
  }

  /* Section headers */
  .section-header {
    font-size: 8.6pt;
    font-weight: bold;
    color: #1a56a0;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    border-bottom: 1px solid #1a56a0;
    padding-bottom: 1px;
    margin-top: 9px;
    margin-bottom: 2px;
  }

  /* Job entry */
  .job-header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-top: 7px;
  }
  .job-title-company {
    font-size: 8.6pt;
    font-weight: bold;
  }
  .job-date {
    font-size: 8.3pt;
    color: #555;
    white-space: nowrap;
    margin-left: 8px;
    flex-shrink: 0;
  }
  .job-subtitle {
    font-style: italic;
    font-size: 8.3pt;
    color: #444;
    margin-top: 0px;
    margin-bottom: 1px;
  }

  /* Bullets */
  ul {
    margin-left: 12px;
    margin-top: 1px;
    margin-bottom: 0px;
  }
  li {
    margin-bottom: 1px;
    padding-left: 1px;
  }
  li::marker {
    font-size: 6pt;
  }

  /* Summary */
  .summary-text {
    margin-top: 1px;
    margin-bottom: 1px;
  }

  /* Skills */
  .skill-line {
    margin-bottom: 0.5px;
  }

  /* Education */
  .edu-text {
    font-weight: bold;
  }

  /* Sub-role entries within a company block */
  .subrole-header {
    margin-top: 4px;
    margin-left: 0px;
  }
  .subrole-title {
    font-style: italic;
    font-weight: bold;
  }

${profileCss}
</style>
</head>
<body>

<div class="name">${inlineMd(resume.name)}</div>
<div class="contact">${inlineMd(resume.contact)}</div>
`;

  for (const section of resume.sections) {
    html += `<div class="section-header">${section.title}</div>\n`;

    for (const entry of section.entries) {
      if (entry.type === 'job') {
        // Split "Title — Company / Location" for display
        const titlePart = entry.title;
        const companyPart = entry.company;
        html += `<div class="job-header">
  <span class="job-title-company"><span class="job-title">${inlineMd(titlePart)}</span>${companyPart ? `  &nbsp; ${inlineMd(companyPart)}` : ''}</span>
  <span class="job-date">${inlineMd(entry.date)}</span>
</div>\n`;
        if (entry.subtitle) {
          html += `<div class="job-subtitle">${inlineMd(entry.subtitle)}</div>\n`;
        }
        if (entry.bullets.length > 0) {
          html += `<ul>\n`;
          for (const b of entry.bullets) {
            html += `  <li>${inlineMd(b)}</li>\n`;
          }
          html += `</ul>\n`;
        }
        if (entry.subroles && entry.subroles.length > 0) {
          for (const sr of entry.subroles) {
            html += `<div class="job-header subrole-header">
  <span class="job-title-company subrole-title">${inlineMd(sr.title)}</span>
  <span class="job-date">${inlineMd(sr.date)}</span>
</div>\n`;
            if (sr.bullets.length > 0) {
              html += `<ul>\n`;
              for (const b of sr.bullets) {
                html += `  <li>${inlineMd(b)}</li>\n`;
              }
              html += `</ul>\n`;
            }
          }
        }
      } else if (entry.type === 'skill') {
        html += `<div class="skill-line">${inlineMd(entry.text)}</div>\n`;
      } else if (entry.type === 'paragraph') {
        const cls = section.title === 'SUMMARY' ? 'summary-text' : 'edu-text';
        html += `<div class="${cls}">${inlineMd(entry.text)}</div>\n`;
      } else if (entry.type === 'bullet') {
        html += `<ul><li>${inlineMd(entry.text)}</li></ul>\n`;
      }
    }
  }

  html += `</body></html>`;
  return html;
}

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

async function main() {
  const browser = await puppeteer.launch({
    executablePath: CHROME_PATH,
    headless: true,
    args: ['--no-sandbox', '--disable-setuid-sandbox'],
  });

  const RESUME_PATH = path.join(profileDir, 'resume.md');
  const OUTPUT_PATH = path.join(profileDir, 'resume.pdf');
  try {
    const profileCss = loadProfileCss(profileDir);
    const md = fs.readFileSync(RESUME_PATH, 'utf8');
    const resume = parseResume(md);
    const html = buildHtml(resume, profileCss);

    const page = await browser.newPage();
    await page.setContent(html, { waitUntil: 'networkidle0' });
    await page.pdf({
      path: OUTPUT_PATH,
      format: 'Letter',
      printBackground: false,
      scale: RESUME_SCALE,
    });
    await page.close();
    console.log(`PDF generated: ${OUTPUT_PATH}`);
  } finally {
    await browser.close();
  }
}

async function writeResumePdf({ html, outputPath, scale = RESUME_SCALE, chromePath = CHROME_PATH } = {}) {
  const browser = await puppeteer.launch({
    executablePath: chromePath,
    headless: true,
    args: ['--no-sandbox', '--disable-setuid-sandbox'],
  });

  try {
    const page = await browser.newPage();
    await page.setContent(html, { waitUntil: 'networkidle0' });
    await page.pdf({
      path: outputPath,
      format: 'Letter',
      printBackground: false,
      scale,
    });
    await page.close();
  } finally {
    await browser.close();
  }
}

function renderResumeMarkdownToHtml(markdown, { profileDir: dir = profileDir } = {}) {
  return buildHtml(parseResume(markdown), loadProfileCss(dir));
}

if (require.main === module) {
  main().catch(err => {
    console.error('Error generating PDF:', err.message);
    process.exit(1);
  });
}

module.exports = {
  buildHtml,
  loadProfileCss,
  parseResume,
  renderResumeMarkdownToHtml,
  writeResumePdf,
};
