import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, expect, it, vi } from 'vitest';
import type { ListingDetail, PaginatedResult } from '@/lib/listings-api';
import { SearchResults } from '../search-results';

// Mock PropertyCard
vi.mock('../property-card', () => ({
  PropertyCard: ({ listing }: { listing: ListingDetail }) => (
    <div data-testid={`property-card-${listing.id}`}>{listing.property.title}</div>
  ),
}));

function makeListing(id: string): ListingDetail {
  return {
    id,
    status: 'ACTIVE',
    transactionType: 'SALE',
    priceVND: '3500000000',
    pricePerM2: 40_000_000,
    rentPriceMonthly: null,
    commissionPct: null,
    viewCount: 100,
    saveCount: 10,
    inquiryCount: 5,
    publishedAt: '2026-01-01T00:00:00Z',
    createdAt: '2025-12-01T00:00:00Z',
    valuationEstimate: null,
    agentQualityScore: null,
    similarCount: 0,
    property: {
      id: `prop-${id}`,
      propertyType: 'APARTMENT',
      title: `Listing ${id}`,
      description: 'Test listing',
      address: '123 Test St',
      ward: 'Ward',
      district: 'District',
      city: 'HCMC',
      areaM2: 75,
      bedrooms: 2,
      bathrooms: 2,
      floors: null,
      direction: null,
      yearBuilt: null,
      legalStatus: null,
      amenities: [],
      projectName: null,
      latitude: null,
      longitude: null,
      media: [],
      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: 's1', fullName: 'Seller', phone: '0901234567' },
    agent: null,
  };
}

function makeResult(count: number, page = 1, totalPages = 1): PaginatedResult<ListingDetail> {
  return {
    data: Array.from({ length: count }, (_, i) => makeListing(`${i + 1}`)),
    total: count,
    page,
    limit: 10,
    totalPages,
  };
}

const defaultProps = {
  page: 1,
  sort: '',
  onPageChange: vi.fn(),
  onSortChange: vi.fn(),
};

describe('SearchResults', () => {
  it('renders loading spinner when loading', () => {
    const { container } = render(
      <SearchResults result={null} loading={true} {...defaultProps} />,
    );
    expect(container.querySelector('.animate-spin')).toBeInTheDocument();
  });

  it('renders error state', () => {
    render(
      <SearchResults result={null} loading={false} error={true} {...defaultProps} />,
    );
    expect(screen.getByText('Không thể tải kết quả tìm kiếm')).toBeInTheDocument();
  });

  it('renders retry button in error state', () => {
    const onRetry = vi.fn();
    render(
      <SearchResults result={null} loading={false} error={true} onRetry={onRetry} {...defaultProps} />,
    );
    expect(screen.getByText('Thử lại')).toBeInTheDocument();
  });

  it('calls onRetry when retry button clicked', async () => {
    const user = userEvent.setup();
    const onRetry = vi.fn();
    render(
      <SearchResults result={null} loading={false} error={true} onRetry={onRetry} {...defaultProps} />,
    );

    await user.click(screen.getByText('Thử lại'));
    expect(onRetry).toHaveBeenCalled();
  });

  it('renders empty state when no results', () => {
    render(
      <SearchResults result={makeResult(0)} loading={false} {...defaultProps} />,
    );
    expect(screen.getByText('Không tìm thấy kết quả')).toBeInTheDocument();
  });

  it('renders empty state with null result', () => {
    render(
      <SearchResults result={null} loading={false} {...defaultProps} />,
    );
    expect(screen.getByText('Không tìm thấy kết quả')).toBeInTheDocument();
  });

  it('renders property cards for results', () => {
    render(
      <SearchResults result={makeResult(3)} loading={false} {...defaultProps} />,
    );
    expect(screen.getByTestId('property-card-1')).toBeInTheDocument();
    expect(screen.getByTestId('property-card-2')).toBeInTheDocument();
    expect(screen.getByTestId('property-card-3')).toBeInTheDocument();
  });

  it('renders total results count', () => {
    render(
      <SearchResults result={makeResult(3)} loading={false} {...defaultProps} />,
    );
    expect(screen.getByText('3 kết quả')).toBeInTheDocument();
  });

  it('renders sort select', () => {
    render(
      <SearchResults result={makeResult(3)} loading={false} {...defaultProps} />,
    );
    expect(screen.getByText('Mới nhất')).toBeInTheDocument();
    expect(screen.getByText('Giá: Thấp đến cao')).toBeInTheDocument();
  });

  it('renders pagination buttons for multi-page results', () => {
    render(
      <SearchResults result={makeResult(3, 1, 3)} loading={false} {...defaultProps} />,
    );
    expect(screen.getByText('Trước')).toBeInTheDocument();
    expect(screen.getByText('Tiếp')).toBeInTheDocument();
  });

  it('disables Trước button on first page', () => {
    render(
      <SearchResults result={makeResult(3, 1, 3)} loading={false} page={1} sort="" onPageChange={vi.fn()} onSortChange={vi.fn()} />,
    );
    expect(screen.getByText('Trước')).toBeDisabled();
  });

  it('disables Tiếp button on last page', () => {
    render(
      <SearchResults result={makeResult(3, 3, 3)} loading={false} page={3} sort="" onPageChange={vi.fn()} onSortChange={vi.fn()} />,
    );
    expect(screen.getByText('Tiếp')).toBeDisabled();
  });

  it('calls onPageChange when Tiếp clicked', async () => {
    const user = userEvent.setup();
    const onPageChange = vi.fn();
    render(
      <SearchResults result={makeResult(3, 1, 3)} loading={false} page={1} sort="" onPageChange={onPageChange} onSortChange={vi.fn()} />,
    );

    await user.click(screen.getByText('Tiếp'));
    expect(onPageChange).toHaveBeenCalledWith(2);
  });

  it('does not render pagination for single page', () => {
    render(
      <SearchResults result={makeResult(3, 1, 1)} loading={false} {...defaultProps} />,
    );
    expect(screen.queryByText('Trước')).not.toBeInTheDocument();
  });
});
