import { HttpException, HttpStatus } from '@nestjs/common';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { LocalAuthGuard } from '../guards/local-auth.guard';

vi.mock('@nestjs/common', async (importOriginal) => {
  const actual = (await importOriginal()) as any;
  return {
    ...actual,
    Logger: class MockLogger {
      error = vi.fn();
      warn = vi.fn();
      log = vi.fn();
    },
  };
});

vi.mock('@modules/shared', async () => {
  const { HttpException: HE, HttpStatus: HS } = await import('@nestjs/common');
  class UnauthorizedException extends HE {
    constructor(message: string) {
      super(message, HS.UNAUTHORIZED);
      this.name = 'UnauthorizedException';
    }
  }
  return { UnauthorizedException };
});

describe('LocalAuthGuard', () => {
  let guard: LocalAuthGuard;

  beforeEach(() => {
    guard = new LocalAuthGuard();
  });

  it('returns user when user is provided', () => {
    const user = { id: 'user-1', phone: '+84912345678', role: 'BUYER' };
    const result = guard.handleRequest(null, user, undefined, {} as any);
    expect(result).toEqual(user);
  });

  it('re-throws HttpException errors directly', () => {
    const httpError = new HttpException('Bad Request', HttpStatus.BAD_REQUEST);
    expect(() => guard.handleRequest(httpError, null, undefined, {} as any)).toThrow(HttpException);
    expect(() => guard.handleRequest(httpError, null, undefined, {} as any)).toThrow('Bad Request');
  });

  it('wraps non-HttpException errors as UnauthorizedException', () => {
    const dbError = new Error('DB connection refused');
    expect(() => guard.handleRequest(dbError, null, undefined, {} as any)).toThrow(
      'Số điện thoại hoặc mật khẩu không đúng',
    );
  });

  it('wraps TypeError (e.g. from null/undefined) as UnauthorizedException', () => {
    const typeError = new TypeError("Cannot read properties of undefined (reading 'replace')");
    expect(() => guard.handleRequest(typeError, null, undefined, {} as any)).toThrow(
      'Số điện thoại hoặc mật khẩu không đúng',
    );
  });

  it('throws UnauthorizedException when no user and no error', () => {
    expect(() => guard.handleRequest(null, null as any, undefined, {} as any)).toThrow(
      'Số điện thoại hoặc mật khẩu không đúng',
    );
  });
});
