import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, RequestMethod, ValidationPipe } from '@nestjs/common';
import { IoAdapter } from '@nestjs/platform-socket.io';
import request from 'supertest';
import { MongoMemoryServer } from 'mongodb-memory-server';
import { UserRole } from '../src/common/constants/enums';
import { AppModule } from '../src/app.module';
import { UsersService } from '../src/users/users.service';

describe('TripTrack (e2e)', () => {
  let app: INestApplication;
  let mongo: MongoMemoryServer;

  beforeAll(async () => {
    mongo = await MongoMemoryServer.create();
    process.env.MONGODB_URI = mongo.getUri();
    process.env.REDIS_ENABLED = 'false';
    process.env.JWT_ACCESS_SECRET = 'test-access-secret-min-32-characters';
    process.env.JWT_REFRESH_SECRET = 'test-refresh-secret-min-32-characters';
    process.env.JWT_ACCESS_EXPIRES = '15m';
    process.env.JWT_REFRESH_EXPIRES = '7d';
    process.env.LOG_LEVEL = 'silent';

    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication({ bufferLogs: true });
    app.useWebSocketAdapter(new IoAdapter(app));
    app.useGlobalPipes(
      new ValidationPipe({
        whitelist: true,
        transform: true,
        forbidUnknownValues: false,
      }),
    );
    app.setGlobalPrefix('api', {
      exclude: [{ path: 'health', method: RequestMethod.GET }],
    });
    await app.init();

    const users = app.get(UsersService);
    await users.createUser({
      email: 'admin@test.com',
      password: 'password123',
      fullName: 'Admin',
      employeeCode: 'ADM1',
      role: UserRole.ADMIN,
    });
    await users.createUser({
      email: 'employee@test.com',
      password: 'password123',
      fullName: 'Field Employee',
      employeeCode: 'EMP1',
      role: UserRole.EMPLOYEE,
    });
  });

  afterAll(async () => {
    await app.close();
    await mongo.stop();
  });

  it('/health (GET)', () => {
    return request(app.getHttpServer()).get('/health').expect(200);
  });

  it('login, create trip, departure punch, gps batch', async () => {
    const loginUser = await request(app.getHttpServer())
      .post('/api/auth/login')
      .send({ email: 'employee@test.com', password: 'password123' })
      .expect(201);
    const userToken = loginUser.body.accessToken as string;

    const createTrip = await request(app.getHttpServer())
      .post('/api/trips')
      .set('Authorization', `Bearer ${userToken}`)
      .send({
        city: 'Pune',
        fromLocation: 'Office',
        toLocation: 'Client Site',
        destinationLat: 18.5204,
        destinationLng: 73.8567,
        vehicleType: 'CAR',
        fuelType: 'PETROL',
      })
      .expect(201);
    const tripId = createTrip.body.tripId as string;

    await request(app.getHttpServer())
      .post(`/api/trips/${tripId}/punches/departure`)
      .set('Authorization', `Bearer ${userToken}`)
      .send({
        timestamp: new Date().toISOString(),
        latitude: 18.5,
        longitude: 73.8,
        batteryPercent: 90,
        gpsAccuracy: 5,
        speed: 0,
        isMockLocation: false,
      })
      .expect(201);

    await request(app.getHttpServer())
      .post(`/api/trips/${tripId}/gps/batch`)
      .set('Authorization', `Bearer ${userToken}`)
      .send({
        points: [
          {
            clientPointId: 'p1',
            timestamp: new Date().toISOString(),
            latitude: 18.51,
            longitude: 73.81,
            speed: 40,
            accuracy: 8,
          },
        ],
      })
      .expect(201);

    const loginAdmin = await request(app.getHttpServer())
      .post('/api/auth/login')
      .send({ email: 'admin@test.com', password: 'password123' })
      .expect(201);
    const adminToken = loginAdmin.body.accessToken as string;

    const activeTrips = await request(app.getHttpServer())
      .get('/api/admin/active-trips')
      .set('Authorization', `Bearer ${adminToken}`)
      .expect(200);
    expect(Array.isArray(activeTrips.body)).toBe(true);
  });
});
