import { NotFoundException } from '@nestjs/common';
import { RecalculateQualityScoreCommand } from '../../application/commands/recalculate-quality-score/recalculate-quality-score.command';
import { GetAgentDashboardQuery } from '../../application/queries/get-agent-dashboard/get-agent-dashboard.query';
import { GetAgentPublicProfileQuery } from '../../application/queries/get-agent-public-profile/get-agent-public-profile.query';
import { AgentsController } from '../controllers/agents.controller';

describe('AgentsController', () => {
  let controller: AgentsController;
  let mockCommandBus: { execute: ReturnType<typeof vi.fn> };
  let mockQueryBus: { execute: ReturnType<typeof vi.fn> };

  const mockAgentUser = { sub: 'user-1', phone: '0901234567', role: 'AGENT' };
  const _mockAdminUser = { sub: 'admin-1', phone: '0901234568', role: 'ADMIN' };

  beforeEach(() => {
    mockCommandBus = { execute: vi.fn() };
    mockQueryBus = { execute: vi.fn() };
    controller = new AgentsController(mockCommandBus as any, mockQueryBus as any);
  });

  describe('GET /agents/me/dashboard — getDashboard', () => {
    it('dispatches GetAgentDashboardQuery with current user', async () => {
      const mockDashboard = {
        agentId: 'agent-1',
        qualityScore: 85,
        totalDeals: 12,
        responseTimeAvg: 600,
        isVerified: true,
        totalLeads: 30,
        leadsByStatus: { NEW: 5, CONTACTED: 10 },
        conversionRate: 0.167,
        totalInquiries: 45,
        unreadInquiries: 3,
        totalListings: 15,
        activeListings: 10,
        avgReviewRating: 4.5,
        totalReviews: 20,
      };
      mockQueryBus.execute.mockResolvedValue(mockDashboard);

      const result = await controller.getDashboard(mockAgentUser as any);

      expect(mockQueryBus.execute).toHaveBeenCalledWith(
        expect.any(GetAgentDashboardQuery),
      );
      const query = mockQueryBus.execute.mock.calls[0]![0] as GetAgentDashboardQuery;
      expect(query.userId).toBe('user-1');
      expect(result).toEqual(mockDashboard);
    });
  });

  describe('GET /agents/:agentId/profile — getPublicProfile', () => {
    it('dispatches GetAgentPublicProfileQuery and returns profile', async () => {
      const mockProfile = {
        id: 'agent-1',
        fullName: 'Nguyễn Văn A',
        avatarUrl: null,
        phone: '0901234567',
        email: null,
        agency: null,
        licenseNumber: null,
        bio: null,
        qualityScore: 85,
        totalDeals: 12,
        isVerified: true,
        serviceAreas: ['Quận 7'],
        memberSince: '2024-01-15',
        activeListings: [],
        avgReviewRating: 4.5,
        totalReviews: 20,
      };
      mockQueryBus.execute.mockResolvedValue(mockProfile);

      const result = await controller.getPublicProfile('agent-1');

      expect(mockQueryBus.execute).toHaveBeenCalledWith(
        expect.any(GetAgentPublicProfileQuery),
      );
      const query = mockQueryBus.execute.mock.calls[0]![0] as GetAgentPublicProfileQuery;
      expect(query.agentId).toBe('agent-1');
      expect(result).toEqual(mockProfile);
    });

    it('throws NotFoundException when profile is null', async () => {
      mockQueryBus.execute.mockResolvedValue(null);

      await expect(controller.getPublicProfile('nonexistent')).rejects.toThrow(
        NotFoundException,
      );
      await expect(controller.getPublicProfile('nonexistent')).rejects.toThrow(
        'Không tìm thấy môi giới',
      );
    });
  });

  describe('POST /agents/:agentId/recalculate-score — recalculateScore', () => {
    it('dispatches RecalculateQualityScoreCommand and returns success message', async () => {
      mockCommandBus.execute.mockResolvedValue(undefined);

      const result = await controller.recalculateScore('agent-1');

      expect(mockCommandBus.execute).toHaveBeenCalledWith(
        expect.any(RecalculateQualityScoreCommand),
      );
      const cmd = mockCommandBus.execute.mock.calls[0]![0] as RecalculateQualityScoreCommand;
      expect(cmd.agentId).toBe('agent-1');
      expect(result).toEqual({ message: 'Quality score recalculated' });
    });
  });
});
