import { act, renderHook } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';

import { useFilters } from './useFilters';
import type { FeatureMeta } from '../types';

vi.mock('../lib/analytics', () => ({
  trackEvent: vi.fn(),
}));

describe('useFilters', () => {
  const features: FeatureMeta[] = [
    {
      name: 'price',
      type: 'numeric',
      min: 0,
      max: 100,
    },
  ];

  it('activates slider preview on pointer down without committing unchanged clicks', () => {
    const { result } = renderHook(() =>
      useFilters({
        initialFilters: { price: [0, 100] },
        features,
      })
    );

    act(() => {
      result.current.handleDragStart('price', [0, 100]);
    });

    expect(result.current.activeFeature).toBe('price');
    expect(result.current.viewSource).toBe('drag');
    expect(result.current.dragValue).toEqual([0, 100]);
    expect(result.current.filterRange).toEqual([0, 100]);

    act(() => {
      result.current.handleDragEnd();
    });

    expect(result.current.activeFeature).toBeNull();
    expect(result.current.dragValue).toBeNull();
    expect(result.current.filters.price).toEqual([0, 100]);

    act(() => {
      result.current.handleDragStart('price', [0, 100]);
      result.current.handleDragChange([10, 90]);
    });

    expect(result.current.activeFeature).toBe('price');
    expect(result.current.viewSource).toBe('drag');

    act(() => {
      result.current.handleDragEnd();
    });

    expect(result.current.activeFeature).toBeNull();
    expect(result.current.filters.price).toEqual([10, 90]);
  });

  it('caps the number of filters for demo users and reports when the limit is hit', () => {
    const sixFeatures: FeatureMeta[] = ['a', 'b', 'c', 'd', 'e', 'f'].map((name) => ({
      name,
      type: 'numeric',
      min: 0,
      max: 100,
    }));
    const onFilterLimitReached = vi.fn();

    const { result } = renderHook(() =>
      useFilters({
        initialFilters: {},
        features: sixFeatures,
        filterLimit: 5,
        onFilterLimitReached,
      })
    );

    act(() => {
      ['a', 'b', 'c', 'd', 'e'].forEach((name) => result.current.handleAddFilter(name));
    });
    expect(Object.keys(result.current.filters)).toHaveLength(5);
    expect(onFilterLimitReached).not.toHaveBeenCalled();

    // The 6th distinct filter is blocked and reported.
    act(() => {
      result.current.handleAddFilter('f');
    });
    expect(Object.keys(result.current.filters)).toHaveLength(5);
    expect(result.current.filters.f).toBeUndefined();
    expect(onFilterLimitReached).toHaveBeenCalledTimes(1);

    // Re-adding an already-present feature is allowed (it replaces, no new key).
    act(() => {
      result.current.handleAddFilter('a');
    });
    expect(Object.keys(result.current.filters)).toHaveLength(5);
    expect(onFilterLimitReached).toHaveBeenCalledTimes(1);
  });

  it('caps bulk handleSetFilters (e.g. AI results) to the demo limit and reports it', () => {
    const sixFeatures: FeatureMeta[] = ['a', 'b', 'c', 'd', 'e', 'f'].map((name) => ({
      name,
      type: 'numeric',
      min: 0,
      max: 100,
    }));
    const onFilterLimitReached = vi.fn();

    const { result } = renderHook(() =>
      useFilters({
        initialFilters: {},
        features: sixFeatures,
        filterLimit: 5,
        onFilterLimitReached,
      })
    );

    act(() => {
      result.current.handleSetFilters({
        a: [0, 1],
        b: [0, 1],
        c: [0, 1],
        d: [0, 1],
        e: [0, 1],
        f: [0, 1],
      });
    });

    expect(Object.keys(result.current.filters)).toHaveLength(5);
    expect(onFilterLimitReached).toHaveBeenCalledTimes(1);
  });

  it('does not cap filters when filterLimit is null (licensed users)', () => {
    const sixFeatures: FeatureMeta[] = ['a', 'b', 'c', 'd', 'e', 'f'].map((name) => ({
      name,
      type: 'numeric',
      min: 0,
      max: 100,
    }));

    const { result } = renderHook(() =>
      useFilters({
        initialFilters: {},
        features: sixFeatures,
        filterLimit: null,
      })
    );

    act(() => {
      ['a', 'b', 'c', 'd', 'e', 'f'].forEach((name) => result.current.handleAddFilter(name));
    });
    expect(Object.keys(result.current.filters)).toHaveLength(6);
  });

  it('uses the provided initial range for drag-only feature keys', () => {
    const { result } = renderHook(() =>
      useFilters({
        initialFilters: {},
        features,
      })
    );

    act(() => {
      result.current.handleDragStart('tt_car_station', [15, 45]);
    });

    expect(result.current.activeFeature).toBe('tt_car_station');
    expect(result.current.dragValue).toEqual([15, 45]);
    expect(result.current.filterRange).toEqual([15, 45]);

    act(() => {
      result.current.handleDragEnd();
    });

    expect(result.current.activeFeature).toBeNull();
    expect(result.current.dragValue).toBeNull();
    expect(result.current.filters).toEqual({});
  });
});
