/* eslint-disable import-x/order */
import { describe, expect, it, vi, beforeEach } from 'vitest';
import type { ListingDetail } from '@/lib/listings-api';

// Mock the server-side listing fetch
vi.mock('@/lib/listings-server', () => ({
  fetchListingById: vi.fn(),
}));

// Avoid pulling in the heavy client component during unit tests
vi.mock('@/components/listings/listing-detail-client', () => ({
  ListingDetailClient: () => null,
}));

vi.mock('@/components/seo/json-ld', () => ({
  JsonLd: () => null,
  generateBreadcrumbJsonLd: () => ({}),
  generateListingJsonLd: () => ({}),
}));

import { fetchListingById } from '@/lib/listings-server';
import { generateMetadata } from '../page';

const mockedFetch = vi.mocked(fetchListingById);

function buildListing(overrides: Partial<ListingDetail> = {}): ListingDetail {
  return {
    id: 'listing-1',
    status: 'ACTIVE',
    transactionType: 'SALE',
    priceVND: '3500000000',
    pricePerM2: null,
    rentPriceMonthly: null,
    commissionPct: null,
    viewCount: 0,
    saveCount: 0,
    inquiryCount: 0,
    publishedAt: null,
    createdAt: '2026-01-01T00:00:00.000Z',
    valuationEstimate: null,
    agentQualityScore: null,
    similarCount: 0,
    property: {
      id: 'prop-1',
      propertyType: 'APARTMENT',
      title: 'Căn hộ cao cấp Quận 1',
      description: 'Đẹp, thoáng',
      address: '123 Lê Lợi',
      ward: 'Bến Nghé',
      district: 'Quận 1',
      city: 'Hồ Chí Minh',
      areaM2: 75,
      usableAreaM2: null,
      bedrooms: 2,
      bathrooms: 2,
      floors: 1,
      floor: null,
      totalFloors: null,
      direction: null,
      yearBuilt: null,
      legalStatus: null,
      amenities: null,
      nearbyPOIs: null,
      metroDistanceM: null,
      projectName: null,
      latitude: null,
      longitude: null,
      furnishing: null,
      propertyCondition: null,
      balconyDirection: null,
      maintenanceFeeVND: null,
      parkingSlots: null,
      viewType: [],
      petFriendly: null,
      suitableFor: [],
      whyThisLocation: null,
      media: [
        {
          id: 'img-1',
          url: 'https://cdn.example.com/img1.jpg',
          type: 'image',
          order: 0,
          caption: null,
        },
      ],
    },
    seller: { id: 'u-1', fullName: 'Nguyen Van A', phone: '0900000000' },
    agent: null,
    ...overrides,
  };
}

describe('listing page generateMetadata', () => {
  beforeEach(() => {
    mockedFetch.mockReset();
  });

  it('returns a not-found title when the listing is missing', async () => {
    mockedFetch.mockResolvedValueOnce(null);
    const meta = await generateMetadata({
      params: Promise.resolve({ locale: 'vi', id: 'missing' }),
    });
    expect(meta.title).toMatch(/Không tìm thấy/);
  });

  it('builds OG + Twitter tags with image, canonical and alternates', async () => {
    mockedFetch.mockResolvedValueOnce(buildListing());
    const meta = await generateMetadata({
      params: Promise.resolve({ locale: 'vi', id: 'listing-1' }),
    });

    expect(meta.title).toContain('Căn hộ cao cấp Quận 1');
    expect(String(meta.description)).toContain('75 m');
    expect(String(meta.description)).toContain('2 PN');
    expect(String(meta.description)).toContain('Quận 1');

    expect(meta.alternates?.canonical).toMatch(/\/vi\/listings\/listing-1$/);
    expect(meta.alternates?.languages?.vi).toMatch(/\/vi\/listings\/listing-1$/);
    expect(meta.alternates?.languages?.en).toMatch(/\/en\/listings\/listing-1$/);

    const og = meta.openGraph as Record<string, unknown>;
    expect(og['type']).toBe('article');
    expect(og['locale']).toBe('vi_VN');
    expect(og['siteName']).toBe('GoodGo');
    const ogImages = og['images'] as Array<{ url: string; width: number; height: number }>;
    expect(ogImages[0]?.url).toBe('https://cdn.example.com/img1.jpg');
    expect(ogImages[0]?.width).toBe(1200);
    expect(ogImages[0]?.height).toBe(630);

    const twitter = meta.twitter as Record<string, unknown>;
    expect(twitter['card']).toBe('summary_large_image');
    expect((twitter['images'] as string[])[0]).toBe('https://cdn.example.com/img1.jpg');

    expect(meta.other?.['og:price:currency']).toBe('VND');
    expect(meta.other?.['og:price:amount']).toBe('3500000000');
  });

  it('falls back to default OG image when no media is present', async () => {
    mockedFetch.mockResolvedValueOnce(
      buildListing({
        property: { ...buildListing().property, media: [] },
      }),
    );
    const meta = await generateMetadata({
      params: Promise.resolve({ locale: 'en', id: 'listing-1' }),
    });

    const og = meta.openGraph as Record<string, unknown>;
    expect(og['locale']).toBe('en_US');
    const ogImages = og['images'] as Array<{ url: string }>;
    expect(ogImages[0]?.url).toBe('/og-image.png');
  });
});
