import { StepId } from '../../../packages/domain/value-objects/StepId';
import { HostedSessionConfig } from '../../../packages/domain/entities/HostedSessionConfig';
import { IBrowserAutomation } from '../../../packages/application/ports/IBrowserAutomation';
import {
  NavigationResult,
  FormFillResult,
  ClickResult,
  WaitResult,
  ModalResult,
} from '../../../packages/application/ports/AutomationResults';

interface MockConfig {
  simulateFailures?: boolean;
  failureRate?: number;
}

interface StepExecutionResult {
  success: boolean;
  stepId: number;
  wasModalStep?: boolean;
  shouldStop?: boolean;
  executionTime: number;
  metrics: {
    totalDelay: number;
    operationCount: number;
  };
}

export class MockBrowserAutomationAdapter implements IBrowserAutomation {
  private config: MockConfig;
  private connected: boolean = false;

  constructor(config: MockConfig = {}) {
    this.config = {
      simulateFailures: config.simulateFailures ?? false,
      failureRate: config.failureRate ?? 0.1,
    };
  }

  async connect(): Promise<void> {
    this.connected = true;
  }

  async disconnect(): Promise<void> {
    this.connected = false;
  }

  isConnected(): boolean {
    return this.connected;
  }

  async navigateToPage(url: string): Promise<NavigationResult> {
    const delay = this.randomDelay(200, 800);
    await this.sleep(delay);
    return {
      success: true,
      url,
      loadTime: delay,
    };
  }

  async fillFormField(fieldName: string, value: string): Promise<FormFillResult> {
    const delay = this.randomDelay(100, 500);
    await this.sleep(delay);
    return {
      success: true,
      fieldName,
      valueSet: value,
    };
  }

  async clickElement(selector: string): Promise<ClickResult> {
    const delay = this.randomDelay(50, 300);
    await this.sleep(delay);
    return {
      success: true,
      target: selector,
    };
  }

  async waitForElement(selector: string, maxWaitMs: number = 5000): Promise<WaitResult> {
    const delay = this.randomDelay(100, 1000);
    
    await this.sleep(delay);
    
    return {
      success: true,
      target: selector,
      waitedMs: delay,
      found: true,
    };
  }

  async handleModal(stepId: StepId, action: string): Promise<ModalResult> {
    if (!stepId.isModalStep()) {
      throw new Error(`Step ${stepId.value} is not a modal step`);
    }
    
    const delay = this.randomDelay(200, 600);
    await this.sleep(delay);
    return {
      success: true,
      stepId: stepId.value,
      action,
    };
  }

  async executeStep(stepId: StepId, config: HostedSessionConfig): Promise<StepExecutionResult> {
    if (this.shouldSimulateFailure()) {
      throw new Error(`Simulated failure at step ${stepId.value}`);
    }

    const startTime = Date.now();
    let totalDelay = 0;
    let operationCount = 0;

    const navigationDelay = this.randomDelay(200, 500);
    await this.sleep(navigationDelay);
    totalDelay += navigationDelay;
    operationCount++;

    if (stepId.isModalStep()) {
      const modalDelay = this.randomDelay(200, 400);
      await this.sleep(modalDelay);
      totalDelay += modalDelay;
      operationCount++;
    }

    const executionTime = Date.now() - startTime;

    return {
      success: true,
      stepId: stepId.value,
      wasModalStep: stepId.isModalStep(),
      shouldStop: stepId.isFinalStep(),
      executionTime,
      metrics: {
        totalDelay,
        operationCount,
      },
    };
  }

  private randomDelay(min: number, max: number): number {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }

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

  private shouldSimulateFailure(): boolean {
    if (!this.config.simulateFailures) {
      return false;
    }
    return Math.random() < (this.config.failureRate || 0.1);
  }
}