/**
 * Script to generate markdown API documentation from TypeScript code using TypeDoc
 */

import fs from 'fs';
import path from 'path';
import { execSync } from 'child_process';
import { globSync } from 'glob';
import { marked } from 'marked';

// Auto-generated warning header
// IMPORTANT: Keep this as the single source of truth for generated docs headers.
const DOCS_GENERATION_COMMAND = 'pnpm typedoc:convert';
const AUTO_GENERATED_WARNING = `<!--
⚠️ AUTO-GENERATED FILE - DO NOT EDIT MANUALLY

Generated by: scripts/docs/docs-generator.js
Command: ${DOCS_GENERATION_COMMAND}

To make changes, edit the source TypeScript files or update the generator script.
-->

`;

// HTML template
const HTML_TEMPLATE = `<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Robota API Documentation</title>
  <meta name="description" content="Robota API Documentation">
  <link rel="stylesheet" href="/robota/style.css">
</head>
<body>
  <div id="content">
    {{CONTENT}}
  </div>
  <script>
    // Redirect to Docsify when page loads
    window.addEventListener('DOMContentLoaded', function() {
      // Remove .html extension from current path
      const currentPath = window.location.pathname;
      if (currentPath.endsWith('.html')) {
        // Redirect for history mode
        const newPath = currentPath.replace('.html', '');
        window.location.replace(newPath);
      }
    });
  </script>
</body>
</html>`;

// Directory path configuration
const ROOT_DIR = process.cwd(); // Using process.cwd() since script runs from root directory
const PACKAGES_DIR = path.join(ROOT_DIR, 'packages');
const DOCS_DIR = path.join(ROOT_DIR, 'content');
const OUTPUT_DIR = path.join(DOCS_DIR, 'api-reference');
const APPS_DOCS_DIR = path.join(ROOT_DIR, 'apps/docs');
const TEMP_DIR = path.join(APPS_DOCS_DIR, '.temp');

// Dynamically discover API categories from packages directory
function getApiCategories() {
    const categories = [];

    if (!fs.existsSync(PACKAGES_DIR)) {
        console.warn(`⚠️ Packages directory not found: ${PACKAGES_DIR}`);
        return categories;
    }

    const packageDirs = fs.readdirSync(PACKAGES_DIR, { withFileTypes: true })
        .filter(dirent => dirent.isDirectory())
        .map(dirent => dirent.name);

    for (const packageName of packageDirs) {
        const packagePath = path.join(PACKAGES_DIR, packageName);
        const srcPath = path.join(packagePath, 'src');
        const entryPoint = path.join(srcPath, 'index.ts');

        // Check if package has src/index.ts entry point
        if (fs.existsSync(entryPoint)) {
            categories.push({
                name: packageName,
                pattern: `packages/${packageName}/src/**/*.ts`,
                entryPoint: entryPoint
            });
            console.log(`📦 Found package: ${packageName}`);
        } else {
            console.log(`⚠️ Skipping ${packageName}: no src/index.ts found`);
        }
    }

    return categories;
}

// Generate API documentation main file
function generateApiIndexPage(apiCategories) {
    const content = `${AUTO_GENERATED_WARNING}# Robota API Reference

Complete API documentation for the Robota SDK packages. Find detailed information about classes, functions, and types for each package.

## Packages

${apiCategories.map(category => `- [${category.name}](${category.name.toLowerCase()}/)`).join('\n')}
`;

    if (!fs.existsSync(OUTPUT_DIR)) {
        fs.mkdirSync(OUTPUT_DIR, { recursive: true });
    }

    const indexPath = path.resolve(OUTPUT_DIR, 'README.md');
    fs.writeFileSync(indexPath, content);
}

