#!/usr/bin/env node

import { container } from 'tsyringe';
import { IResolutionService } from '@services/resolution/ResolutionService/IResolutionService.js';
import { IStateService } from '@services/state/StateService/IStateService.js';
import { IParserService } from '@services/pipeline/ParserService/IParserService.js';
import { IInterpreterService } from '@services/pipeline/InterpreterService/IInterpreterService.js';
import { IFileSystemService } from '@services/fs/FileSystemService/IFileSystemService.js';
import { MeldResolutionError } from '@core/errors/MeldResolutionError.js';
import path from 'path';
import chalk from 'chalk';
import { VariableResolutionTracker, ResolutionTrackingConfig } from '../../tests/utils/debug/index.js';
import { IPathService } from '@services/fs/PathService/IPathService.js';

// Import concrete classes for direct instantiation
import { ResolutionService } from '@services/resolution/ResolutionService/ResolutionService.js';
import { StateService } from '@services/state/StateService/StateService.js';
import { ParserService } from '@services/pipeline/ParserService/ParserService.js';
import { InterpreterService } from '@services/pipeline/InterpreterService/InterpreterService.js';
import { FileSystemService } from '@services/fs/FileSystemService/FileSystemService.js';
import { PathService } from '@services/fs/PathService/PathService.js';
import { NodeFileSystem } from '@services/fs/FileSystemService/NodeFileSystem.js';
import { PathOperationsService } from '@services/fs/FileSystemService/PathOperationsService.js';
import { DirectiveService } from '@services/pipeline/DirectiveService/DirectiveService.js';
import { ValidationService } from '@services/resolution/ValidationService/ValidationService.js';
import { CircularityService } from '@services/resolution/CircularityService/CircularityService.js';

interface DebugResolutionOptions {
  filePath: string;
  variableName?: string;
  watchMode?: boolean;
  outputFormat?: 'json' | 'text';
}

// Define interfaces for the resolution tracker types
interface ResolutionAttempt {
  variableName: string;
  context: string;
  timestamp: number;
  success: boolean;
  value?: any;
  source?: string;
  contextBoundary?: {
    type: 'parent-to-child' | 'child-to-parent';
    sourceId?: string;
    targetId?: string;
  };
}

/**
 * Debug variable resolution in a Meld file
 */
