import { CreateInquiryCommand } from '../../application/commands/create-inquiry/create-inquiry.command';
import { MarkInquiryReadCommand } from '../../application/commands/mark-inquiry-read/mark-inquiry-read.command';
import { GetInquiriesByAgentQuery } from '../../application/queries/get-inquiries-by-agent/get-inquiries-by-agent.query';
import { GetInquiriesByListingQuery } from '../../application/queries/get-inquiries-by-listing/get-inquiries-by-listing.query';
import { InquiriesController } from '../controllers/inquiries.controller';

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

  const mockBuyer = { sub: 'buyer-1', phone: '0901234567', role: 'BUYER' };
  const mockAgent = { sub: 'agent-1', phone: '0901234568', role: 'AGENT' };

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

  describe('POST /inquiries — createInquiry', () => {
    it('dispatches CreateInquiryCommand with correct parameters', async () => {
      const dto = { listingId: 'listing-1', message: 'Tôi muốn xem nhà', phone: '0909999999' };
      const expected = { id: 'inq-1', listingId: 'listing-1', createdAt: '2026-01-01T00:00:00.000Z' };
      mockCommandBus.execute.mockResolvedValue(expected);

      const result = await controller.createInquiry(dto as any, mockBuyer as any);

      expect(mockCommandBus.execute).toHaveBeenCalledWith(expect.any(CreateInquiryCommand));
      const cmd = mockCommandBus.execute.mock.calls[0]![0] as CreateInquiryCommand;
      expect(cmd.userId).toBe('buyer-1');
      expect(cmd.listingId).toBe('listing-1');
      expect(cmd.message).toBe('Tôi muốn xem nhà');
      expect(cmd.phone).toBe('0909999999');
      expect(result).toEqual(expected);
    });

    it('passes null phone when not provided', async () => {
      const dto = { listingId: 'listing-1', message: 'Xin chào' };
      mockCommandBus.execute.mockResolvedValue({ id: 'inq-2' });

      await controller.createInquiry(dto as any, mockBuyer as any);

      const cmd = mockCommandBus.execute.mock.calls[0]![0] as CreateInquiryCommand;
      expect(cmd.phone).toBeNull();
    });
  });

  describe('GET /inquiries/listing/:listingId — getByListing', () => {
    it('dispatches GetInquiriesByListingQuery with defaults', async () => {
      const expected = { data: [], total: 0, page: 1, limit: 20, totalPages: 0 };
      mockQueryBus.execute.mockResolvedValue(expected);

      const result = await controller.getByListing('listing-1', {} as any);

      expect(mockQueryBus.execute).toHaveBeenCalledWith(expect.any(GetInquiriesByListingQuery));
      const query = mockQueryBus.execute.mock.calls[0]![0] as GetInquiriesByListingQuery;
      expect(query.listingId).toBe('listing-1');
      expect(query.page).toBe(1);
      expect(query.limit).toBe(20);
      expect(result).toEqual(expected);
    });

    it('passes custom pagination', async () => {
      mockQueryBus.execute.mockResolvedValue({ data: [] });

      await controller.getByListing('listing-1', { page: 3, limit: 10 } as any);

      const query = mockQueryBus.execute.mock.calls[0]![0] as GetInquiriesByListingQuery;
      expect(query.page).toBe(3);
      expect(query.limit).toBe(10);
    });
  });

  describe('GET /inquiries/agent/me — getMyInquiries', () => {
    it('dispatches GetInquiriesByAgentQuery with current user', async () => {
      const expected = { data: [], total: 0, page: 1, limit: 20, totalPages: 0 };
      mockQueryBus.execute.mockResolvedValue(expected);

      const result = await controller.getMyInquiries(mockAgent as any, {} as any);

      expect(mockQueryBus.execute).toHaveBeenCalledWith(expect.any(GetInquiriesByAgentQuery));
      const query = mockQueryBus.execute.mock.calls[0]![0] as GetInquiriesByAgentQuery;
      expect(query.agentUserId).toBe('agent-1');
      expect(query.page).toBe(1);
      expect(query.limit).toBe(20);
      expect(result).toEqual(expected);
    });
  });

  describe('PATCH /inquiries/:id/read — markAsRead', () => {
    it('dispatches MarkInquiryReadCommand and returns success', async () => {
      mockCommandBus.execute.mockResolvedValue(undefined);

      const result = await controller.markAsRead('inq-1', mockAgent as any);

      expect(mockCommandBus.execute).toHaveBeenCalledWith(expect.any(MarkInquiryReadCommand));
      const cmd = mockCommandBus.execute.mock.calls[0]![0] as MarkInquiryReadCommand;
      expect(cmd.inquiryId).toBe('inq-1');
      expect(cmd.agentUserId).toBe('agent-1');
      expect(result).toEqual({ success: true });
    });
  });
});
