#!/usr/bin/env node

/**
 * Generates TypeScript file with choice labels from Django TextChoices in Python models
 * 
 * Usage: node scripts/generate-choice-labels.cjs
 * 
 * This script reads Django models.py files from backend apps and extracts
 * TextChoices class definitions (format: VALUE = 'value', 'Czech Label') 
 * and generates a TypeScript file with runtime-accessible label mappings.
 * 
 * This is more reliable than parsing OpenAPI schema since it reads directly
 * from the source of truth (Python models).
 */

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

// Configuration - Backend Python apps to scan
const PYTHON_APPS = [
  path.join(__dirname, '../../backend/account'),
  path.join(__dirname, '../../backend/booking'),
  path.join(__dirname, '../../backend/commerce'),
  path.join(__dirname, '../../backend/servicedesk'),
  path.join(__dirname, '../../backend/product'),
  path.join(__dirname, '../../backend/configuration'),
];
const OUTPUT_PATH = path.join(__dirname, '../src/constants/choiceLabels.ts');

// Convert camelCase to UPPER_SNAKE_CASE
function camelToSnakeCase(str) {
  return str
    .replace(/([A-Z])/g, '_$1')
    .replace(/^_/, '')  // Remove leading underscore
    .toUpperCase();
}

// Extract TextChoices from Python models.py file
function parsePythonModels(filePath) {
  const content = fs.readFileSync(filePath, 'utf8');
  const results = {};
  
  // First, find all model class definitions to track context
  // Match: class ModelName(SoftDeleteModel): or class ModelName(models.Model):
  const modelRegex = /class\s+(\w+)\([^)]*(?:Model|SoftDeleteModel)[^)]*\):/g;
  const modelPositions = [];
  let modelMatch;
  
  while ((modelMatch = modelRegex.exec(content)) !== null) {
    modelPositions.push({
      name: modelMatch[1],
      start: modelMatch.index,
    });
  }
  
  // Match TextChoices class definitions:
  // class RoleChoices(models.TextChoices): or class StatusChoices(models.TextChoices):
  const classRegex = /class\s+(\w+Choices)\s*\([^)]*TextChoices[^)]*\):\s*\n((?:\s+\w+\s*=\s*[^\n]+\n?)+)/g;
  
  let classMatch;
  while ((classMatch = classRegex.exec(content)) !== null) {
    const [, className, classBody] = classMatch;
    const choicePosition = classMatch.index;
    
    // Find the parent model class (closest model before this choice)
    let parentModel = null;
    for (let i = modelPositions.length - 1; i >= 0; i--) {
      if (modelPositions[i].start < choicePosition) {
        parentModel = modelPositions[i].name;
        break;
      }
    }
    
    // Generate enum name based on parent model + choice class name
    // MarketSlot + StatusChoices -> MarketSlotStatusEnum
    // Reservation + StatusChoices -> ReservationStatusEnum (but spec uses Status9e5Enum)
    // Order + StatusChoices -> OrderStatusEnum
    // For top-level choices (no parent), use just the choice name
    let enumName;
    if (parentModel && className === 'StatusChoices') {
      // Use parent model name for nested StatusChoices
      enumName = `${parentModel}${className.replace(/Choices$/, 'Enum')}`;
    } else {
      // Top-level choices like RoleChoices, AccountTypeChoices
      enumName = className.replace(/Choices$/, 'Enum');
    }
    
    // Parse individual choice lines: ADMIN = 'admin', 'Administrátor'
    const choiceRegex = /\w+\s*=\s*['"]([^'"]+)['"],\s*['"]([^'"]+)['"]/g;
    const labels = {};
    
    let choiceMatch;
    while ((choiceMatch = choiceRegex.exec(classBody)) !== null) {
      const [, value, label] = choiceMatch;
      labels[value] = label;
    }
    
    if (Object.keys(labels).length > 0) {
      results[enumName] = labels;
    }
  }
  
  return results;
}

