import { describe, expect, it } from 'vitest';
import type { FeatureMeta } from '../types';
import {
  SPECIFIC_CRIME_FEATURE_NAMES,
  createSpecificCrimeFilterKey,
  getDefaultSpecificCrimeFeatureName,
  getSpecificCrimeFeatureName,
  getSpecificCrimeFilterKeyId,
  getSpecificCrimeType,
  getSpecificCrimeWindow,
  isSpecificCrimeFeatureName,
  isSpecificCrimeFilterName,
  normalizeSpecificCrimeFilters,
  specificCrimeFeatureName,
  withSpecificCrimeWindow,
} from './crime-filter';

const numeric = (name: string): FeatureMeta => ({ name, type: 'numeric', min: 0, max: 10 });

describe('specific-crime window helpers', () => {
  it('recognizes both the 7-year and 2-year rate features', () => {
    expect(isSpecificCrimeFeatureName('Burglary (/yr, 7y)')).toBe(true);
    expect(isSpecificCrimeFeatureName('Burglary (/yr, 2y)')).toBe(true);
    expect(isSpecificCrimeFeatureName('Burglary (avg/yr)')).toBe(false);
    // The "Serious crime" / "Minor crime" aggregates stay separate sliders.
    expect(isSpecificCrimeFeatureName('Serious crime (/yr, 7y)')).toBe(false);
  });

  it('extracts the window and bare type', () => {
    expect(getSpecificCrimeWindow('Burglary (/yr, 2y)')).toBe('2y');
    expect(getSpecificCrimeWindow('Burglary (/yr, 7y)')).toBe('7y');
    expect(getSpecificCrimeWindow('Burglary')).toBeNull();
    expect(getSpecificCrimeType('Violence and sexual offences (/yr, 2y)')).toBe(
      'Violence and sexual offences'
    );
    expect(getSpecificCrimeType('not a crime')).toBeNull();
  });

  it('swaps a feature name between windows and round-trips', () => {
    expect(withSpecificCrimeWindow('Burglary (/yr, 7y)', '2y')).toBe('Burglary (/yr, 2y)');
    expect(withSpecificCrimeWindow('Burglary (/yr, 2y)', '7y')).toBe('Burglary (/yr, 7y)');
    // Unrecognized names pass through untouched.
    expect(withSpecificCrimeWindow('Burglary', '2y')).toBe('Burglary');
    expect(specificCrimeFeatureName('Drugs', '2y')).toBe('Drugs (/yr, 2y)');
  });

  it('defaults to the 7-year window and enumerates 7-year dropdown names', () => {
    const features = [numeric('Burglary (/yr, 7y)'), numeric('Burglary (/yr, 2y)')];
    expect(getDefaultSpecificCrimeFeatureName(features)).toBe('Burglary (/yr, 7y)');
    expect(SPECIFIC_CRIME_FEATURE_NAMES.every((n) => n.endsWith('(/yr, 7y)'))).toBe(true);
  });
});

describe('specific-crime filter keys', () => {
  it('resolves a 2-year filter key back to its backend column', () => {
    const key = createSpecificCrimeFilterKey('Burglary (/yr, 2y)', 3);
    expect(isSpecificCrimeFilterName(key)).toBe(true);
    expect(getSpecificCrimeFilterKeyId(key)).toBe('3');
    expect(getSpecificCrimeFeatureName(key)).toBe('Burglary (/yr, 2y)');
  });

  it('folds a bare 2-year crime feature into a multi-instance key', () => {
    const normalized = normalizeSpecificCrimeFilters({
      'Burglary (/yr, 2y)': [1, 5],
      'Median price (£)': [0, 100],
    });
    const keys = Object.keys(normalized);
    expect(keys.some((k) => isSpecificCrimeFilterName(k))).toBe(true);
    const crimeKey = keys.find((k) => isSpecificCrimeFilterName(k))!;
    expect(getSpecificCrimeFeatureName(crimeKey)).toBe('Burglary (/yr, 2y)');
    expect(normalized[crimeKey]).toEqual([1, 5]);
    // Non-crime filters are left untouched.
    expect(normalized['Median price (£)']).toEqual([0, 100]);
  });
});
