/**
 * E2E R1 — invitation & activation : lien 7 jours, usage unique,
 * aucun compte actif avant activation (décision maquettes R1).
 */
process.env.DEMO_MODE = 'true';

import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { PrismaClient } from '@prisma/client';
import request from 'supertest';
import { seed } from '../prisma/seed';
import { AppModule } from '../src/app.module';

describe('Invitation → activation (e2e)', () => {
  let app: INestApplication;
  let admin: string;
  const prisma = new PrismaClient();
  const http = () => request(app.getHttpServer());
  const email = `invite-${Date.now().toString(36)}@spelev.ma`;

  beforeAll(async () => {
    await seed(prisma);
    const moduleRef = await Test.createTestingModule({
      imports: [AppModule.forRoot()],
    }).compile();
    app = moduleRef.createNestApplication();
    await app.init();

    const { body } = await http().get('/auth/demo-accounts');
    const compte = body.accounts.find(
      (a: { roleName: string }) => a.roleName === 'Administrateur',
    );
    admin = (await http().post('/auth/demo-login').send({ userId: compte.id })).body
      .accessToken;
  });

  afterAll(async () => {
    await prisma.user.deleteMany({ where: { email } });
    await app?.close();
    await prisma.$disconnect();
  });

  it('invite, empêche la connexion avant activation, active, connecte', async () => {
    const { body: roles } = await http()
      .get('/roles')
      .set('Authorization', `Bearer ${admin}`)
      .expect(200);
    const technicien = roles.roles.find(
      (r: { name: string }) => r.name === 'Technicien',
    );

    // 1. Invitation → compte « invited », lien émis
    const invitation = await http()
      .post('/users/invitations')
      .set('Authorization', `Bearer ${admin}`)
      .send({ email, displayName: 'Recrue Test', roleId: technicien.id })
      .expect(201);
    expect(invitation.body.activationToken).toBeTruthy();

    const { body: users } = await http()
      .get('/users')
      .set('Authorization', `Bearer ${admin}`);
    const invited = users.users.find((u: { email: string }) => u.email === email);
    expect(invited.status).toBe('invited');

    // 2. Pas de connexion possible avant activation
    await http()
      .post('/auth/login')
      .send({ email, password: 'MotDePasse!123' })
      .expect(401);

    // 3. Renvoi du lien : l'ancien devient invalide (usage unique)
    const renvoi = await http()
      .post(`/users/${invitation.body.userId}/invitation`)
      .set('Authorization', `Bearer ${admin}`)
      .expect(201);
    await http()
      .post('/auth/activate')
      .send({ token: invitation.body.activationToken, password: 'MotDePasse!123' })
      .expect(400);

    // 4. Activation → connecté directement, statut « active »
    const activation = await http()
      .post('/auth/activate')
      .send({ token: renvoi.body.activationToken, password: 'MotDePasse!123' })
      .expect(200);
    expect(activation.body.user.role.name).toBe('Technicien');
    await http()
      .get('/users/me')
      .set('Authorization', `Bearer ${activation.body.accessToken}`)
      .expect(200);

    // 5. Le lien est consommé ; la connexion classique fonctionne désormais
    await http()
      .post('/auth/activate')
      .send({ token: renvoi.body.activationToken, password: 'Autre!12345' })
      .expect(400);
    await http()
      .post('/auth/login')
      .send({ email, password: 'MotDePasse!123' })
      .expect(200);

    // 6. Renvoyer un lien sur un compte activé → refus
    await http()
      .post(`/users/${invitation.body.userId}/invitation`)
      .set('Authorization', `Bearer ${admin}`)
      .expect(409);
  });

  it('refuse un email déjà connu (409) et un lien fantaisiste (400)', async () => {
    const { body: roles } = await http()
      .get('/roles')
      .set('Authorization', `Bearer ${admin}`);
    await http()
      .post('/users/invitations')
      .set('Authorization', `Bearer ${admin}`)
      .send({
        email: 'dispatcher@demo.siop.ma',
        displayName: 'Doublon',
        roleId: roles.roles[0].id,
      })
      .expect(409);
    await http()
      .post('/auth/activate')
      .send({ token: 'jeton-inexistant-123', password: 'MotDePasse!123' })
      .expect(400);
  });
});