export async function debugResolutionCommand(options: DebugResolutionOptions): Promise<void> {
  const { filePath, variableName, outputFormat = 'text' } = options;
  
  console.log('DEBUG: debug-resolution command started with options', JSON.stringify(options));
  console.log(chalk.blue('Debug resolution command started'));
  console.log(chalk.blue('Options:'), JSON.stringify(options, null, 2));
  
  try {
    // Create service instances directly instead of using DI
    console.log(chalk.blue('Creating services...'));
    
    // Create the path operations service (needed for FileSystemService)
    const pathOps = new PathOperationsService();
    
    // Create the node file system implementation
    const nodeFs = new NodeFileSystem();
    
    // Create the base services first
    const stateService = new StateService();
    const fileSystemService = new FileSystemService(pathOps, nodeFs);
    const parserService = new ParserService();
    const pathService = new PathService();
    
    // Initialize the path service
    pathService.initialize(fileSystemService, parserService);
    
    // Initialize paths in the state service
    const resolvedPath = path.resolve(filePath);
    const projectPath = path.dirname(resolvedPath);
    console.log(chalk.blue('Project path:'), projectPath);
    
    stateService.setPathVar('PROJECTPATH', projectPath);
    stateService.setPathVar('.', projectPath);
    stateService.setCurrentFilePath(filePath);
    
    // Create services that depend on the base services
    const resolutionService = new ResolutionService(
      stateService,
      fileSystemService,
      parserService,
      pathService
    );
    
    // Create the validation service
    const validationService = new ValidationService();
    
    // Create the interpreter service first
    const interpreterService = new InterpreterService();
    
    // Create the circularity service
    const circularityService = new CircularityService();
    
    // Create the directive service
    const directiveService = new DirectiveService();
    directiveService.initialize(
      validationService,
      stateService,
      pathService,
      fileSystemService,
      parserService,
      interpreterService, // Provide the interpreter service
      circularityService, // CircularityService
      resolutionService
    );
    
    // Now initialize the interpreter service with the directive service
    interpreterService.initialize(directiveService, stateService);
    
    // Register default handlers
    directiveService.registerDefaultHandlers();
    
    // Enable resolution tracking if a variable name is provided
    let tracker: VariableResolutionTracker | undefined;
    
    console.log(chalk.blue('Enabling resolution tracking...'));
    if (typeof resolutionService.enableResolutionTracking === 'function') {
      console.log(chalk.blue('enableResolutionTracking method found'));
      const config: ResolutionTrackingConfig = {
        enabled: true
      };
      
      if (variableName) {
        console.log(chalk.blue(`Watching variable: ${variableName}`));
        config.watchVariables = [variableName];
      }
      
      resolutionService.enableResolutionTracking(config);
      console.log(chalk.blue('Resolution tracking enabled'));
    } else {
      console.warn(chalk.yellow('Resolution tracking is not available - enableResolutionTracking method missing'));
    }
    
    console.log(chalk.blue(`Processing file: ${filePath}`));
    
    // Check if file exists
    if (!await fileSystemService.exists(filePath)) {
      console.error(chalk.red(`File not found: ${filePath}`));
      return;
    }
    
    // Read file content
    console.log(chalk.blue('Reading file content...'));
    const fileContent = await fileSystemService.readFile(filePath);
    console.log(chalk.blue('File content length:'), fileContent.length);
    
    // Create a root state
    console.log(chalk.blue('Creating root state...'));
    const rootState = stateService;
    
    // Parse the file
    console.log(chalk.blue('Parsing file...'));
    const nodes = await parserService.parse(fileContent);
    console.log(chalk.blue('Parsed nodes:'), nodes.length);
    
    // Process the file
    console.log(chalk.blue('Interpreting nodes...'));
    await interpreterService.interpret(nodes, {
      initialState: rootState,
      filePath,
      mergeState: true
    });
    console.log(chalk.blue('Interpretation complete'));
    
    // Get resolution attempts
    let attempts: ResolutionAttempt[] = [];
    if (typeof resolutionService.getResolutionTracker === 'function') {
      console.log(chalk.blue('Getting resolution attempts...'));
      attempts = resolutionService.getResolutionTracker()?.getAttempts() as ResolutionAttempt[] || [];
      console.log(chalk.blue('Resolution attempts:'), attempts.length);
    }
    
    // Output results
    if (outputFormat === 'json') {
      console.log(JSON.stringify(attempts, null, 2));
    } else {
      // Group attempts by variable
      console.log(chalk.blue('\nResolution attempts by variable:'));
      
      const attemptsByVariable: Record<string, ResolutionAttempt[]> = {};
      
      for (const attempt of attempts) {
        if (!attemptsByVariable[attempt.variableName]) {
          attemptsByVariable[attempt.variableName] = [];
        }
        attemptsByVariable[attempt.variableName].push(attempt);
      }
      
      // Display attempts by variable
      for (const [variable, variableAttempts] of Object.entries(attemptsByVariable)) {
        console.log(chalk.green(`\nVariable: ${variable}`));
        
        for (const attempt of variableAttempts) {
          const status = attempt.success ? chalk.green('✓') : chalk.red('✗');
          const value = attempt.success ? chalk.cyan(JSON.stringify(attempt.value)) : chalk.red('not found');
          const context = chalk.yellow(attempt.context);
          
          console.log(`  ${status} Context: ${context}`);
          console.log(`     Value: ${value}`);
          
          if (attempt.source) {
            console.log(`     Source: ${chalk.magenta(attempt.source)}`);
          }
          
          if (attempt.contextBoundary) {
            const boundaryType = attempt.contextBoundary.type;
            const source = attempt.contextBoundary.sourceId || 'unknown';
            const target = attempt.contextBoundary.targetId || 'unknown';
            
            console.log(`     Boundary: ${chalk.blue(boundaryType)} from ${source} to ${target}`);
          }
        }
      }
      
      // Summary
      console.log(chalk.blue('\nSummary:'));
      console.log(`Total attempts: ${attempts.length}`);
      console.log(`Successful attempts: ${attempts.filter(a => a.success).length}`);
      console.log(`Failed attempts: ${attempts.filter(a => !a.success).length}`);
    }
    
  } catch (error) {
    console.error(chalk.red('Error:'), error);
    
    if (error instanceof MeldResolutionError) {
      console.error(chalk.red(`Resolution error: ${error.message}`));
      if (error.details) {
        console.error(chalk.red(`Details: ${JSON.stringify(error.details, null, 2)}`));
      }
    } else {
      console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
      if (error instanceof Error && error.stack) {
        console.error(chalk.dim(error.stack));
      }
    }
    console.error(chalk.yellow('If this is a module resolution error, make sure you have built the codebase with "npm run build" before running debug commands'));
  }
}