/**
 * @vitest-environment node
 */
import { describe, it, expect, beforeEach, vi } from 'vitest';
import type { ListingDetail } from '../listings-api';

// Provide a minimal localStorage mock before importing the store module
// (Zustand persist needs getItem/setItem)
const store: Record<string, string> = {};
vi.stubGlobal('localStorage', {
  getItem: (key: string) => store[key] ?? null,
  setItem: (key: string, value: string) => { store[key] = value; },
  removeItem: (key: string) => { delete store[key]; },
  clear: () => { for (const k of Object.keys(store)) delete store[k]; },
  get length() { return Object.keys(store).length; },
  key: (i: number) => Object.keys(store)[i] ?? null,
});

// Now import after mocks are in place
const { useComparisonStore, computeComparisonStats, MAX_COMPARE, MIN_COMPARE } = await import('../comparison-store');

// Reset Zustand store between tests
beforeEach(() => {
  useComparisonStore.setState({
    selectedIds: [],
    listings: [],
    isLoading: false,
    error: null,
  });
});

// ---------------------------------------------------------------------------
// Store — addToCompare / removeFromCompare / isSelected
// ---------------------------------------------------------------------------

describe('useComparisonStore', () => {
  it('adds a listing ID to the comparison set', () => {
    const { addToCompare } = useComparisonStore.getState();
    const result = addToCompare('listing-1');
    expect(result).toBe(true);
    expect(useComparisonStore.getState().selectedIds).toEqual(['listing-1']);
  });

  it('does not add duplicate IDs', () => {
    const { addToCompare } = useComparisonStore.getState();
    addToCompare('listing-1');
    const result = addToCompare('listing-1');
    expect(result).toBe(false);
    expect(useComparisonStore.getState().selectedIds).toEqual(['listing-1']);
  });

  it('respects MAX_COMPARE limit', () => {
    const { addToCompare } = useComparisonStore.getState();
    for (let i = 1; i <= MAX_COMPARE; i++) {
      expect(addToCompare(`listing-${i}`)).toBe(true);
    }
    const result = addToCompare(`listing-${MAX_COMPARE + 1}`);
    expect(result).toBe(false);
    expect(useComparisonStore.getState().selectedIds.length).toBe(MAX_COMPARE);
  });

  it('removes a listing ID from the comparison set', () => {
    const store = useComparisonStore.getState();
    store.addToCompare('listing-1');
    store.addToCompare('listing-2');
    store.removeFromCompare('listing-1');
    expect(useComparisonStore.getState().selectedIds).toEqual(['listing-2']);
  });

  it('isSelected returns correct value', () => {
    const store = useComparisonStore.getState();
    store.addToCompare('listing-1');
    expect(store.isSelected('listing-1')).toBe(true);
    expect(store.isSelected('listing-2')).toBe(false);
  });

  it('clearAll resets the store', () => {
    const store = useComparisonStore.getState();
    store.addToCompare('listing-1');
    store.addToCompare('listing-2');
    store.clearAll();
    const state = useComparisonStore.getState();
    expect(state.selectedIds).toEqual([]);
    expect(state.listings).toEqual([]);
    expect(state.error).toBeNull();
  });

  it('canCompare returns true when >= MIN_COMPARE items selected', () => {
    const store = useComparisonStore.getState();
    store.addToCompare('listing-1');
    expect(useComparisonStore.getState().canCompare()).toBe(false);
    store.addToCompare('listing-2');
    expect(useComparisonStore.getState().canCompare()).toBe(true);
  });

  it('canAdd returns false when MAX_COMPARE items selected', () => {
    const store = useComparisonStore.getState();
    for (let i = 1; i <= MAX_COMPARE; i++) {
      store.addToCompare(`listing-${i}`);
    }
    expect(useComparisonStore.getState().canAdd()).toBe(false);
  });

  it('setListings stores listing data and clears loading/error', () => {
    const store = useComparisonStore.getState();
    store.setLoading(true);
    store.setError('some error');
    const mockListings = [makeListing('1'), makeListing('2')];
    store.setListings(mockListings);
    const state = useComparisonStore.getState();
    expect(state.listings).toEqual(mockListings);
    expect(state.isLoading).toBe(false);
    expect(state.error).toBeNull();
  });

  it('removeFromCompare also removes from listings', () => {
    const store = useComparisonStore.getState();
    store.addToCompare('listing-1');
    store.addToCompare('listing-2');
    store.setListings([makeListing('listing-1'), makeListing('listing-2')]);
    store.removeFromCompare('listing-1');
    const state = useComparisonStore.getState();
    expect(state.selectedIds).toEqual(['listing-2']);
    expect(state.listings.length).toBe(1);
    expect(state.listings[0]?.id).toBe('listing-2');
  });
});