// Generate API documentation using TypeDoc
async function generateDocsForCategory(category) {
    const { name, pattern, entryPoint } = category;

    // Check file existence
    if (!fs.existsSync(entryPoint)) {
        console.error(`⚠️ Entry point does not exist: ${entryPoint}`);
        return 0;
    }

    // Find files
    const files = globSync(path.join(ROOT_DIR, pattern), {
        ignore: ['**/*.test.ts', '**/*.spec.ts', '**/node_modules/**']
    });

    if (files.length === 0) {
        console.log(`⚠️ No files found for ${name}`);
        return 0;
    }

    // Create category directory
    const categoryDir = path.join(OUTPUT_DIR, name.toLowerCase());
    if (!fs.existsSync(categoryDir)) {
        fs.mkdirSync(categoryDir, { recursive: true });
    }

    // Execute TypeDoc command
    try {
        // Find tsconfig.json in package path
        const packageDir = path.dirname(path.dirname(entryPoint)); // Parent directory of src
        const tsconfigPath = path.join(packageDir, 'tsconfig.json');

        if (!fs.existsSync(tsconfigPath)) {
            console.error(`⚠️ tsconfig.json file not found: ${tsconfigPath}`);
            return 0;
        }

        const command = `npx typedoc --options ${path.join(ROOT_DIR, 'typedoc.json')} --out ${categoryDir} --entryPoints ${entryPoint} --tsconfig ${tsconfigPath} --name "${name}"`;

        console.log(`🔄 Converting ${name} TypeScript to Markdown...`);
        execSync(command, { stdio: 'pipe' }); // Hide logs

        // Fix file structure (modules.md -> README.md)
        fixFileStructure(categoryDir, name);

        // Add auto-generated warnings
        addAutoGeneratedWarnings(categoryDir);

        // Fix link paths
        fixDocumentLinks(categoryDir, name.toLowerCase());

        // Generate sidebar for API reference categories
        generateApiSidebar(categoryDir, name);

        console.log(`✅ Generated API docs for ${name} (${files.length} files)`);
        return files.length;
    } catch (error) {
        console.error(`⚠️ Error occurred while generating ${name} category API documentation:`, error);
        return 0;
    }
}

// Fix file structure and create proper README.md for each category
function fixFileStructure(categoryDir, categoryName) {
    const modulesPath = path.join(categoryDir, 'modules.md');
    const readmePath = path.join(categoryDir, 'README.md');
    const parentReadmePath = path.join(OUTPUT_DIR, 'README.md');

    // For first package (agents), move project README.md to parent folder
    if (categoryName === 'agents' && fs.existsSync(readmePath)) {
        // Move project-wide README.md to api-reference root
        fs.copyFileSync(readmePath, parentReadmePath);
        console.log(`📄 Moved project README.md to api-reference root`);
    }

    // Convert modules.md to README.md
    if (fs.existsSync(modulesPath)) {
        // If modules.md exists, rename to README.md
        if (fs.existsSync(readmePath)) {
            // Delete existing README.md if it exists (unnecessary since it's project-wide README.md)
            fs.unlinkSync(readmePath);
            console.log(`🗑️  Removed project README.md from ${categoryName}`);
        }

        fs.renameSync(modulesPath, readmePath);
        console.log(`📄 Converted modules.md to README.md for ${categoryName}`);
    } else {
        console.log(`⚠️  modules.md not found in ${categoryName}`);
    }
}

// Remove TypeDoc generated index files that cause sidebar duplication
function removeTypeDocIndexFiles(categoryDir) {
    const categoryName = path.basename(categoryDir);
    const filesToRemove = ['modules.md'];

    // Remove modules.md only
    for (const file of filesToRemove) {
        const filePath = path.join(categoryDir, file);
        if (fs.existsSync(filePath)) {
            fs.unlinkSync(filePath);
            console.log(`🗑️  Removed ${file} from ${categoryName}`);
        }
    }

    // Keep the original TypeDoc generated README.md
    console.log(`📄 Keeping original README.md for ${categoryName}`);
}

// Fix TypeScript generic syntax that Vue/VitePress might interpret as HTML tags
function fixTypeScriptGenerics(content) {
    // Replace Promise<Type> with Promise\<Type\> to escape angle brackets
    content = content.replace(/Promise<([^>]+)>/g, 'Promise\\<$1\\>');

    // Replace other common generic patterns
    content = content.replace(/Array<([^>]+)>/g, 'Array\\<$1\\>');
    content = content.replace(/Record<([^>]+)>/g, 'Record\\<$1\\>');
    content = content.replace(/Partial<([^>]+)>/g, 'Partial\\<$1\\>');
    content = content.replace(/Required<([^>]+)>/g, 'Required\\<$1\\>');
    content = content.replace(/Readonly<([^>]+)>/g, 'Readonly\\<$1\\>');

    // Fix generic function signatures like Function<T>
    content = content.replace(/(\w+)<([^>]+)>/g, '$1\\<$2\\>');

    return content;
}

// Add auto-generated warnings to all generated files
function addAutoGeneratedWarnings(categoryDir) {
    const mdFiles = globSync(path.join(categoryDir, '**/*.md'));

    for (const mdFile of mdFiles) {
        try {
            let content = fs.readFileSync(mdFile, 'utf-8');

            // Check if warning already exists
            if (!content.includes('AUTO-GENERATED FILE')) {
                // Fix TypeScript generics that might be interpreted as HTML
                content = fixTypeScriptGenerics(content);

                content = AUTO_GENERATED_WARNING + content;
                fs.writeFileSync(mdFile, content);
            }
        } catch (error) {
            console.error(`⚠️ Error occurred while adding warning header to ${mdFile}:`, error);
        }
    }
}

