import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { DIContainer } from '../../../..//apps/companion/main/di-container';
import type { HostedSessionConfig } from 'apps/companion/main/automation/domain/types/HostedSessionConfig';
import { PlaywrightAutomationAdapter } from '../../../../apps/companion/main/automation/infrastructure/automation';

describe('companion start automation - browser connection failure before steps', () => {
  const originalEnv = { ...process.env };
  let originalTestLauncher: unknown;

  beforeEach(() => {
    process.env = { ...originalEnv, NODE_ENV: 'production' };
 
    originalTestLauncher = (PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
      testLauncher?: unknown;
    }).testLauncher;

    const failingLauncher = {
      launch: async () => {
        throw new Error('Simulated browser launch failure');
      },
      launchPersistentContext: async () => {
        throw new Error('Simulated persistent context failure');
      },
    };

    (PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
      testLauncher?: typeof failingLauncher;
    }).testLauncher = failingLauncher;

    DIContainer.resetInstance();
  });

  afterEach(async () => {
    const container = DIContainer.getInstance();
    await container.shutdown();
    DIContainer.resetInstance();
    (PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
      testLauncher?: unknown;
    }).testLauncher = originalTestLauncher;
    process.env = originalEnv;
  });

  it('fails browser connection and aborts before executing step 1', async () => {
    const container = DIContainer.getInstance();
    const startAutomationUseCase = container.getStartAutomationUseCase();
    const sessionRepository = container.getSessionRepository();
    const automationEngine = container.getAutomationEngine();

    const connectionResult = await container.initializeBrowserConnection();
    expect(connectionResult.success).toBe(false);
    expect(connectionResult.error).toBeDefined();

    const executeStepSpy = vi.spyOn(
      automationEngine,
      'executeStep',
    );

    const config: HostedSessionConfig = {
      sessionName: 'Companion integration connection failure',
      trackId: 'test-track',
      carIds: ['car-1'],
    };

    let sessionId: string | null = null;

    try {
      const dto = await startAutomationUseCase.execute(config);
      sessionId = dto.sessionId;
    } catch (error) {
      expect((error as Error).message).toBeDefined();
    }

    expect(executeStepSpy).not.toHaveBeenCalled();

    if (sessionId) {
      const session = await sessionRepository.findById(sessionId);
      if (session) {
        const message = session.errorMessage as string | undefined;
        if (message) {
          expect(message).not.toContain('Step 1 (LOGIN) failed: Browser not connected');
          expect(message.toLowerCase()).toContain('browser');
        }
      }
    }
  });

  it('treats successful adapter connect without a page as connection failure', async () => {
    const container = DIContainer.getInstance();
    const browserAutomation = container.getBrowserAutomation();
 
    expect(browserAutomation).toBeInstanceOf(PlaywrightAutomationAdapter);
 
    const AdapterWithPrototype = PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
      prototype: {
        connect: () => Promise<{ success: boolean; error?: string }>;
      };
    };
    const originalConnect = AdapterWithPrototype.prototype.connect;
 
    AdapterWithPrototype.prototype.connect = async function () {
      return { success: true };
    };

    try {
      const connectionResult = await container.initializeBrowserConnection();
      expect(connectionResult.success).toBe(false);
      expect(connectionResult.error).toBeDefined();
      expect(String(connectionResult.error).toLowerCase()).toContain('browser');
    } finally {
      AdapterWithPrototype.prototype.connect = originalConnect;
    }
  });
});