import { Test } from '@nestjs/testing';
import { INestApplication, ValidationPipe } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt';
import request from 'supertest';
import { AppModule } from '../src/app.module';
import { PrismaService } from '@chatapp/database';
import { RedisService } from '@chatapp/redis';

describe('AppController (e2e)', () => {
  let app: INestApplication;

  beforeAll(async () => {
    // Set required env vars for JWT
    process.env.JWT_SECRET = process.env.JWT_SECRET || 'test-jwt-secret-e2e';
    process.env.JWT_ACCESS_EXPIRES = process.env.JWT_ACCESS_EXPIRES || '15m';
    process.env.JWT_REFRESH_EXPIRES = process.env.JWT_REFRESH_EXPIRES || '30d';

    const moduleRef = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({ isGlobal: true }),
        AppModule,
      ],
    })
      .overrideProvider(PrismaService)
      .useValue({
        // Minimal mock so the app can bootstrap without a DB
        user: {
          findUnique: jest.fn().mockResolvedValue(null),
          create: jest.fn().mockResolvedValue({
            id: 'user-1',
            email: 'test@test.com',
            displayName: 'Test User',
            avatarUrl: null,
            isDeleted: false,
          }),
        },
        workspace: {
          create: jest.fn().mockResolvedValue({
            id: 'ws-1',
            name: 'Test',
            domain: 'test',
          }),
        },
        workspaceMember: {
          findMany: jest.fn().mockResolvedValue([]),
        },
        channel: {
          create: jest.fn().mockResolvedValue({ id: 'ch-1' }),
        },
        channelMember: {
          create: jest.fn().mockResolvedValue({}),
          findMany: jest.fn().mockResolvedValue([]),
        },
        session: {
          create: jest.fn().mockResolvedValue({}),
          findFirst: jest.fn().mockResolvedValue(null),
          update: jest.fn().mockResolvedValue({}),
          updateMany: jest.fn().mockResolvedValue({}),
        },
        message: {
          create: jest.fn(),
          findUnique: jest.fn(),
          findMany: jest.fn(),
          update: jest.fn(),
        },
        messageReaction: {
          create: jest.fn(),
          deleteMany: jest.fn(),
        },
        savedMessage: {
          create: jest.fn(),
          deleteMany: jest.fn(),
        },
        channel_update: jest.fn(),
        $connect: jest.fn(),
        $disconnect: jest.fn(),
      })
      .overrideProvider(RedisService)
      .useValue({
        client: {
          incr: jest.fn().mockResolvedValue(1),
          expire: jest.fn().mockResolvedValue(1),
        },
      })
      .compile();

    app = moduleRef.createNestApplication();

    // Global validation pipe (same as main.ts)
    app.useGlobalPipes(
      new ValidationPipe({
        whitelist: true,
        forbidNonWhitelisted: true,
        transform: true,
        transformOptions: { enableImplicitConversion: true },
      }),
    );

    app.setGlobalPrefix('api/v1');

    await app.init();
  });

  afterAll(async () => {
    if (app) await app.close();
  });

  it('GET /api/v1 sin auth devuelve 401', () => {
    return request(app.getHttpServer())
      .get('/api/v1/channels')
      .expect(401);
  });

  it('POST /api/v1/auth/register crea usuario y devuelve token', () => {
    // Override the PrismaService mock for this specific test
    const prisma = app.get(PrismaService) as any;
    prisma.user.findUnique.mockResolvedValue(null);
    prisma.user.create.mockResolvedValue({
      id: 'user-1',
      email: 'newuser@test.com',
      displayName: 'New User',
      avatarUrl: null,
    });

    return request(app.getHttpServer())
      .post('/api/v1/auth/register')
      .send({
        email: 'newuser@test.com',
        password: 'Password123!!!',
        display_name: 'New User',
      })
      .expect(201)
      .then((res: any) => {
        expect(res.body).toHaveProperty('access_token');
        expect(res.body).toHaveProperty('refresh_token');
        expect(res.body.user.email).toBe('newuser@test.com');
      });
  });
});