import { render } from '@testing-library/react';
import { describe, expect, it } from 'vitest';
import type { AgentPublicProfile } from '@/lib/agents-api';
import type { ListingDetail } from '@/lib/listings-api';
import { JsonLd, generateListingJsonLd, generateBreadcrumbJsonLd, generateWebsiteJsonLd, generateAgentJsonLd } from '../json-ld';

// ─── JsonLd component ────────────────────────────────────────

describe('JsonLd', () => {
  it('renders a script tag with type application/ld+json', () => {
    const data = { '@context': 'https://schema.org', '@type': 'WebSite' };
    const { container } = render(<JsonLd data={data} />);
    const script = container.querySelector('script[type="application/ld+json"]');
    expect(script).toBeInTheDocument();
  });

  it('serializes data as JSON inside the script tag', () => {
    const data = { '@context': 'https://schema.org', '@type': 'WebSite', name: 'GoodGo' };
    const { container } = render(<JsonLd data={data} />);
    const script = container.querySelector('script')!;
    expect(JSON.parse(script.innerHTML)).toEqual(data);
  });

  it('handles array data', () => {
    const data = [
      { '@context': 'https://schema.org', '@type': 'WebSite' },
      { '@context': 'https://schema.org', '@type': 'Organization' },
    ];
    const { container } = render(<JsonLd data={data} />);
    const script = container.querySelector('script')!;
    expect(JSON.parse(script.innerHTML)).toHaveLength(2);
  });
});

// ─── generateWebsiteJsonLd ──────────────────────────────────

describe('generateWebsiteJsonLd', () => {
  it('generates WebSite schema', () => {
    const result = generateWebsiteJsonLd('https://goodgo.vn');
    expect(result['@context']).toBe('https://schema.org');
    expect(result['@type']).toBe('WebSite');
    expect(result.name).toBe('GoodGo');
    expect(result.url).toBe('https://goodgo.vn');
  });

  it('includes SearchAction', () => {
    const result = generateWebsiteJsonLd('https://goodgo.vn');
    expect(result.potentialAction).toBeDefined();
    const action = result.potentialAction as Record<string, unknown>;
    expect(action['@type']).toBe('SearchAction');
  });

  it('includes bilingual language', () => {
    const result = generateWebsiteJsonLd('https://goodgo.vn');
    expect(result.inLanguage).toEqual(['vi', 'en']);
  });
});

// ─── generateBreadcrumbJsonLd ───────────────────────────────

describe('generateBreadcrumbJsonLd', () => {
  it('generates BreadcrumbList schema', () => {
    const items = [
      { name: 'Trang chủ', url: 'https://goodgo.vn' },
      { name: 'Tìm kiếm', url: 'https://goodgo.vn/search' },
    ];
    const result = generateBreadcrumbJsonLd(items);
    expect(result['@type']).toBe('BreadcrumbList');
    expect(result.itemListElement).toHaveLength(2);
  });

  it('sets correct positions starting from 1', () => {
    const items = [
      { name: 'Home', url: 'https://goodgo.vn' },
      { name: 'Search', url: 'https://goodgo.vn/search' },
    ];
    const result = generateBreadcrumbJsonLd(items);
    const elements = result.itemListElement as Array<Record<string, unknown>>;
    expect(elements[0]?.['position']).toBe(1);
    expect(elements[1]?.['position']).toBe(2);
  });

  it('returns empty list for no items', () => {
    const result = generateBreadcrumbJsonLd([]);
    expect(result.itemListElement).toEqual([]);
  });
});

// ─── generateListingJsonLd ──────────────────────────────────

