import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { MockBrowserAutomationAdapter } from '../../../packages/infrastructure/adapters/automation/MockBrowserAutomationAdapter';
import { StepId } from '../../../packages/domain/value-objects/StepId';

describe('MockBrowserAutomationAdapter Integration Tests', () => {
  let adapter: MockBrowserAutomationAdapter;

  beforeEach(() => {
    adapter = new MockBrowserAutomationAdapter();
  });

  describe('navigateToPage', () => {
    it('should simulate navigation with delay', async () => {
      const url = 'https://members.iracing.com/membersite/HostedRacing';

      const result = await adapter.navigateToPage(url);

      expect(result.success).toBe(true);
      expect(result.loadTime).toBeGreaterThan(0);
    });

    it('should return navigation URL in result', async () => {
      const url = 'https://members.iracing.com/membersite/HostedRacing';

      const result = await adapter.navigateToPage(url);

      expect(result.url).toBe(url);
    });

    it('should simulate realistic delays', async () => {
      const url = 'https://members.iracing.com/membersite/HostedRacing';

      const result = await adapter.navigateToPage(url);

      expect(result.loadTime).toBeGreaterThanOrEqual(200);
      expect(result.loadTime).toBeLessThanOrEqual(800);
    });
  });

  describe('fillFormField', () => {
    it('should simulate form field fill with delay', async () => {
      const fieldName = 'session-name';
      const value = 'Test Race Session';

      const result = await adapter.fillFormField(fieldName, value);

      expect(result.success).toBe(true);
      expect(result.fieldName).toBe(fieldName);
      expect(result.valueSet).toBe(value);
    });

    it('should simulate typing speed delay', async () => {
      const fieldName = 'session-name';
      const value = 'A'.repeat(50);

      const result = await adapter.fillFormField(fieldName, value);

      expect(result.valueSet).toBeDefined();
    });

    it('should handle empty field values', async () => {
      const fieldName = 'session-name';
      const value = '';

      const result = await adapter.fillFormField(fieldName, value);

      expect(result.success).toBe(true);
      expect(result.valueSet).toBe('');
    });
  });

  describe('clickElement', () => {
    it('should simulate button click with delay', async () => {
      const selector = '#create-session-button';

      const result = await adapter.clickElement(selector);

      expect(result.success).toBe(true);
      expect(result.target).toBe(selector);
    });

    it('should simulate click delays', async () => {
      const selector = '#submit-button';

      const result = await adapter.clickElement(selector);

      expect(result.target).toBeDefined();
    });
  });

  describe('waitForElement', () => {
    it('should simulate waiting for element to appear', async () => {
      const selector = '.modal-dialog';

      const result = await adapter.waitForElement(selector);

      expect(result.success).toBe(true);
      expect(result.target).toBe(selector);
    });

    it('should simulate element load time', async () => {
      const selector = '.loading-spinner';

      const result = await adapter.waitForElement(selector);

      expect(result.waitedMs).toBeGreaterThanOrEqual(100);
      expect(result.waitedMs).toBeLessThanOrEqual(1000);
    });

    it('should timeout after maximum wait time', async () => {
      const selector = '.non-existent-element';
      const maxWaitMs = 5000;

      const result = await adapter.waitForElement(selector, maxWaitMs);
      expect(result.success).toBe(true);
    });
  });

  describe('handleModal', () => {
    it('should simulate modal handling for step 6', async () => {
      const stepId = StepId.create(6);
      const action = 'close';

      const result = await adapter.handleModal(stepId, action);

      expect(result.success).toBe(true);
      expect(result.stepId).toBe(6);
      expect(result.action).toBe(action);
    });

    it('should simulate modal handling for step 9', async () => {
      const stepId = StepId.create(9);
      const action = 'confirm';

      const result = await adapter.handleModal(stepId, action);

      expect(result.success).toBe(true);
      expect(result.stepId).toBe(9);
    });

    it('should simulate modal handling for step 12', async () => {
      const stepId = StepId.create(12);
      const action = 'select';

      const result = await adapter.handleModal(stepId, action);

      expect(result.success).toBe(true);
      expect(result.stepId).toBe(12);
    });

    it('should throw error for non-modal steps', async () => {
      const stepId = StepId.create(1);
      const action = 'close';

      await expect(adapter.handleModal(stepId, action)).rejects.toThrow(
        'Step 1 is not a modal step'
      );
    });

    it('should simulate modal interaction delays', async () => {
      const stepId = StepId.create(6);
      const action = 'close';

      const result = await adapter.handleModal(stepId, action);

      expect(result.success).toBe(true);
      expect(result.stepId).toBe(6);
      expect(result.action).toBe(action);
    });
  });

  describe('executeStep', () => {
    it('should execute step 1 (navigation)', async () => {
      const stepId = StepId.create(1);
      const config = {
        sessionName: 'Test Race',
        trackId: 'spa',
        carIds: ['dallara-f3'],
      };

      const result = await adapter.executeStep(stepId, config);

      expect(result.success).toBe(true);
      expect(result.stepId).toBe(1);
    });

    it('should execute step 6 (modal step)', async () => {
      const stepId = StepId.create(6);
      const config = {
        sessionName: 'Test Race',
        trackId: 'spa',
        carIds: ['dallara-f3'],
      };

      const result = await adapter.executeStep(stepId, config);

      expect(result.success).toBe(true);
      expect(result.stepId).toBe(6);
      expect(result.wasModalStep).toBe(true);
    });

    it('should execute step 18 (final step)', async () => {
      const stepId = StepId.create(18);
      const config = {
        sessionName: 'Test Race',
        trackId: 'spa',
        carIds: ['dallara-f3'],
      };

      const result = await adapter.executeStep(stepId, config);

      expect(result.success).toBe(true);
      expect(result.stepId).toBe(18);
      expect(result.shouldStop).toBe(true);
    });

    it('should simulate realistic step execution times', async () => {
      const stepId = StepId.create(5);
      const config = {
        sessionName: 'Test Race',
        trackId: 'spa',
        carIds: ['dallara-f3'],
      };

      const result = await adapter.executeStep(stepId, config);

      expect(result.executionTime).toBeGreaterThan(0);
    });
  });

  describe('error simulation', () => {
    it('should simulate random failures when enabled', async () => {
      const adapterWithFailures = new MockBrowserAutomationAdapter({
        simulateFailures: true,
        failureRate: 1.0, // Always fail
      });

      const stepId = StepId.create(5);
      const config = {
        sessionName: 'Test Race',
        trackId: 'spa',
        carIds: ['dallara-f3'],
      };

      await expect(adapterWithFailures.executeStep(stepId, config)).rejects.toThrow();
    });

    it('should not fail when failure simulation disabled', async () => {
      const adapterNoFailures = new MockBrowserAutomationAdapter({
        simulateFailures: false,
      });

      const stepId = StepId.create(5);
      const config = {
        sessionName: 'Test Race',
        trackId: 'spa',
        carIds: ['dallara-f3'],
      };

      const result = await adapterNoFailures.executeStep(stepId, config);

      expect(result.success).toBe(true);
    });
  });

  describe('performance metrics', () => {
    it('should track operation metrics', async () => {
      const stepId = StepId.create(1);
      const config = {
        sessionName: 'Test Race',
        trackId: 'spa',
        carIds: ['dallara-f3'],
      };

      const result = await adapter.executeStep(stepId, config);

      expect(result.metrics).toBeDefined();
      expect(result.metrics.totalDelay).toBeGreaterThan(0);
      expect(result.metrics.operationCount).toBeGreaterThan(0);
    });
  });
});