// ---------------------------------------------------------------------------
// computeComparisonStats
// ---------------------------------------------------------------------------

describe('computeComparisonStats', () => {
  it('returns null for fewer than MIN_COMPARE listings', () => {
    expect(computeComparisonStats([])).toBeNull();
    expect(computeComparisonStats([makeListing('1')])).toBeNull();
  });

  it('computes correct price range', () => {
    const listings = [
      makeListing('1', { priceVND: '1000000000' }),
      makeListing('2', { priceVND: '2000000000' }),
      makeListing('3', { priceVND: '3000000000' }),
    ];
    const stats = computeComparisonStats(listings);
    expect(stats).not.toBeNull();
    expect(stats!.priceRange.min).toBe(1_000_000_000);
    expect(stats!.priceRange.max).toBe(3_000_000_000);
    expect(stats!.priceRange.avg).toBe(2_000_000_000);
  });

  it('computes correct area range', () => {
    const listings = [
      makeListing('1', { areaM2: 50 }),
      makeListing('2', { areaM2: 100 }),
    ];
    const stats = computeComparisonStats(listings);
    expect(stats).not.toBeNull();
    expect(stats!.areaRange.min).toBe(50);
    expect(stats!.areaRange.max).toBe(100);
    expect(stats!.areaRange.avg).toBe(75);
  });

  it('computes pricePerM2Range when data is available', () => {
    const listings = [
      makeListing('1', { pricePerM2: 20_000_000 }),
      makeListing('2', { pricePerM2: 40_000_000 }),
    ];
    const stats = computeComparisonStats(listings);
    expect(stats).not.toBeNull();
    expect(stats!.pricePerM2Range).not.toBeNull();
    expect(stats!.pricePerM2Range!.min).toBe(20_000_000);
    expect(stats!.pricePerM2Range!.max).toBe(40_000_000);
    expect(stats!.pricePerM2Range!.avg).toBe(30_000_000);
  });

  it('returns null pricePerM2Range when no pricePerM2 data', () => {
    const listings = [
      makeListing('1', { pricePerM2: null }),
      makeListing('2', { pricePerM2: null }),
    ];
    const stats = computeComparisonStats(listings);
    expect(stats).not.toBeNull();
    expect(stats!.pricePerM2Range).toBeNull();
  });

  it('handles mixed pricePerM2 availability', () => {
    const listings = [
      makeListing('1', { pricePerM2: 30_000_000 }),
      makeListing('2', { pricePerM2: null }),
      makeListing('3', { pricePerM2: 50_000_000 }),
    ];
    const stats = computeComparisonStats(listings);
    expect(stats).not.toBeNull();
    expect(stats!.pricePerM2Range).not.toBeNull();
    expect(stats!.pricePerM2Range!.min).toBe(30_000_000);
    expect(stats!.pricePerM2Range!.max).toBe(50_000_000);
    expect(stats!.pricePerM2Range!.avg).toBe(40_000_000);
  });
});

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

describe('constants', () => {
  it('MAX_COMPARE is 5', () => {
    expect(MAX_COMPARE).toBe(5);
  });

  it('MIN_COMPARE is 2', () => {
    expect(MIN_COMPARE).toBe(2);
  });
});

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function makeListing(
  id: string,
  overrides: {
    priceVND?: string;
    areaM2?: number;
    pricePerM2?: number | null;
  } = {},
): ListingDetail {
  return {
    id,
    status: 'ACTIVE',
    transactionType: 'SALE',
    priceVND: overrides.priceVND ?? '1500000000',
    pricePerM2: overrides.pricePerM2 !== undefined ? overrides.pricePerM2 : 30_000_000,
    rentPriceMonthly: null,
    commissionPct: null,
    viewCount: 0,
    saveCount: 0,
    inquiryCount: 0,
    publishedAt: null,
    createdAt: '2026-01-01T00:00:00Z',
    valuationEstimate: null,
    agentQualityScore: null,
    similarCount: 0,
    property: {
      id: `prop-${id}`,
      propertyType: 'APARTMENT',
      title: `Test Property ${id}`,
      description: 'A test property',
      address: '123 Test St',
      ward: 'Ward 1',
      district: 'District 1',
      city: 'Ho Chi Minh',
      areaM2: overrides.areaM2 ?? 80,
      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: 'seller-1',
      fullName: 'Test Seller',
      phone: '0912345678',
    },
    agent: null,
  };
}