describe('generateListingJsonLd', () => {
  const mockListing: ListingDetail = {
    id: 'listing-1',
    status: 'ACTIVE',
    transactionType: 'SALE',
    priceVND: '3500000000',
    pricePerM2: 40_000_000,
    rentPriceMonthly: null,
    commissionPct: null,
    viewCount: 10,
    saveCount: 5,
    inquiryCount: 3,
    publishedAt: '2026-01-01T00:00:00Z',
    createdAt: '2025-12-01T00:00:00Z',
    valuationEstimate: null,
    agentQualityScore: null,
    similarCount: 0,
    property: {
      id: 'prop-1',
      propertyType: 'APARTMENT',
      title: 'Căn hộ 2PN',
      description: 'Mô tả căn hộ đẹp',
      address: '123 Nguyễn Hữu Thọ',
      ward: 'Phường Tân Hưng',
      district: 'Quận 7',
      city: 'Hồ Chí Minh',
      areaM2: 75,
      bedrooms: 2,
      bathrooms: 2,
      floors: null,
      direction: null,
      yearBuilt: null,
      legalStatus: null,
      amenities: [],
      projectName: null,
      latitude: 10.73,
      longitude: 106.72,
      media: [{ id: 'media-1', type: 'image', url: 'https://example.com/img1.jpg', order: 0, caption: null }],
      usableAreaM2: null,
      floor: null,
      totalFloors: null,
      nearbyPOIs: null,
      metroDistanceM: null,
      furnishing: null,
      propertyCondition: null,
      balconyDirection: null,
      maintenanceFeeVND: null,
      parkingSlots: null,
      viewType: [],
      petFriendly: null,
      suitableFor: [],
      whyThisLocation: null,
    },
    seller: { id: 'seller-1', fullName: 'Seller', phone: '0912345678' },
    agent: null,
  };

  it('generates RealEstateListing schema type', () => {
    const result = generateListingJsonLd(mockListing, 'https://goodgo.vn');
    expect(result['@type']).toBe('RealEstateListing');
  });

  it('sets correct URL', () => {
    const result = generateListingJsonLd(mockListing, 'https://goodgo.vn');
    expect(result['url']).toBe('https://goodgo.vn/listings/listing-1');
  });

  it('includes offer with VND price', () => {
    const result = generateListingJsonLd(mockListing, 'https://goodgo.vn');
    const offers = result['offers'] as Record<string, unknown>;
    expect(offers['price']).toBe(3_500_000_000);
    expect(offers['priceCurrency']).toBe('VND');
  });

  it('sets InStock availability for ACTIVE listing', () => {
    const result = generateListingJsonLd(mockListing, 'https://goodgo.vn');
    const offers = result['offers'] as Record<string, unknown>;
    expect(offers['availability']).toBe('https://schema.org/InStock');
  });

  it('sets SoldOut availability for non-ACTIVE listing', () => {
    const soldListing = { ...mockListing, status: 'SOLD' as const };
    const result = generateListingJsonLd(soldListing, 'https://goodgo.vn');
    const offers = result['offers'] as Record<string, unknown>;
    expect(offers['availability']).toBe('https://schema.org/SoldOut');
  });

  it('includes geo coordinates when available', () => {
    const result = generateListingJsonLd(mockListing, 'https://goodgo.vn');
    const location = result['contentLocation'] as Record<string, unknown>;
    const geo = location['geo'] as Record<string, unknown>;
    expect(geo['latitude']).toBe(10.73);
    expect(geo['longitude']).toBe(106.72);
  });

  it('includes property area in additionalProperty', () => {
    const result = generateListingJsonLd(mockListing, 'https://goodgo.vn');
    const additionalProps = result['additionalProperty'] as Array<Record<string, unknown>>;
    const areaEntry = additionalProps.find((p) => p['name'] === 'Dien tich');
    expect(areaEntry?.['value']).toBe('75 m\u00B2');
  });

  it('includes bedrooms when present', () => {
    const result = generateListingJsonLd(mockListing, 'https://goodgo.vn');
    const additionalProps = result['additionalProperty'] as Array<Record<string, unknown>>;
    const bedEntry = additionalProps.find((p) => p['name'] === 'Phong ngu');
    expect(bedEntry?.['value']).toBe(2);
  });

  it('excludes bedrooms when null', () => {
    const noBedListing = {
      ...mockListing,
      property: { ...mockListing.property, bedrooms: null },
    };
    const result = generateListingJsonLd(noBedListing, 'https://goodgo.vn');
    const additionalProps = result['additionalProperty'] as Array<Record<string, unknown>>;
    const bedEntry = additionalProps.find((p) => p['name'] === 'Phong ngu');
    expect(bedEntry).toBeUndefined();
  });
});

// ─── generateAgentJsonLd ────────────────────────────────────

describe('generateAgentJsonLd', () => {
  const mockAgent: AgentPublicProfile = {
    id: 'agent-1',
    fullName: 'Nguyen Van C',
    phone: '0912345678',
    email: 'agent@goodgo.vn',
    avatarUrl: 'https://example.com/avatar.jpg',
    bio: 'Agent chuyên nghiệp',
    agency: 'GoodGo Agency',
    licenseNumber: null,
    serviceAreas: ['Quận 1', 'Quận 7'],
    activeListings: [],
    totalReviews: 20,
    avgReviewRating: 4.5,
    qualityScore: 95,
    totalDeals: 50,
    isVerified: true,
    memberSince: '2024-01-01T00:00:00Z',
  };

  it('generates RealEstateAgent schema type', () => {
    const result = generateAgentJsonLd(mockAgent, 'https://goodgo.vn');
    expect(result['@type']).toBe('RealEstateAgent');
  });

  it('includes agent name', () => {
    const result = generateAgentJsonLd(mockAgent, 'https://goodgo.vn');
    expect(result['name']).toBe('Nguyen Van C');
  });

  it('includes aggregate rating when reviews exist', () => {
    const result = generateAgentJsonLd(mockAgent, 'https://goodgo.vn');
    const rating = result['aggregateRating'] as Record<string, unknown>;
    expect(rating['ratingValue']).toBe(4.5);
    expect(rating['reviewCount']).toBe(20);
  });

  it('excludes aggregate rating when no reviews', () => {
    const noReviewAgent = { ...mockAgent, totalReviews: 0 };
    const result = generateAgentJsonLd(noReviewAgent, 'https://goodgo.vn');
    expect(result['aggregateRating']).toBeUndefined();
  });

  it('includes service areas', () => {
    const result = generateAgentJsonLd(mockAgent, 'https://goodgo.vn');
    const areas = result['areaServed'] as Array<Record<string, unknown>>;
    expect(areas).toHaveLength(2);
    expect(areas[0]?.['name']).toBe('Quận 1');
  });

  it('includes agency as worksFor', () => {
    const result = generateAgentJsonLd(mockAgent, 'https://goodgo.vn');
    const worksFor = result['worksFor'] as Record<string, unknown>;
    expect(worksFor['name']).toBe('GoodGo Agency');
  });
});
