import { render, screen } from '@testing-library/react';
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
import type { ValuationComparable } from '@/lib/valuation-api';
import { ComparablesMap } from '../comparables-map';

// Mapbox GL does not run cleanly in jsdom — mock with a minimal stand-in
// that records addTo calls so we can assert marker count.
const markerAddTo = vi.fn();
const mapAddControl = vi.fn();
const mapFitBounds = vi.fn();
const mapFlyTo = vi.fn();
const mapRemove = vi.fn();

vi.mock('mapbox-gl', () => {
  class MockMap {
    addControl = mapAddControl;
    fitBounds = mapFitBounds;
    flyTo = mapFlyTo;
    remove = mapRemove;
  }
  class MockNavigationControl {}
  class MockAttributionControl {}

  class MockMarker {
    setLngLat() {
      return this;
    }
    setPopup() {
      return this;
    }
    addTo() {
      markerAddTo();
      return this;
    }
    remove() {
      // noop
    }
  }

  class MockPopup {
    setHTML() {
      return this;
    }
  }

  class MockLngLatBounds {
    extend() {
      return this;
    }
    isEmpty() {
      return false;
    }
  }

  return {
    default: {
      accessToken: '',
      Map: MockMap,
      NavigationControl: MockNavigationControl,
      AttributionControl: MockAttributionControl,
      Marker: MockMarker,
      Popup: MockPopup,
      LngLatBounds: MockLngLatBounds,
    },
  };
});

vi.mock('mapbox-gl/dist/mapbox-gl.css', () => ({}));

const sampleComparables: ValuationComparable[] = [
  {
    id: 'comp-1',
    title: 'Căn hộ tương tự A',
    address: '456 Nguyễn Hữu Thọ',
    district: 'Quận 7',
    priceVND: '4800000000',
    areaM2: 78,
    pricePerM2: 61_500_000,
    similarity: 0.92,
    latitude: 10.73,
    longitude: 106.72,
  },
  {
    id: 'comp-2',
    title: 'Căn hộ tương tự B',
    address: '789 Phạm Viết Chánh',
    district: 'Bình Thạnh',
    priceVND: '5200000000',
    areaM2: 82,
    pricePerM2: 63_400_000,
    similarity: 0.7,
    latitude: 10.8,
    longitude: 106.7,
  },
];

describe('ComparablesMap', () => {
  beforeEach(() => {
    markerAddTo.mockClear();
    mapAddControl.mockClear();
    mapFitBounds.mockClear();
    mapFlyTo.mockClear();
    mapRemove.mockClear();
    process.env['NEXT_PUBLIC_MAPBOX_TOKEN'] = 'pk.test';
  });

  afterEach(() => {
    delete (process.env as Record<string, string | undefined>)[
      'NEXT_PUBLIC_MAPBOX_TOKEN'
    ];
  });

  it('renders header and descriptor', () => {
    render(<ComparablesMap comparables={sampleComparables} />);
    expect(screen.getByText('Bản đồ so sánh')).toBeInTheDocument();
    expect(screen.getByText(/2 BĐS so sánh/)).toBeInTheDocument();
  });

  it('renders prompt when mapbox token is missing', () => {
    delete (process.env as Record<string, string | undefined>)[
      'NEXT_PUBLIC_MAPBOX_TOKEN'
    ];
    render(<ComparablesMap comparables={sampleComparables} />);
    expect(
      screen.getByText(/Thiết lập NEXT_PUBLIC_MAPBOX_TOKEN/),
    ).toBeInTheDocument();
  });

  it('shows empty state when no comparables have coordinates', () => {
    const withoutCoords = sampleComparables.map(
      ({ latitude: _lat, longitude: _lng, ...rest }) => rest,
    );
    render(<ComparablesMap comparables={withoutCoords} />);
    expect(
      screen.getByText(/Không có toạ độ cho các BĐS so sánh/),
    ).toBeInTheDocument();
  });

  it('adds a marker for each geolocated comparable plus subject pin', () => {
    render(
      <ComparablesMap
        comparables={sampleComparables}
        subjectLatitude={10.77}
        subjectLongitude={106.7}
      />,
    );
    expect(markerAddTo).toHaveBeenCalledTimes(3);
  });
});
