import type { AutomationEnginePort } from '../../../../application/ports/AutomationEnginePort';
import type { HostedSessionConfig } from '../../../../domain/types/HostedSessionConfig';
import { StepId } from '../../../../domain/value-objects/StepId';
import type { IBrowserAutomation } from '../../../../application/ports/ScreenAutomationPort';
import type { SessionRepositoryPort } from '../../../../application/ports/SessionRepositoryPort';
import { StepTransitionValidator } from '../../../../domain/services/StepTransitionValidator';

type ValidationResult = {
  isValid: boolean;
  error?: string;
};

export class MockAutomationEngineAdapter implements AutomationEnginePort {
  private isRunning = false;
  private automationPromise: Promise<void> | null = null;

  constructor(
    public readonly browserAutomation: IBrowserAutomation,
    private readonly sessionRepository: SessionRepositoryPort
  ) {}

  private toStepConfig(config: HostedSessionConfig): Record<string, unknown> {
    const baseConfig: Record<string, unknown> = {
      sessionName: config.sessionName,
      trackId: config.trackId,
      carIds: [...config.carIds],
    };

    if (config.serverName !== undefined) baseConfig.serverName = config.serverName;
    if (config.password !== undefined) baseConfig.password = config.password;
    if (config.adminPassword !== undefined) baseConfig.adminPassword = config.adminPassword;
    if (config.maxDrivers !== undefined) baseConfig.maxDrivers = config.maxDrivers;
    if (config.carSearch !== undefined) baseConfig.carSearch = config.carSearch;
    if (config.trackSearch !== undefined) baseConfig.trackSearch = config.trackSearch;
    if (config.weatherType !== undefined) baseConfig.weatherType = config.weatherType;
    if (config.timeOfDay !== undefined) baseConfig.timeOfDay = config.timeOfDay;
    if (config.sessionDuration !== undefined) baseConfig.sessionDuration = config.sessionDuration;
    if (config.practiceLength !== undefined) baseConfig.practiceLength = config.practiceLength;
    if (config.qualifyingLength !== undefined) baseConfig.qualifyingLength = config.qualifyingLength;
    if (config.warmupLength !== undefined) baseConfig.warmupLength = config.warmupLength;
    if (config.raceLength !== undefined) baseConfig.raceLength = config.raceLength;
    if (config.startType !== undefined) baseConfig.startType = config.startType;
    if (config.restarts !== undefined) baseConfig.restarts = config.restarts;
    if (config.damageModel !== undefined) baseConfig.damageModel = config.damageModel;
    if (config.trackState !== undefined) baseConfig.trackState = config.trackState;

    return baseConfig;
  }

  async validateConfiguration(config: HostedSessionConfig): Promise<ValidationResult> {
    if (!config.sessionName || config.sessionName.trim() === '') {
      return { isValid: false, error: 'Session name is required' };
    }
    if (!config.trackId || config.trackId.trim() === '') {
      return { isValid: false, error: 'Track ID is required' };
    }
    if (!config.carIds || config.carIds.length === 0) {
      return { isValid: false, error: 'At least one car must be selected' };
    }
    return { isValid: true };
  }

  async executeStep(stepId: StepId, config: HostedSessionConfig): Promise<void> {
    const sessions = await this.sessionRepository.findAll();
    const session = sessions[0];
    if (!session) {
      throw new Error('No active session found');
    }

    // Start session if it's at step 1 and pending
    if (session.state.isPending() && stepId.value === 1) {
      session.start();
      await this.sessionRepository.update(session);
      
      // Start automated progression
      this.startAutomation(config);
    }
  }

  private startAutomation(config: HostedSessionConfig): void {
    if (this.isRunning) {
      return;
    }
    this.isRunning = true;
    this.automationPromise = this.runAutomationLoop(config);
  }

  private async runAutomationLoop(config: HostedSessionConfig): Promise<void> {
    while (this.isRunning) {
      try {
        const sessions = await this.sessionRepository.findAll();
        const session = sessions[0];
        
        if (!session || !session.state.isInProgress()) {
          this.isRunning = false;
          return;
        }

        const currentStep = session.currentStep;
        
        // Execute current step using the browser automation
        if (this.browserAutomation.executeStep) {
          const result = await this.browserAutomation.executeStep(
            currentStep,
            this.toStepConfig(config),
          );
          if (!result.success) {
            const stepDescription = StepTransitionValidator.getStepDescription(currentStep);
            const errorMessage = `Step ${currentStep.value} (${stepDescription}) failed: ${result.error}`;
            console.error(errorMessage);
            
            // Stop automation and mark session as failed
            this.isRunning = false;
            
            session.fail(errorMessage);
            await this.sessionRepository.update(session);
            return;
          }
        } else {
          // Fallback for adapters without executeStep (e.g., MockBrowserAutomationAdapter)
          await this.browserAutomation.navigateToPage(`step-${currentStep.value}`);
        }
        
        // Transition to next step
        if (!currentStep.isFinalStep()) {
          session.transitionToStep(currentStep.next());
          await this.sessionRepository.update(session);
          
          // If we just transitioned to the final step, execute it before stopping
          const nextStep = session.currentStep;
          if (nextStep.isFinalStep()) {
            // Execute final step handler
            if (this.browserAutomation.executeStep) {
              const result = await this.browserAutomation.executeStep(
                nextStep,
                this.toStepConfig(config),
              );
              if (!result.success) {
                const stepDescription = StepTransitionValidator.getStepDescription(nextStep);
                const errorMessage = `Step ${nextStep.value} (${stepDescription}) failed: ${result.error}`;
                console.error(errorMessage);
                // Don't try to fail terminal session - just log the error
                // Session is already in STOPPED_AT_STEP_18 state after transitionToStep()
              }
            }
            // Stop after final step
            this.isRunning = false;
            return;
          }
        } else {
          // Current step is already final - stop
          this.isRunning = false;
          return;
        }

        // Wait before next iteration
        await this.delay(500);
      } catch (error) {
        console.error('Automation error:', error);
        this.isRunning = false;

        try {
          const sessions = await this.sessionRepository.findAll();
          const session = sessions[0];
          if (session && !session.state.isTerminal()) {
            const message =
              error instanceof Error ? error.message : String(error);
            session.fail(`Automation error: ${message}`);
            await this.sessionRepository.update(session);
          }
        } catch {
        }

        return;
      }
    }
  }

  private delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  public stopAutomation(): void {
    this.isRunning = false;
    this.automationPromise = null;
  }
}