/**
 * Snapshot tests for GET /listings/:id enriched response.
 *
 * Three roles are tested:
 *  - public   (no caller) → inquiryCount must be null
 *  - owner    (seller-1)  → inquiryCount visible
 *  - admin    (ADMIN)     → inquiryCount visible
 */
import { GetListingHandler } from '../queries/get-listing/get-listing.handler';
import { GetListingQuery } from '../queries/get-listing/get-listing.query';

const FROZEN_DATE = '2026-04-21T00:00:00.000Z';

const BASE_LISTING = {
  id: 'listing-snap-1',
  status: 'ACTIVE',
  transactionType: 'SALE',
  priceVND: '7500000000',
  pricePerM2: 93750000,
  rentPriceMonthly: null,
  commissionPct: 2.5,
  viewCount: 42,
  saveCount: 7,
  inquiryCount: 12,
  isFeatured: true,
  featuredUntil: '2026-06-01T00:00:00.000Z',
  publishedAt: '2026-04-01T00:00:00.000Z',
  createdAt: '2026-03-20T00:00:00.000Z',
  valuationEstimate: null,
  agentQualityScore: { score: 90, tier: 'PLATINUM' },
  similarCount: 8,
  property: {
    id: 'prop-snap-1',
    propertyType: 'APARTMENT',
    title: 'Căn hộ view sông Q4',
    description: 'Căn hộ cao cấp',
    address: '1 Nguyễn Văn Linh',
    ward: 'Tân Phong',
    district: 'Quận 7',
    city: 'Hồ Chí Minh',
    latitude: 10.725,
    longitude: 106.7,
    areaM2: 80,
    usableAreaM2: 75,
    bedrooms: 2,
    bathrooms: 2,
    floors: null,
    floor: 15,
    totalFloors: 30,
    direction: 'SOUTH',
    yearBuilt: 2022,
    legalStatus: 'Sổ hồng',
    amenities: null,
    nearbyPOIs: null,
    metroDistanceM: 500,
    projectName: 'The River',
    furnishing: 'FULL',
    propertyCondition: 'NEW',
    balconyDirection: 'EAST',
    maintenanceFeeVND: '3000000',
    parkingSlots: 1,
    viewType: ['RIVER'],
    petFriendly: true,
    suitableFor: ['FAMILY'],
    whyThisLocation: 'Vị trí đắc địa',
    media: [{ id: 'm-1', url: 'https://cdn.example.com/1.jpg', type: 'image', order: 0, caption: null }],
  },
  seller: { id: 'seller-snap-1', fullName: 'Trần Thị B', phone: '0911234567' },
  agent: { id: 'agent-snap-1', userId: 'user-agent', agency: 'Đất Xanh Group' },
};

const AVM_RESULT = {
  estimatedPrice: '7800000000',
  confidence: 0.91,
  modelVersion: 'v2.1',
  comparables: [],
};

function makeHandler(): GetListingHandler {
  const mockRepo = { findByIdWithProperty: vi.fn().mockResolvedValue(BASE_LISTING) };
  const mockAvm = { estimateValue: vi.fn().mockResolvedValue(AVM_RESULT) };
  const mockCache = {
    getOrSet: vi.fn().mockImplementation(async (_k: string, fn: () => Promise<unknown>) => fn()),
  };
  const mockLogger = { log: vi.fn(), error: vi.fn(), warn: vi.fn(), debug: vi.fn() };

  return new GetListingHandler(mockRepo as any, mockAvm as any, mockCache as any, mockLogger as any);
}

describe('GET /listings/:id — enriched response snapshot', () => {
  beforeEach(() => {
    vi.useFakeTimers();
    vi.setSystemTime(new Date(FROZEN_DATE));
  });

  afterEach(() => {
    vi.useRealTimers();
  });

  it('public caller: inquiryCount is null, all other enrichment fields present', async () => {
    const handler = makeHandler();
    const result = await handler.execute(new GetListingQuery('listing-snap-1'));

    expect(result).toMatchSnapshot();
    expect(result!.inquiryCount).toBeNull();
    expect(result!.valuationEstimate).toEqual({
      value: '7800000000',
      confidence: 0.91,
      modelVersion: 'v2.1',
      estimatedAt: FROZEN_DATE,
    });
    expect(result!.agentQualityScore).toEqual({ score: 90, tier: 'PLATINUM' });
    expect(result!.similarCount).toBe(8);
  });

  it('owner caller: inquiryCount is visible', async () => {
    const handler = makeHandler();
    const result = await handler.execute(
      new GetListingQuery('listing-snap-1', { userId: 'seller-snap-1', role: 'USER' }),
    );

    expect(result).toMatchSnapshot();
    expect(result!.inquiryCount).toBe(12);
  });

  it('admin caller: inquiryCount is visible', async () => {
    const handler = makeHandler();
    const result = await handler.execute(
      new GetListingQuery('listing-snap-1', { userId: 'admin-x', role: 'ADMIN' }),
    );

    expect(result).toMatchSnapshot();
    expect(result!.inquiryCount).toBe(12);
  });
});
