#!/usr/bin/env npx tsx

import * as fs from 'fs';
import * as path from 'path';

interface EndpointInfo {
  path: string;
  method: string;
  description: string;
  operationId: string;
}

interface CategoryInfo {
  name: string;
  endpoints: EndpointInfo[];
}

/**
 * Parse the gen.ts file and extract all API endpoint information
 */
function parseGenFile(filePath: string): EndpointInfo[] {
  const content = fs.readFileSync(filePath, 'utf-8');
  const endpoints: EndpointInfo[] = [];

  // Match the paths interface content
  const pathsInterfaceMatch = content.match(/export interface paths \{([\s\S]*?)\n\}/);
  if (!pathsInterfaceMatch) {
    throw new Error('Could not find paths interface in gen.ts file');
  }

  const pathsContent = pathsInterfaceMatch[1];
  
  // Regex to match each endpoint definition
  const endpointRegex = /\s*'([^']+)':\s*\{\s*((?:\s*\/\*\*[\s\S]*?\*\/\s*)?[a-z]+:\s*operations\[[^\]]+\];\s*)*\s*\}/g;
  
  let match: RegExpExecArray | null;
  while ((match = endpointRegex.exec(pathsContent)) !== null) {
    const endpointPath = match[1];
    const endpointBlock = match[2];
    
    // Extract individual HTTP methods within this endpoint
    const methodRegex = /(?:\s*\/\*\*\s*([\s\S]*?)\s*\*\/\s*)?([a-z]+):\s*operations\['([^']+)'\]/g;
    
    let methodMatch: RegExpExecArray | null;
    while ((methodMatch = methodRegex.exec(endpointBlock)) !== null) {
      const rawDescription = methodMatch[1];
      const method = methodMatch[2].toUpperCase();
      const operationId = methodMatch[3];
      
      // Clean up description
      let description = 'No description available';
      if (rawDescription) {
        // Extract the main description, handling JSDoc format
        const descMatch = rawDescription.match(/^\s*([^\n@]*)/);
        if (descMatch && descMatch[1].trim()) {
          description = descMatch[1].trim();
        }
        
        // Look for @description tag
        const descriptionMatch = rawDescription.match(/@description\s+([\s\S]+?)(?:\n|\*\/|$)/);
        if (descriptionMatch) {
          description = descriptionMatch[1].replace(/\s*\*\s*/g, ' ').trim();
        }
      }
      
      endpoints.push({
        path: endpointPath,
        method,
        description,
        operationId
      });
    }
  }

  return endpoints.sort((a, b) => a.path.localeCompare(b.path));
}

/**
 * Group endpoints by category based on their path prefix
 */
function groupEndpointsByCategory(endpoints: EndpointInfo[]): CategoryInfo[] {
  const categories = new Map<string, EndpointInfo[]>();

  endpoints.forEach(endpoint => {
    // Extract category from path (e.g., "/api/billing/info" -> "billing")
    const pathParts = endpoint.path.split('/');
    let category = 'Other';
    
    if (pathParts.length >= 3 && pathParts[1] === 'api') {
      category = pathParts[2];
    }
    
    if (!categories.has(category)) {
      categories.set(category, []);
    }
    categories.get(category)!.push(endpoint);
  });

  // Convert to array and sort
  return Array.from(categories.entries())
    .map(([name, endpoints]) => ({
      name: name.charAt(0).toUpperCase() + name.slice(1),
      endpoints: endpoints.sort((a, b) => a.path.localeCompare(b.path))
    }))
    .sort((a, b) => a.name.localeCompare(b.name));
}

/**
 * Generate Markdown documentation
 */
