import { describe, expect, it } from 'vitest';
import type { FeatureMeta } from '../types';
import {
  CRIME_SEVERITY_FILTER_NAMES,
  createCrimeSeverityFilterKey,
  getCrimeSeverityFeatureName,
  getCrimeSeverityFilterKeyId,
  getCrimeSeverityFilterName,
  getCrimeSeverityVariantConfig,
  getDefaultCrimeSeverityFeatureName,
  isCrimeSeverityFeatureName,
  isCrimeSeverityFilterName,
  normalizeCrimeSeverityFilters,
} from './crime-severity-filter';

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

describe('crime-severity feature recognition', () => {
  it('recognizes Serious/Minor crime in both windows only', () => {
    expect(isCrimeSeverityFeatureName('Serious crime (/yr, 7y)')).toBe(true);
    expect(isCrimeSeverityFeatureName('Serious crime (/yr, 2y)')).toBe(true);
    expect(isCrimeSeverityFeatureName('Minor crime (/yr, 2y)')).toBe(true);
    // Detailed categories belong to "Specific crimes", not severity.
    expect(isCrimeSeverityFeatureName('Burglary (/yr, 7y)')).toBe(false);
    // Bare names without a window suffix are not feature columns.
    expect(isCrimeSeverityFeatureName('Serious crime')).toBe(false);
  });

  it('maps a feature or key back to its severity filter name', () => {
    expect(getCrimeSeverityFilterName('Serious crime (/yr, 2y)')).toBe('Serious crime');
    expect(getCrimeSeverityFilterName('Minor crime (/yr, 7y)')).toBe('Minor crime');
    const key = createCrimeSeverityFilterKey('Serious crime', 'Serious crime (/yr, 7y)', 0);
    expect(getCrimeSeverityFilterName(key)).toBe('Serious crime');
    expect(getCrimeSeverityFilterName('Burglary (/yr, 7y)')).toBeNull();
  });
});

describe('crime-severity filter keys', () => {
  it('resolves a 2-year key back to its backend column and id', () => {
    const key = createCrimeSeverityFilterKey('Minor crime', 'Minor crime (/yr, 2y)', 4);
    expect(isCrimeSeverityFilterName(key)).toBe(true);
    expect(getCrimeSeverityFilterKeyId(key)).toBe('4');
    expect(getCrimeSeverityFeatureName(key)).toBe('Minor crime (/yr, 2y)');
  });

  it('defaults to the 7-year window when present', () => {
    const features = [numeric('Serious crime (/yr, 7y)'), numeric('Serious crime (/yr, 2y)')];
    expect(getDefaultCrimeSeverityFeatureName(features, 'Serious crime')).toBe(
      'Serious crime (/yr, 7y)'
    );
    expect(getDefaultCrimeSeverityFeatureName(features, 'Minor crime')).toBeNull();
  });

  it('folds bare severity features but leaves specific crimes and others alone', () => {
    const normalized = normalizeCrimeSeverityFilters({
      'Serious crime (/yr, 2y)': [1, 5],
      'Burglary (/yr, 7y)': [0, 3],
      'Median price (£)': [0, 100],
    });
    const keys = Object.keys(normalized);
    const severityKey = keys.find((k) => isCrimeSeverityFilterName(k))!;
    expect(getCrimeSeverityFeatureName(severityKey)).toBe('Serious crime (/yr, 2y)');
    expect(normalized[severityKey]).toEqual([1, 5]);
    // Specific-crime + plain features pass through untouched.
    expect(normalized['Burglary (/yr, 7y)']).toEqual([0, 3]);
    expect(normalized['Median price (£)']).toEqual([0, 100]);
  });
});

describe('crime-severity variant config', () => {
  it('exposes a single variant per severity with a 7y/2y window toggle', () => {
    for (const filterName of CRIME_SEVERITY_FILTER_NAMES) {
      const config = getCrimeSeverityVariantConfig(filterName);
      expect(config.filterName).toBe(filterName);
      expect(config.featureNames).toEqual([`${filterName} (/yr, 7y)`]);
      expect(config.window?.options.map((o) => o.id)).toEqual(['7y', '2y']);
      // Switching window re-points to the same severity, other window.
      const sevenYear = `${filterName} (/yr, 7y)`;
      expect(config.window?.withWindow(sevenYear, '2y')).toBe(`${filterName} (/yr, 2y)`);
    }
  });
});
