import { INestApplication } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { io, Socket } from 'socket.io-client';
import request from 'supertest';
import { App } from 'supertest/types';
import { AppModule } from './../src/app.module';

// Mock chokidar to avoid ES module issues
jest.mock('chokidar', () => ({
  watch: jest.fn(),
}));

describe('AppController (e2e)', () => {
  let app: INestApplication<App>;
  let clientSocket: Socket;

  beforeEach(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.listen(3001);
  });

  afterEach(async () => {
    if (clientSocket) {
      clientSocket.disconnect();
    }
    await app.close();
  });

  it('/ (GET)', () => {
    return request(app.getHttpServer())
      .get('/')
      .expect(200)
      .expect((res) => {
        expect(res.body).toHaveProperty('status', 'ok');
      });
  });

  describe('WebSocket Integration', () => {
    beforeEach((done) => {
      clientSocket = io('http://localhost:3001');
      clientSocket.on('connect', () => {
        done();
      });
    });

    it('should connect to WebSocket', () => {
      expect(clientSocket.connected).toBe(true);
    });

    it('should handle join message', (done) => {
      const room = 'testRoom';
      clientSocket.emit('join', { room });

      clientSocket.on('joined', (data) => {
        expect(data).toEqual({ room });
        done();
      });
    });

    it('should handle leave message', (done) => {
      const room = 'testRoom';
      clientSocket.emit('join', { room });

      clientSocket.on('joined', () => {
        clientSocket.emit('leave', { room });

        clientSocket.on('left', (data) => {
          expect(data).toEqual({ room });
          done();
        });
      });
    });

    it('should emit taskUpdate on settings change', (done) => {
      const settings = { testKey: 'testValue' };

      clientSocket.on('taskUpdate', (data) => {
        expect(data).toEqual({
          type: 'settings',
          task: 'update',
          settings,
        });
        done();
      });

      // Trigger settings update via HTTP
      request(app.getHttpServer())
        .post('/config/settings')
        .send(settings)
        .expect(201)
        .end((err) => {
          if (err) {
            done(err);
          }
          // The WebSocket event should have been emitted by now
        });
    });
  });
});