// Main function
function generateLabels() {
  console.log('🔍 Scanning Python models for TextChoices...');
  
  const enums = {};
  let totalFiles = 0;
  
  // Scan each backend app for models.py
  for (const appDir of PYTHON_APPS) {
    const appName = path.basename(appDir);
    const modelsFile = path.join(appDir, 'models.py');
    
    if (!fs.existsSync(modelsFile)) {
      continue;
    }
    
    console.log(`📁 Scanning ${appName}/models.py...`);
    totalFiles++;
    
    // Parse the models file
    const results = parsePythonModels(modelsFile);
    
    for (const [enumName, labels] of Object.entries(results)) {
      if (enums[enumName]) {
        // Check for conflicts
        const existing = JSON.stringify(enums[enumName]);
        const current = JSON.stringify(labels);
        
        if (existing !== current) {
          console.warn(`  ⚠️  ${enumName}: Conflict in ${appName}, keeping first version`);
        }
      } else {
        enums[enumName] = labels;
        console.log(`  ✓ ${enumName}: ${Object.keys(labels).length} labels`);
      }
    }
  }

  if (totalFiles === 0) {
    console.error('❌ No models.py files found in backend apps');
    process.exit(1);
  }

  if (Object.keys(enums).length === 0) {
    console.error('❌ No TextChoices found in Python models');
    process.exit(1);
  }

  // Generate TypeScript file
  console.log('📝 Generating TypeScript file...');

  const tsContent = `/**
 * Auto-generated choice labels from Django TextChoices in Python models
 * Generated by: scripts/generate-choice-labels.cjs
 * 
 * DO NOT EDIT MANUALLY - Run \`npm run api:gen\` to regenerate
 * 
 * Source: backend (TextChoices classes)
 */

${Object.entries(enums).map(([enumName, labels]) => {
  const enumBaseName = enumName.replace(/Enum$/, '');
  const constantName = camelToSnakeCase(enumBaseName) + '_LABELS';
  
  return `/**
 * Labels for ${enumName}
 * ${Object.entries(labels).map(([value, label]) => `* ${value}: ${label}`).join('\n * ')}
 */
export const ${constantName} = ${JSON.stringify(labels, null, 2)} as const;
`;
}).join('\n')}
/**
 * Type-safe helper to get choice label
 */
export function getChoiceLabel<T extends string>(
  labels: Record<string, string>,
  value: T | undefined | null
): string {
  if (!value) return '';
  return labels[value] || value;
}

/**
 * Get options array for select dropdowns
 */
export function getChoiceOptions<T extends string>(
  labels: Record<T, string>
): Array<{ value: T; label: string }> {
  return Object.entries(labels).map(([value, label]) => ({
    value: value as T,
    label: label as string,
  }));
}

// Auto-generate all OPTIONS exports
${Object.entries(enums).map(([enumName]) => {
  const enumBaseName = enumName.replace(/Enum$/, '');
  const labelsConstName = camelToSnakeCase(enumBaseName) + '_LABELS';
  const optionsConstName = camelToSnakeCase(enumBaseName) + '_OPTIONS';
  return `export const ${optionsConstName} = getChoiceOptions(${labelsConstName});`;
}).join('\n')}
`;

  // Ensure output directory exists
  const outputDir = path.dirname(OUTPUT_PATH);
  if (!fs.existsSync(outputDir)) {
    fs.mkdirSync(outputDir, { recursive: true });
  }

  // Write file
  fs.writeFileSync(OUTPUT_PATH, tsContent, 'utf8');

  console.log(`✅ Generated ${OUTPUT_PATH}`);
  console.log(`   Found ${Object.keys(enums).length} enum types with labels`);
}

// Run the script
try {
  generateLabels();
} catch (error) {
  console.error('❌ Error generating choice labels:', error.message);
  process.exit(1);
}