// Generate sidebar for API reference categories - DISABLED for auto-sidebar plugin
function generateApiSidebar(categoryDir, categoryName) {
    // Sidebar generation disabled - using auto-sidebar plugin instead
    return;

    // try {
    //     const sidebarPath = path.join(categoryDir, '_sidebar.md');
    //
    //     // Check what files and directories exist
    //     const classesDir = path.join(categoryDir, 'classes');
    //     const interfacesDir = path.join(categoryDir, 'interfaces');
    //     const enumsDir = path.join(categoryDir, 'enums');
    //     const typesDir = path.join(categoryDir, 'types');
    //
    //     let sidebarContent = `${AUTO_GENERATED_WARNING}* [${categoryName} API](README.md)
    //
    // `;
    //
    //     // Add classes section
    //     if (fs.existsSync(classesDir)) {
    //         const classFiles = fs.readdirSync(classesDir)
    //             .filter(f => f.endsWith('.md'))
    //             .sort();
    //
    //         if (classFiles.length > 0) {
    //             sidebarContent += `**Classes**\n`;
    //             for (const file of classFiles) {
    //                 const className = file.replace('.md', '');
    //                 sidebarContent += `* [${className}](classes/${className})\n`;
    //             }
    //             sidebarContent += '\n';
    //         }
    //     }
    //
    //     // Add interfaces section
    //     if (fs.existsSync(interfacesDir)) {
    //         const interfaceFiles = fs.readdirSync(interfacesDir)
    //             .filter(f => f.endsWith('.md'))
    //             .sort();
    //
    //         if (interfaceFiles.length > 0) {
    //             sidebarContent += `**Interfaces**\n`;
    //             for (const file of interfaceFiles) {
    //                 const interfaceName = file.replace('.md', '');
    //                 sidebarContent += `* [${interfaceName}](interfaces/${interfaceName})\n`;
    //             }
    //             sidebarContent += '\n';
    //         }
    //     }
    //
    //     // Add enums section
    //     if (fs.existsSync(enumsDir)) {
    //         const enumFiles = fs.readdirSync(enumsDir)
    //             .filter(f => f.endsWith('.md'))
    //             .sort();
    //
    //         if (enumFiles.length > 0) {
    //             sidebarContent += `**Enums**\n`;
    //             for (const file of enumFiles) {
    //                 const enumName = file.replace('.md', '');
    //                 sidebarContent += `* [${enumName}](enums/${enumName})\n`;
    //             }
    //             sidebarContent += '\n';
    //         }
    //     }
    //
    //     // Add types section
    //     if (fs.existsSync(typesDir)) {
    //         const typeFiles = fs.readdirSync(typesDir)
    //             .filter(f => f.endsWith('.md'))
    //             .sort();
    //
    //         if (typeFiles.length > 0) {
    //             sidebarContent += `**Types**\n`;
    //             for (const file of typeFiles) {
    //                 const typeName = file.replace('.md', '');
    //                 sidebarContent += `* [${typeName}](types/${typeName})\n`;
    //             }
    //             sidebarContent += '\n';
    //         }
    //     }
    //
    //     // Add navigation links
    //     sidebarContent += `**Navigation**\n`;
    //     sidebarContent += `* [← Back to API Reference](../)\n`;
    //
    //     // Write sidebar file
    //     fs.writeFileSync(sidebarPath, sidebarContent);
    //
    // } catch (error) {
    //     console.error(`⚠️ Error occurred while generating sidebar for ${categoryName}:`, error);
    // }
}

