import { UnauthorizedException } from '@nestjs/common';
import { GoogleStrategy } from './google.strategy';
import { JwtRefreshStrategy } from './jwt-refresh.strategy';
import { JwtStrategy } from './jwt.strategy';
import { SuperAdminJwtStrategy } from './super-admin-jwt.strategy';

const config = (values: Record<string, string> = {}) => ({
  get: jest.fn((key: string) => values[key] ?? 'test-secret'),
});

describe('authentication strategies', () => {
  describe('JwtStrategy', () => {
    it('accepts access tokens only for active users', async () => {
      const repository = { findById: jest.fn().mockResolvedValue({ isDisabled: false }) };
      const strategy = new JwtStrategy(
        config({ 'jwt.accessSecret': 'access-secret' }) as any,
        repository as any,
      );
      const payload = { sub: 'user-1', tokenType: 'access' } as any;

      await expect(strategy.validate(payload)).resolves.toBe(payload);
      expect(repository.findById).toHaveBeenCalledWith('user-1');
    });

    it('rejects wrong token purpose before database access', async () => {
      const repository = { findById: jest.fn() };
      const strategy = new JwtStrategy(config() as any, repository as any);

      await expect(
        strategy.validate({ sub: 'user-1', tokenType: 'refresh' } as any),
      ).rejects.toBeInstanceOf(UnauthorizedException);
      expect(repository.findById).not.toHaveBeenCalled();
    });

    it.each([null, { isDisabled: true }])('rejects unavailable account %#', async (user) => {
      const strategy = new JwtStrategy(
        config() as any,
        { findById: jest.fn().mockResolvedValue(user) } as any,
      );

      await expect(
        strategy.validate({ sub: 'user-1', tokenType: 'access' } as any),
      ).rejects.toBeInstanceOf(UnauthorizedException);
    });
  });

  describe('purpose-bound stateless strategies', () => {
    it('accepts only user refresh tokens in JwtRefreshStrategy', () => {
      const strategy = new JwtRefreshStrategy(config() as any);
      const payload = { sub: 'user-1', tokenType: 'refresh' } as any;

      expect(strategy.validate(payload)).toBe(payload);
      expect(() => strategy.validate({ tokenType: 'access' } as any)).toThrow(
        UnauthorizedException,
      );
    });

    it('accepts only superadmin access tokens', () => {
      const strategy = new SuperAdminJwtStrategy(config() as any);
      const payload = { sub: 'superadmin', tokenType: 'superadmin_access' } as any;

      expect(strategy.validate(payload)).toBe(payload);
      expect(() => strategy.validate({ tokenType: 'access' } as any)).toThrow(
        UnauthorizedException,
      );
    });
  });

  describe('GoogleStrategy', () => {
    it('normalizes profile data before authentication', () => {
      const strategy = new GoogleStrategy(config() as any);
      const done = jest.fn();

      strategy.validate(
        'access',
        'refresh',
        {
          id: 'google-1',
          displayName: 'Google Artist',
          emails: [{ value: 'ARTIST@EXAMPLE.COM', verified: true }],
          photos: [{ value: 'https://example.com/avatar.jpg' }],
        } as any,
        done,
      );

      expect(done).toHaveBeenCalledWith(null, {
        googleId: 'google-1',
        email: 'artist@example.com',
        name: 'Google Artist',
        avatar: 'https://example.com/avatar.jpg',
      });
    });

    it('rejects profiles without an email', () => {
      const strategy = new GoogleStrategy(config() as any);
      const done = jest.fn();

      strategy.validate('access', 'refresh', { id: 'google-1' } as any, done);

      expect(done).toHaveBeenCalledWith(expect.any(UnauthorizedException));
    });

    it('provides a safe fallback display name', () => {
      const strategy = new GoogleStrategy(config() as any);
      const done = jest.fn();

      strategy.validate(
        'access',
        'refresh',
        { id: 'google-1', emails: [{ value: 'artist@example.com' }] } as any,
        done,
      );

      expect(done).toHaveBeenCalledWith(
        null,
        expect.objectContaining({ name: 'Google User', avatar: undefined }),
      );
    });
  });
});
