#!/usr/bin/env node
/**
 * PDF Generation Script
 * 
 * Uses Puppeteer to render each HTML page to PDF.
 * Run with: node generate-pdfs.js
 * 
 * Prerequisites: npm install puppeteer
 */

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

// Configuration
const SITE_DIR = __dirname; // Running from /srv in Docker, which contains all site files
const PDF_DIR = path.join(SITE_DIR, 'pdfs');
const PORT = 8765;

// MIME types for static file serving
const MIME_TYPES = {
    '.html': 'text/html',
    '.css': 'text/css',
    '.js': 'application/javascript',
    '.json': 'application/json',
    '.png': 'image/png',
    '.jpg': 'image/jpeg',
    '.jpeg': 'image/jpeg',
    '.gif': 'image/gif',
    '.svg': 'image/svg+xml',
    '.ico': 'image/x-icon',
    '.woff': 'font/woff',
    '.woff2': 'font/woff2',
    '.ttf': 'font/ttf',
    '.eot': 'application/vnd.ms-fontobject',
};

/**
 * Find all HTML files in a directory recursively
 */
function findHtmlFiles(dir, baseDir = dir) {
    const files = [];
    const entries = fs.readdirSync(dir, { withFileTypes: true });
    
    for (const entry of entries) {
        const fullPath = path.join(dir, entry.name);
        
        if (entry.isDirectory()) {
            // Skip pdfs directory, node_modules, and hidden directories
            if (entry.name === 'pdfs' || entry.name === 'node_modules' || entry.name.startsWith('.')) {
                continue;
            }
            files.push(...findHtmlFiles(fullPath, baseDir));
        } else if (entry.isFile() && entry.name.endsWith('.html')) {
            // Skip template files
            if (entry.name.includes('template') || entry.name.includes('with-includes')) {
                continue;
            }
            const relativePath = path.relative(baseDir, fullPath);
            files.push(relativePath);
        }
    }
    
    return files;
}

/**
 * Create a simple static file server
 */
function createServer() {
    return http.createServer((req, res) => {
        let urlPath = req.url.split('?')[0];
        if (urlPath === '/') urlPath = '/index.html';
        
        const filePath = path.join(SITE_DIR, urlPath);
        const ext = path.extname(filePath);
        const contentType = MIME_TYPES[ext] || 'application/octet-stream';
        
        fs.readFile(filePath, (err, data) => {
            if (err) {
                res.writeHead(404);
                res.end('Not found');
                return;
            }
            res.writeHead(200, { 'Content-Type': contentType });
            res.end(data);
        });
    });
}

/**
 * Ensure directory exists
 */
function ensureDir(dirPath) {
    if (!fs.existsSync(dirPath)) {
        fs.mkdirSync(dirPath, { recursive: true });
    }
}

/**
 * Generate PDF for a single HTML file
 */
async function generatePdf(browser, htmlFile) {
    const page = await browser.newPage();
    
    // Convert file path to URL path
    const urlPath = '/' + htmlFile.replace(/\\/g, '/');
    const url = `http://localhost:${PORT}${urlPath}`;
    
    // Determine output PDF path
    const pdfRelativePath = htmlFile.replace(/\.html$/, '.pdf');
    const pdfPath = path.join(PDF_DIR, pdfRelativePath);
    
    // Ensure output directory exists
    ensureDir(path.dirname(pdfPath));
    
    try {
        // Navigate to the page and wait for content to load
        await page.goto(url, { 
            waitUntil: 'networkidle0',
            timeout: 30000 
        });
        
        // Wait for includes to load - check if header-include exists and has content
        try {
            await page.waitForFunction(() => {
                const headerInclude = document.getElementById('header-include');
                // If header-include exists, wait for it to have content (includes loaded)
                // If it doesn't exist, that's fine too (page doesn't use includes)
                if (headerInclude) {
                    return headerInclude.innerHTML.trim().length > 0 || 
                           document.querySelector('.main-nav') !== null;
                }
                return true; // No header-include, page is ready
            }, { timeout: 10000 });
        } catch (waitError) {
            // If waiting for includes times out, continue anyway
            console.warn(`Warning: Includes may not have loaded for ${htmlFile}, continuing...`);
        }
        
        // Wait a bit more for any remaining JavaScript to finish
        await page.waitForTimeout(500);
        
        // Generate PDF
        await page.pdf({
            path: pdfPath,
            format: 'A4',
            printBackground: true,
            margin: {
                top: '20mm',
                right: '15mm',
                bottom: '20mm',
                left: '15mm'
            }
        });
        
        console.log(`✓ Generated: ${pdfRelativePath}`);
    } catch (error) {
        console.error(`✗ Failed: ${htmlFile} - ${error.message}`);
        // Don't re-throw - let the caller handle it
    } finally {
        try {
            await page.close();
        } catch (closeError) {
            // Page might already be closed, ignore
        }
    }
}

/**
 * Main function
 */
async function main() {
    console.log('PDF Generation Script');
    console.log('=====================\n');
    
    // Find all HTML files
    const htmlFiles = findHtmlFiles(SITE_DIR);
    console.log(`Found ${htmlFiles.length} HTML files to process\n`);
    
    if (htmlFiles.length === 0) {
        console.log('No HTML files found. Exiting.');
        return;
    }
    
    // Clean and create PDF directory
    if (fs.existsSync(PDF_DIR)) {
        fs.rmSync(PDF_DIR, { recursive: true });
    }
    ensureDir(PDF_DIR);
    
    // Start local server
    const server = createServer();
    await new Promise(resolve => server.listen(PORT, resolve));
    console.log(`Local server started on port ${PORT}\n`);
    
    // Launch browser
    // Use system Chromium if available (in Docker), otherwise use Puppeteer's bundled Chrome
    const browser = await puppeteer.launch({
        headless: 'new',
        executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || undefined,
        args: [
            '--no-sandbox',
            '--disable-setuid-sandbox',
            '--disable-dev-shm-usage',
            '--disable-accelerated-2d-canvas',
            '--no-first-run',
            '--no-zygote',
            '--single-process',
            '--disable-gpu'
        ]
    });
    
    let successCount = 0;
    let failCount = 0;
    
    try {
        // Generate PDFs for each HTML file
        for (const htmlFile of htmlFiles) {
            try {
                await generatePdf(browser, htmlFile);
                successCount++;
            } catch (error) {
                failCount++;
                console.error(`Failed to generate PDF for ${htmlFile}:`, error.message);
                // Continue with next file instead of stopping
            }
        }
        
        console.log(`\n✓ PDF generation complete!`);
        console.log(`  Success: ${successCount}, Failed: ${failCount}`);
        console.log(`  Files saved to: ${PDF_DIR}`);
    } finally {
        await browser.close();
        server.close();
    }
}

// Run the script
main().catch(error => {
    console.error('Fatal error:', error);
    process.exit(1);
});