// Fix link paths in API documentation (relative paths -> absolute paths)
function fixDocumentLinks(categoryDir, categoryName) {
    // Find all markdown files in the category
    const mdFiles = globSync(path.join(categoryDir, '**/*.md'));

    for (const mdFile of mdFiles) {
        try {
            // Current file's relative path (from docs directory)
            const relativePath = path.relative(DOCS_DIR, mdFile);
            // Directory containing current file (e.g., api-reference/core/classes)
            const fileDir = path.dirname(relativePath);
            // Current file name (e.g., FunctionRegistry.md)
            const fileName = path.basename(mdFile);
            // File name without extension (e.g., FunctionRegistry)
            const fileNameWithoutExt = fileName.replace('.md', '');

            // Read file content
            let content = fs.readFileSync(mdFile, 'utf-8');

            // Handle various link patterns
            // 1. README.md -> directory index
            content = content.replace(/\]\(README\.md(#[^)]+)?\)/g, (match, section) => {
                return section ? `](../${section})` : `](../)`;
            });

            // 2. ../README.md -> parent directory index
            content = content.replace(/\]\(\.\.\/README\.md(#[^)]+)?\)/g, (match, section) => {
                return section ? `](../../${section})` : `](../../)`;
            });

            // 3. Handle relative paths (e.g., ../interfaces/XXX.md -> ../interfaces/XXX)
            content = content.replace(/\]\(([^)]+)\.md(#[^)]*)?\)/g, (match, path, anchor) => {
                return `](${path}${anchor || ''})`;
            });

            // 4. Change modules links to README or current page anchors
            content = content.replace(/\]\(modules\)/g, '](README)');
            content = content.replace(/\]\(\.\/modules\)/g, '](./README)');

            // 5. Fix modules.html links with anchors - convert to current page anchors
            content = content.replace(/\]\(\.\/modules\.html(#[^)]+)\)/g, (match, anchor) => {
                return `](${anchor})`;
            });
            content = content.replace(/\]\(modules\.html(#[^)]+)\)/g, (match, anchor) => {
                return `](${anchor})`;
            });

            // 6. Fix modules#anchor links - convert to current page anchors (for README.md files)
            if (fileName === 'README.md' || fileName === 'modules.md') {
                content = content.replace(/\]\(modules(#[^)]+)\)/g, (match, anchor) => {
                    return `](${anchor})`;
                });
                content = content.replace(/\]\(\.\/modules(#[^)]+)\)/g, (match, anchor) => {
                    return `](${anchor})`;
                });
            }

            // Save file
            fs.writeFileSync(mdFile, content);
        } catch (error) {
            console.error(`⚠️ Error occurred while fixing links in ${mdFile}:`, error);
        }
    }
}

// Copy public directory files to .temp directory
function copyPublicFiles() {
    const publicDir = path.join(APPS_DOCS_DIR, 'public');
    const tempPublicDir = path.join(TEMP_DIR, 'public');

    if (!fs.existsSync(publicDir)) {
        return;
    }

    // Create temp public directory if it doesn't exist
    if (!fs.existsSync(tempPublicDir)) {
        fs.mkdirSync(tempPublicDir, { recursive: true });
    }

    // Copy all files from public to temp/public
    try {
        const files = fs.readdirSync(publicDir);
        for (const file of files) {
            const srcPath = path.join(publicDir, file);
            const destPath = path.join(tempPublicDir, file);

            if (fs.statSync(srcPath).isDirectory()) {
                // Recursively copy directories
                copyDirectoryRecursive(srcPath, destPath);
            } else {
                // Copy files
                fs.copyFileSync(srcPath, destPath);
            }
        }
    } catch (error) {
        console.error('⚠️ Error copying public files:', error);
    }
}

// Helper function to recursively copy directories
function copyDirectoryRecursive(src, dest) {
    if (!fs.existsSync(dest)) {
        fs.mkdirSync(dest, { recursive: true });
    }

    const files = fs.readdirSync(src);
    for (const file of files) {
        const srcPath = path.join(src, file);
        const destPath = path.join(dest, file);

        if (fs.statSync(srcPath).isDirectory()) {
            copyDirectoryRecursive(srcPath, destPath);
        } else {
            fs.copyFileSync(srcPath, destPath);
        }
    }
}

// Clean API reference directory before generation
function cleanApiReferenceDir() {
    if (fs.existsSync(OUTPUT_DIR)) {
        console.log('🧹 Cleaning existing API reference directory...');

        // Backup README.md file
        const readmePath = path.join(OUTPUT_DIR, 'README.md');
        let readmeContent = null;
        if (fs.existsSync(readmePath)) {
            readmeContent = fs.readFileSync(readmePath, 'utf-8');
        }

        // Delete entire folder
        fs.rmSync(OUTPUT_DIR, { recursive: true, force: true });

        // Recreate folder
        fs.mkdirSync(OUTPUT_DIR, { recursive: true });

        // Restore README.md file
        if (readmeContent) {
            fs.writeFileSync(readmePath, readmeContent);
            console.log('📄 Preserved existing README.md');
        }

        console.log('✅ API reference directory cleaned');
    }
}

async function main() {
    console.log('🔄 Converting TypeScript to API documentation...');

    // Clean existing API reference directory
    cleanApiReferenceDir();

    // Copy public files first
    copyPublicFiles();

    // Dynamically discover API categories
    const apiCategories = getApiCategories();
    console.log(`📋 Found ${apiCategories.length} packages with API documentation`);

    // Generate API index page with discovered packages
    generateApiIndexPage(apiCategories);

    // Generate documentation for each category
    let totalDocs = 0;
    for (const category of apiCategories) {
        const count = await generateDocsForCategory(category);
        totalDocs += count;
    }

    console.log(`✅ TypeDoc conversion completed! ${totalDocs} files processed.`);
}

// Execute main function
main().catch(error => {
    console.error('❌ Error occurred during API documentation generation:', error);
    process.exit(1);
}); 