import { Test, TestingModule } from '@nestjs/testing';
import { AuthController } from './auth.controller';
import { AuthenticatedUser } from './interfaces/jwt-payload.interface';
import { DevOnlyGuard } from '../common/guards/dev-only/dev-only.guard';

describe('AuthController', () => {
  let controller: AuthController;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [AuthController],
    })
      // DevOnlyGuard depends on ConfigService; these tests call controller
      // methods directly, so stub it out to keep the test module self-contained.
      .overrideGuard(DevOnlyGuard)
      .useValue({ canActivate: () => true })
      .compile();

    controller = module.get<AuthController>(AuthController);
  });

  it('should be defined', () => {
    expect(controller).toBeDefined();
  });

  describe('getHealth', () => {
    it('should return health status', () => {
      const result = controller.getHealth();

      expect(result).toHaveProperty('status', 'OK');
      expect(result).toHaveProperty('timestamp');
      expect(result).toHaveProperty('message', 'BFF PlanFi está funcionando!');
      expect(result.timestamp).toMatch(
        /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/,
      );
    });
  });

  describe('getProfile', () => {
    it('should return user profile', () => {
      const user: AuthenticatedUser = {
        id: 'user_123',
        type: 'user',
        payload: {
          sub: 'user_123',
          iss: 'test-issuer',
          prv: 'users',
          iat: 1640995200,
          exp: 1672531200,
          nbf: 1640995200,
          jti: 'jwt-id-123',
        },
        tokenData: { userId: 'user_123' },
        expiresAt: new Date('2024-12-31'),
        issuedAt: new Date('2024-01-01'),
        rawToken: null,
      };

      const result = controller.getProfile(user);

      expect(result).toHaveProperty('message', 'Perfil acessado com sucesso');
      expect(result).toHaveProperty('user');
      expect(result.user).toHaveProperty('id', 'user_123');
      expect(result.user).toHaveProperty('type', 'user');
      expect(result.user).toHaveProperty('expiresAt', user.expiresAt);
      expect(result.user).toHaveProperty('issuedAt', user.issuedAt);
    });
  });

  describe('getUserDashboard', () => {
    it('should return user dashboard', () => {
      const user: AuthenticatedUser = {
        id: 'user_123',
        type: 'user',
        payload: {
          sub: 'user_123',
          iss: 'test-issuer',
          prv: 'users',
          iat: 1640995200,
          exp: 1672531200,
          nbf: 1640995200,
          jti: 'jwt-id-456',
        },
        tokenData: { userId: 'user_123' },
        expiresAt: new Date('2024-12-31'),
        issuedAt: new Date('2024-01-01'),
        rawToken: null,
      };

      const result = controller.getUserDashboard(user);

      expect(result).toHaveProperty('message', 'Dashboard do usuário');
      expect(result).toHaveProperty('userId', 'user_123');
      expect(result).toHaveProperty('userType', 'user');
      expect(result).toHaveProperty('payload', user.payload);
    });
  });

  describe('getClientDashboard', () => {
    it('should return client dashboard', () => {
      const user: AuthenticatedUser = {
        id: 'client_123',
        type: 'client',
        payload: {
          sub: 'client_123',
          iss: 'test-issuer',
          prv: 'hash123',
          iat: 1640995200,
          exp: 1672531200,
          nbf: 1640995200,
          jti: 'jwt-id-789',
        },
        tokenData: { clientId: 'client_123' },
        expiresAt: new Date('2024-12-31'),
        issuedAt: new Date('2024-01-01'),
        rawToken: null,
      };

      const result = controller.getClientDashboard(user);

      expect(result).toHaveProperty('message', 'Dashboard do client');
      expect(result).toHaveProperty('clientId', 'client_123');
      expect(result).toHaveProperty('userType', 'client');
      expect(result).toHaveProperty('payload', user.payload);
    });
  });

  describe('validateToken', () => {
    it('should return error when no token provided', () => {
      const result = controller.validateToken({ token: '' });

      expect(result).toHaveProperty('valid', false);
      expect(result).toHaveProperty('error', 'Token não fornecido');
    });

    it('should return error when token is null', () => {
      const result = controller.validateToken({ token: null as any });

      expect(result).toHaveProperty('valid', false);
      expect(result).toHaveProperty('error', 'Token não fornecido');
    });

    it('should return error when token is undefined', () => {
      const result = controller.validateToken({ token: undefined as any });

      expect(result).toHaveProperty('valid', false);
      expect(result).toHaveProperty('error', 'Token não fornecido');
    });

    it('should return instructions when token is provided', () => {
      const result = controller.validateToken({ token: 'valid-token' });

      expect(result).toHaveProperty('message');
      expect(result).toHaveProperty('example');
      expect(result.message).toContain('Use o header Authorization: Bearer');
      expect(result.example).toContain('Authorization: Bearer');
    });
  });

  describe('getMe', () => {
    it('should return user information', () => {
      const user: AuthenticatedUser = {
        id: 'user_123',
        type: 'user',
        payload: {
          sub: 'user_123',
          iss: 'test-issuer',
          prv: 'users',
          iat: 1640995200,
          exp: 1672531200,
          nbf: 1640995200,
          jti: 'jwt-id-101',
        },
        tokenData: { userId: 'user_123' },
        expiresAt: new Date('2024-12-31'),
        issuedAt: new Date('2024-01-01'),
        rawToken: null,
      };

      const result = controller.getMe(user);

      expect(result).toHaveProperty('id', 'user_123');
      expect(result).toHaveProperty('type', 'user');
      expect(result).toHaveProperty('expiresAt', user.expiresAt);
      expect(result).toHaveProperty('issuedAt', user.issuedAt);
      expect(result).toHaveProperty('payload', user.payload);
    });
  });

  describe('getClientTest', () => {
    it('should return OK', () => {
      const result = controller.getClientTest();

      expect(result).toBe('OK');
    });
  });

  describe('getTokenDebug', () => {
    it('should return complete token debug information', () => {
      const user: AuthenticatedUser = {
        id: 'user_123',
        type: 'user',
        payload: {
          sub: 'user_123',
          iss: 'test-issuer',
          prv: 'users',
          iat: 1640995200,
          exp: 1672531200,
          nbf: 1640995200,
          jti: 'jwt-id-102',
        },
        tokenData: { userId: 'user_123' },
        expiresAt: new Date('2024-12-31'),
        issuedAt: new Date('2024-01-01'),
        rawToken: 'test-token',
      };

      const token = 'test-token';
      const tokenData = { userId: 'user_123', email: 'test@example.com' };
      const jwtPayload = user.payload;
      const uuid = 'uuid-123';
      const email = 'test@example.com';
      const name = 'Test User';

      const result = controller.getTokenDebug(
        user,
        token,
        tokenData,
        jwtPayload,
        uuid,
        email,
        name,
      );

      expect(result).toHaveProperty('message', 'Debug completo do token JWT');
      expect(result).toHaveProperty('authentication');
      expect(result.authentication).toHaveProperty('id', 'user_123');
      expect(result.authentication).toHaveProperty('type', 'user');
      expect(result).toHaveProperty('rawToken');
      expect(result.rawToken).toHaveProperty('value', 'test-token');
      expect(result.rawToken).toHaveProperty('length', 10);
      expect(result.rawToken).toHaveProperty('parts', 1);
      expect(result).toHaveProperty('tokenData', tokenData);
      expect(result).toHaveProperty('jwtPayload', jwtPayload);
      expect(result).toHaveProperty('extractedFields');
      expect(result.extractedFields).toHaveProperty('uuid', 'uuid-123');
      expect(result.extractedFields).toHaveProperty(
        'email',
        'test@example.com',
      );
      expect(result.extractedFields).toHaveProperty('name', 'Test User');
      expect(result).toHaveProperty('laravelCompatible', true);
      expect(result).toHaveProperty('instructions');
      expect(result.instructions.message).toContain(
        'Este token pode ser usado diretamente com a API Laravel',
      );
      expect(result.instructions.example).toContain(
        'curl -H "Authorization: Bearer test-token"',
      );
    });
  });

  describe('getLaravelCompatibility', () => {
    it('should return Laravel compatibility information', () => {
      const user: AuthenticatedUser = {
        id: 'user_123',
        type: 'user',
        payload: {
          sub: 'user_123',
          iss: 'test-issuer',
          prv: 'users',
          iat: 1640995200,
          exp: 1672531200,
          nbf: 1640995200,
          jti: 'jwt-id-103',
        },
        tokenData: { userId: 'user_123' },
        expiresAt: new Date('2024-12-31'),
        issuedAt: new Date('2024-01-01'),
        rawToken: null,
      };

      const provider = 'users';
      const issuer = 'test-issuer';
      const jwtId = 'jwt-id-103';

      const result = controller.getLaravelCompatibility(
        user,
        provider,
        issuer,
        jwtId,
      );

      expect(result).toHaveProperty(
        'message',
        'Dados de compatibilidade com Laravel',
      );
      expect(result).toHaveProperty('bffData');
      expect(result.bffData).toHaveProperty('userId', 'user_123');
      expect(result.bffData).toHaveProperty('userType', 'user');
      expect(result.bffData).toHaveProperty('provider', 'users');
      expect(result.bffData).toHaveProperty('issuer', 'test-issuer');
      expect(result.bffData).toHaveProperty('jwtId', 'jwt-id-103');
      expect(result).toHaveProperty('laravelFields');
      expect(result.laravelFields).toHaveProperty('sub', 'user_123');
      expect(result.laravelFields).toHaveProperty('iss', 'test-issuer');
      expect(result.laravelFields).toHaveProperty('jti', 'jwt-id-103');
      expect(result.laravelFields).toHaveProperty('prv', 'users');
      expect(result).toHaveProperty('compatibility');
      expect(result.compatibility).toHaveProperty('sameSecret');
      expect(result.compatibility).toHaveProperty('sameAlgorithm');
      expect(result.compatibility).toHaveProperty('tokenValidity');
    });
  });
});
