import { UserEntity } from '@modules/auth/domain/entities/user.entity';
import { type IUserRepository } from '@modules/auth/domain/repositories/user.repository';
import { HashedPassword } from '@modules/auth/domain/value-objects/hashed-password.vo';
import { Phone } from '@modules/auth/domain/value-objects/phone.vo';
import { UpdateUserStatusCommand } from '../commands/update-user-status/update-user-status.command';
import { UpdateUserStatusHandler } from '../commands/update-user-status/update-user-status.handler';

async function createUser(role = 'BUYER' as any, isActive = true): Promise<UserEntity> {
  const phone = Phone.create('0901234567').unwrap();
  const hash = await HashedPassword.fromPlain('Password123');
  const passwordHash = hash.isOk ? hash.unwrap() : null;
  return new UserEntity('user-1', {
    email: null,
    phone,
    passwordHash,
    fullName: 'Test User',
    avatarUrl: null,
    role,
    kycStatus: 'NONE',
    kycData: null,
    isActive,
  });
}

describe('UpdateUserStatusHandler', () => {
  let handler: UpdateUserStatusHandler;
  let mockUserRepo: { [K in keyof IUserRepository]: ReturnType<typeof vi.fn> };
  let mockEventBus: { publish: ReturnType<typeof vi.fn> };

  beforeEach(() => {
    mockUserRepo = {
      findById: vi.fn(),
      findByPhone: vi.fn(),
      findByEmail: vi.fn(),
      save: vi.fn(),
      update: vi.fn(),
    };
    mockEventBus = { publish: vi.fn() };
    handler = new UpdateUserStatusHandler(mockUserRepo as any, mockEventBus as any);
  });

  it('deactivates an active user', async () => {
    const user = await createUser('BUYER', true);
    mockUserRepo.findById.mockResolvedValue(user);
    mockUserRepo.update.mockResolvedValue(undefined);

    const command = new UpdateUserStatusCommand('user-1', 'admin-1', false, 'Vi phạm chính sách');
    const result = await handler.execute(command);

    expect(result.isActive).toBe(false);
    expect(result.message).toContain('vô hiệu hóa');
    expect(mockUserRepo.update).toHaveBeenCalledTimes(1);
    expect(mockEventBus.publish).toHaveBeenCalled();
  });

  it('activates an inactive user', async () => {
    const user = await createUser('BUYER', false);
    mockUserRepo.findById.mockResolvedValue(user);
    mockUserRepo.update.mockResolvedValue(undefined);

    const command = new UpdateUserStatusCommand('user-1', 'admin-1', true, 'Resolved');
    const result = await handler.execute(command);

    expect(result.isActive).toBe(true);
    expect(result.message).toContain('kích hoạt');
  });

  it('throws NotFoundException when user does not exist', async () => {
    mockUserRepo.findById.mockResolvedValue(null);

    const command = new UpdateUserStatusCommand('nonexistent', 'admin-1', false, 'test reason');
    await expect(handler.execute(command)).rejects.toThrow('Người dùng không tồn tại');
  });

  it('prevents changing admin status', async () => {
    const admin = await createUser('ADMIN', true);
    mockUserRepo.findById.mockResolvedValue(admin);

    const command = new UpdateUserStatusCommand('user-1', 'admin-1', false, 'test reason');
    await expect(handler.execute(command)).rejects.toThrow(/admin/i);
  });

  it('throws when status already matches', async () => {
    const user = await createUser('BUYER', true);
    mockUserRepo.findById.mockResolvedValue(user);

    const command = new UpdateUserStatusCommand('user-1', 'admin-1', true, 'test reason');
    await expect(handler.execute(command)).rejects.toThrow('đang hoạt động');
  });
});
