/**
 * Verify Command
 * Validates workflow and checks for dependency mismatches without generating code
 */

import * as fs from 'fs';
import * as path from 'path';
import * as yaml from 'js-yaml';
import { WorkflowEngine } from '../../engine/workflow-engine';
import { DependencyAnalyzer } from '../../generators/dependency-analyzer';
import { VersionManifest } from '../../generators/manifest-generator';

interface VerifyOptions {
  output?: string;
  verbose?: boolean;
}

export async function verifyCommand(workflowPath: string, options: VerifyOptions) {
  console.log('\n📊 Verification Report\n');

  try {
    // Read workflow file
    const workflowContent = fs.readFileSync(workflowPath, 'utf-8');
    const workflow = yaml.load(workflowContent) as any;

    console.log(`Workflow: ${workflow.workflow.name}`);
    console.log(`Version: ${workflow.workflow.version}`);
    console.log();

    // Validate workflow
    const engine = new WorkflowEngine();
    const validation = engine.validate(workflow);

    if (!validation.valid) {
      console.error('❌ Workflow Validation Failed:\n');
      validation.errors.forEach(error => console.error(`   ${error}`));
      process.exit(1);
    }

    if (validation.warnings.length > 0) {
      console.log('⚠️  Validation Warnings:\n');
      validation.warnings.forEach(warning => console.log(`   ${warning}`));
      console.log();
    }

    // Check for existing manifest
    const outputDir = options.output || process.cwd();
    const manifestPath = path.join(outputDir, '.bangstack', 'manifest.json');

    let currentManifest: VersionManifest | null = null;
    if (fs.existsSync(manifestPath)) {
      currentManifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
      if (currentManifest) {
        console.log('Current State:');
        console.log(`  Generated: ${new Date(currentManifest.generated_at).toLocaleString()}`);
        console.log(`  Version: ${currentManifest.workflow_version}`);
        console.log();
      }
    } else {
      console.log('Current State: No previous generation found\n');
    }

    // Analyze dependencies
    const analyzer = new DependencyAnalyzer();
    const componentAnalysis: Array<{
      name: string;
      type: string;
      technology: string;
      expected: string[];
      detected: string[];
      warnings: string[];
    }> = [];

    let hasWarnings = false;

    for (const [componentName, component] of Object.entries(workflow.stack || {})) {
      const comp = component as any;

      // Run dependency analysis
      const analysis = analyzer.analyzeComponent(
        outputDir,
        componentName,
        comp.type,
        comp.technology
      );

      const expectedDeps = comp.expected_dependencies?.map((d: any) => d.service) || [];
      const detectedDeps = analysis.detectedDependencies.map(d => d.service);

      // Compare dependencies
      const warnings: string[] = [];

      if (comp.expected_dependencies && comp.expected_dependencies.length > 0) {
        const comparisonWarnings = analyzer.compareDependencies(
          comp.expected_dependencies,
          analysis.detectedDependencies
        );
        warnings.push(...comparisonWarnings);
      }

      // Add analysis errors
      if (analysis.errors && analysis.errors.length > 0) {
        warnings.push(...analysis.errors);
      }

      if (warnings.length > 0) {
        hasWarnings = true;
      }

      componentAnalysis.push({
        name: componentName,
        type: comp.type,
        technology: comp.technology,
        expected: expectedDeps,
        detected: detectedDeps,
        warnings,
      });
    }

    // Compare with current manifest if it exists
    const changes: string[] = [];

    if (currentManifest) {
      // Version change
      if (currentManifest.workflow_version !== workflow.workflow.version) {
        changes.push(
          `📦 Version: ${currentManifest.workflow_version} → ${workflow.workflow.version}`
        );
      }

      // Infrastructure service changes
      const currentServices = Object.keys(currentManifest.infrastructure_services);
      const newServices = collectInfrastructureServices(workflow);
      const newServiceNames = Object.keys(newServices);

      const removedServices = currentServices.filter(s => !newServiceNames.includes(s));
      const addedServices = newServiceNames.filter(s => !currentServices.includes(s));

      if (removedServices.length > 0 || addedServices.length > 0) {
        changes.push('\nInfrastructure Services:');
        if (removedServices.length > 0) {
          changes.push(`  ➖ Removed: ${removedServices.join(', ')}`);
        }
        if (addedServices.length > 0) {
          changes.push(`  ➕ Added: ${addedServices.join(', ')}`);
        }
      }

      if (changes.length > 0) {
        console.log('Changes Detected:');
        changes.forEach(change => console.log(`  ${change}`));
        console.log();
      }
    }

    // Display component analysis
    if (componentAnalysis.length > 0) {
      console.log('Component Dependencies:\n');

      for (const comp of componentAnalysis) {
        const expectedStr = comp.expected.length > 0 ? comp.expected.join(', ') : 'none';
        const detectedStr = comp.detected.length > 0 ? comp.detected.join(', ') : 'none';

        const hasIssues = comp.warnings.length > 0;
        const statusIcon = hasIssues ? '⚠️ ' : '✓';

        console.log(`  ${statusIcon} ${comp.name} (${comp.technology}):`);
        console.log(`     Expected: ${expectedStr}`);
        console.log(`     Detected: ${detectedStr}`);

        if (comp.warnings.length > 0) {
          comp.warnings.forEach(warning => {
            console.log(`     ${warning}`);
          });
        }

        console.log();
      }
    }

    // Recommendations
    if (hasWarnings) {
      console.log('Recommendations:');

      // Check for orphaned client files
      if (currentManifest) {
        for (const [_componentName, component] of Object.entries(currentManifest.components)) {
          const fileNames = Object.keys(component.implementation_files);
          const currentServices = collectInfrastructureServices(workflow);
          const currentServiceNames = Object.keys(currentServices);

          for (const fileName of fileNames) {
            const serviceName = fileName.replace('-client.ts', '');
            if (!currentServiceNames.includes(serviceName)) {
              console.log(`  • Remove or update ${fileName} (no longer used)`);
            }
          }
        }
      }

      // Suggest missing implementations
      for (const comp of componentAnalysis) {
        for (const expected of comp.expected) {
          if (!comp.detected.includes(expected)) {
            console.log(`  • Implement ${expected} service integration in ${comp.name} component`);
          }
        }
      }

      console.log(`  • Run: bang generate ${workflowPath} -o ${outputDir}`);
      console.log();
    }

    // Summary
    const warningCount = componentAnalysis.reduce((sum, comp) => sum + comp.warnings.length, 0);

    if (warningCount > 0) {
      console.log(`Summary: ⚠️  ${warningCount} warning${warningCount === 1 ? '' : 's'} found - manual review required`);
      process.exit(1);
    } else {
      console.log('Summary: ✅ No issues found - ready to generate');
      process.exit(0);
    }

  } catch (error) {
    console.error(`\n❌ Error: ${error instanceof Error ? error.message : String(error)}\n`);
    process.exit(1);
  }
}

// Helper to collect infrastructure services (same as in ManifestGenerator)
function collectInfrastructureServices(workflow: any): Record<string, any> {
  const services: Record<string, any> = {};

  for (const [stageName, stage] of Object.entries(workflow.stages || {})) {
    const stageConfig = stage as any;
    const infraServices = stageConfig.infrastructure?.services || {};

    for (const [serviceName, serviceConfig] of Object.entries(infraServices)) {
      const config = serviceConfig as any;

      if (!services[serviceName]) {
        services[serviceName] = {
          providers: [],
          stages: [],
        };
      }

      if (config.provider && !services[serviceName].providers.includes(config.provider)) {
        services[serviceName].providers.push(config.provider);
      }

      services[serviceName].stages.push(stageName);
    }
  }

  return services;
}

// Attach helper as method for TypeScript context
(verifyCommand as any).collectInfrastructureServices = collectInfrastructureServices;
