import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { DIContainer } from '../../../apps/companion/main/di-container';
import { StepId } from 'apps/companion/main/automation/domain/value-objects/StepId';
import type { HostedSessionConfig } from 'apps/companion/main/automation/domain/types/HostedSessionConfig';
import { PlaywrightAutomationAdapter } from 'core/automation/infrastructure//automation';

describe('Companion UI - hosted workflow via fixture-backed real stack', () => {
  let container: DIContainer;
  let adapter: PlaywrightAutomationAdapter;
  let sessionId: string;
  let originalEnv: string | undefined;
  let originalFixtureFlag: string | undefined;

  beforeAll(async () => {
    originalEnv = process.env.NODE_ENV;
    originalFixtureFlag = process.env.COMPANION_FIXTURE_HOSTED;
    Object.defineProperty(process.env, 'NODE_ENV', {
      value: 'test',
      writable: true,
      enumerable: true,
      configurable: true
    });
    process.env.COMPANION_FIXTURE_HOSTED = '1';

    DIContainer.resetInstance();
    container = DIContainer.getInstance();

    const connection = await container.initializeBrowserConnection();
    expect(connection.success).toBe(true);

    const browserAutomation = container.getBrowserAutomation();
    expect(browserAutomation).toBeInstanceOf(PlaywrightAutomationAdapter);
    adapter = browserAutomation as PlaywrightAutomationAdapter;
    expect(adapter.isConnected()).toBe(true);
    expect(adapter.getPage()).not.toBeNull();
  }, 120000);

  afterAll(async () => {
    await container.shutdown();
    Object.defineProperty(process.env, 'NODE_ENV', {
      value: originalEnv,
      writable: true,
      enumerable: true,
      configurable: true
    });
    process.env.COMPANION_FIXTURE_HOSTED = originalFixtureFlag;
  });

  async function waitForFinalSession(deadlineMs: number) {
    const repo = container.getSessionRepository();
    const deadline = Date.now() + deadlineMs;
    let finalSession = null;

    // eslint-disable-next-line no-constant-condition
    while (true) {
      const sessions = await repo.findAll();
      finalSession = sessions[0] ?? null;

      if (finalSession && (finalSession.state.isStoppedAtStep18() || finalSession.state.isCompleted())) {
        break;
      }

      if (Date.now() > deadline) {
        throw new Error('Timed out waiting for hosted workflow to complete via companion DI stack');
      }

      await new Promise((resolve) => setTimeout(resolve, 250));
    }

    return finalSession;
  }

  it(
    'drives AutomationEngineAdapter via DI over fixtures and shows overlay progress',
    async () => {
      const startUseCase = container.getStartAutomationUseCase();
      const repo = container.getSessionRepository();

      const config: HostedSessionConfig = {
        sessionName: 'Companion E2E - fixture hosted workflow',
        serverName: 'Companion Fixture Server',
        password: 'companion',
        adminPassword: 'admin-companion',
        maxDrivers: 20,
        trackId: 'spa',
        carIds: ['dallara-f3'],
        weatherType: 'dynamic',
        timeOfDay: 'afternoon',
        sessionDuration: 60,
        practiceLength: 10,
        qualifyingLength: 10,
        warmupLength: 5,
        raceLength: 30,
        startType: 'standing',
        restarts: 'single-file',
        damageModel: 'realistic',
        trackState: 'auto'
      };

      const dto = await startUseCase.execute(config);
      expect(dto.state).toBe('PENDING');
      expect(dto.currentStep).toBe(1);
      sessionId = dto.sessionId;

      const session = await repo.findById(sessionId);
      expect(session).not.toBeNull();
      expect(session!.state.isPending()).toBe(true);

      await adapter.navigateToPage('http://localhost:3456/');
      const engine = container.getAutomationEngine();
      await engine.executeStep(StepId.create(1), config);

      const page = adapter.getPage();
      expect(page).not.toBeNull();

      await page!.waitForSelector('#gridpilot-overlay', { state: 'attached', timeout: 30000 });
      const startingText = await page!.textContent('#gridpilot-action');
      expect(startingText ?? '').not.toEqual('');

      let reachedStep7OrBeyond = false;

      const deadlineForProgress = Date.now() + 60000;
      while (Date.now() < deadlineForProgress) {
        const updated = await repo.findById(sessionId);
        if (updated && updated.currentStep.value >= 7) {
          reachedStep7OrBeyond = true;
          break;
        }
        await new Promise((resolve) => setTimeout(resolve, 250));
      }

      expect(reachedStep7OrBeyond).toBe(true);

      const overlayStepText = await page!.textContent('#gridpilot-step-text');
      const overlayBody = (overlayStepText ?? '').trim().toLowerCase();
      expect(overlayBody.length).toBeGreaterThan(0);

      const finalSession = await waitForFinalSession(60000);
      expect(finalSession.state.isStoppedAtStep18() || finalSession.state.isCompleted()).toBe(true);
      expect(finalSession.errorMessage).toBeUndefined();

      const progressState = finalSession.state.value;
      expect(['STOPPED_AT_STEP_18', 'COMPLETED']).toContain(progressState);
    },
    180000
  );
});