function generateMarkdownDocs(categories: CategoryInfo[]): string {
  const totalEndpoints = categories.reduce((sum, cat) => sum + cat.endpoints.length, 0);
  
  let markdown = `# API Endpoints Documentation

This documentation contains ${totalEndpoints} API endpoints extracted from the OpenAPI specification.

## Table of Contents

`;

  // Generate table of contents
  categories.forEach(category => {
    markdown += `- [${category.name}](#${category.name.toLowerCase()}) (${category.endpoints.length} endpoints)\n`;
  });

  markdown += '\n## Endpoints by Category\n\n';

  // Generate documentation for each category
  categories.forEach(category => {
    markdown += `### ${category.name}\n\n`;
    markdown += `| Method | Path | Description |\n`;
    markdown += `|--------|------|-------------|\n`;

    category.endpoints.forEach(endpoint => {
      const description = endpoint.description.replace(/\|/g, '\\|').replace(/\n/g, ' ');
      markdown += `| ${endpoint.method} | \`${endpoint.path}\` | ${description} |\n`;
    });

    markdown += '\n';
  });

  // Add summary statistics
  markdown += '## Summary\n\n';
  markdown += `- **Total Endpoints**: ${totalEndpoints}\n`;
  markdown += `- **Categories**: ${categories.length}\n\n`;

  const methodCounts = new Map<string, number>();
  categories.forEach(category => {
    category.endpoints.forEach(endpoint => {
      methodCounts.set(endpoint.method, (methodCounts.get(endpoint.method) || 0) + 1);
    });
  });

  markdown += '### HTTP Methods\n\n';
  Array.from(methodCounts.entries())
    .sort(([,a], [,b]) => b - a)
    .forEach(([method, count]) => {
      markdown += `- **${method}**: ${count} endpoints\n`;
    });

  markdown += `\n*Generated on ${new Date().toISOString()}*\n`;

  return markdown;
}

/**
 * Generate JSON documentation
 */
function generateJsonDocs(categories: CategoryInfo[]): object {
  return {
    metadata: {
      generatedAt: new Date().toISOString(),
      totalEndpoints: categories.reduce((sum, cat) => sum + cat.endpoints.length, 0),
      totalCategories: categories.length
    },
    categories: categories.map(category => ({
      name: category.name,
      count: category.endpoints.length,
      endpoints: category.endpoints.map(endpoint => ({
        path: endpoint.path,
        method: endpoint.method,
        description: endpoint.description,
        operationId: endpoint.operationId
      }))
    }))
  };
}

/**
 * Main function
 */
async function main() {
  try {
    const genFilePath = path.join(process.cwd(), 'src', 'utils', 'gen.ts');
    const docsDir = path.join(process.cwd(), 'docs');

    console.log('🔍 Parsing OpenAPI TypeScript file...');
    const endpoints = parseGenFile(genFilePath);
    console.log(`✅ Found ${endpoints.length} endpoints`);

    console.log('📂 Grouping endpoints by category...');
    const categories = groupEndpointsByCategory(endpoints);
    console.log(`✅ Grouped into ${categories.length} categories`);

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

    console.log('📝 Generating Markdown documentation...');
    const markdownDocs = generateMarkdownDocs(categories);
    fs.writeFileSync(path.join(docsDir, 'api-endpoints.md'), markdownDocs);
    console.log('✅ Created docs/api-endpoints.md');

    console.log('🔧 Generating JSON documentation...');
    const jsonDocs = generateJsonDocs(categories);
    fs.writeFileSync(path.join(docsDir, 'api-endpoints.json'), JSON.stringify(jsonDocs, null, 2));
    console.log('✅ Created docs/api-endpoints.json');

    // Print summary
    console.log('\n📊 Summary:');
    console.log(`   Total endpoints: ${endpoints.length}`);
    console.log(`   Categories: ${categories.length}`);
    categories.slice(0, 5).forEach(cat => {
      console.log(`   - ${cat.name}: ${cat.endpoints.length} endpoints`);
    });
    if (categories.length > 5) {
      console.log(`   - ... and ${categories.length - 5} more categories`);
    }

    console.log('\n✨ Documentation generation complete!');

  } catch (error) {
    console.error('❌ Error generating documentation:', error);
    process.exit(1);
  }
}

// Run the script
main();