import type { FeatureFilters, FeatureMeta } from '../types';

export const SCHOOL_FILTER_NAME = 'Schools';
export const SCHOOL_FILTER_KEY_PREFIX = `${SCHOOL_FILTER_NAME}:`;

export type SchoolPhase = 'primary' | 'secondary';
export type SchoolRating = 'good' | 'outstanding';

export interface SchoolFilterConfig {
  phase: SchoolPhase;
  rating: SchoolRating;
  featureName: string;
}

export const SCHOOL_FILTERS: SchoolFilterConfig[] = [
  {
    phase: 'primary',
    rating: 'good',
    featureName: 'Good+ primary school catchments',
  },
  {
    phase: 'secondary',
    rating: 'good',
    featureName: 'Good+ secondary school catchments',
  },
  {
    phase: 'primary',
    rating: 'outstanding',
    featureName: 'Outstanding primary school catchments',
  },
  {
    phase: 'secondary',
    rating: 'outstanding',
    featureName: 'Outstanding secondary school catchments',
  },
];

const SCHOOL_FEATURE_NAMES = new Set(SCHOOL_FILTERS.map((filter) => filter.featureName));

export function isBackendSchoolFeatureName(name: string): boolean {
  return SCHOOL_FEATURE_NAMES.has(name);
}

export function isSchoolFilterName(name: string): boolean {
  return isBackendSchoolFeatureName(name) || name.startsWith(SCHOOL_FILTER_KEY_PREFIX);
}

export function getSchoolFilterConfig(name: string): SchoolFilterConfig | null {
  const synthetic = parseSchoolFilterKey(name);
  if (synthetic) return synthetic;
  return SCHOOL_FILTERS.find((filter) => filter.featureName === name) ?? null;
}

export function getSchoolFeatureName(phase: SchoolPhase, rating: SchoolRating): string {
  return (
    SCHOOL_FILTERS.find((filter) => filter.phase === phase && filter.rating === rating)
      ?.featureName ?? SCHOOL_FILTERS[0].featureName
  );
}

export function createSchoolFilterKey(
  phase: SchoolPhase,
  rating: SchoolRating,
  id: number | string
): string {
  return `${SCHOOL_FILTER_KEY_PREFIX}${phase}:${rating}:${id}`;
}

export function getSchoolFilterKeyId(name: string): string | null {
  if (!name.startsWith(SCHOOL_FILTER_KEY_PREFIX)) return null;
  return name.split(':')[3] ?? null;
}

export function parseSchoolFilterKey(name: string): SchoolFilterConfig | null {
  if (!name.startsWith(SCHOOL_FILTER_KEY_PREFIX)) return null;
  const [, phaseRaw, ratingRaw] = name.split(':');
  const phase = phaseRaw as SchoolPhase;
  const rating = ratingRaw as SchoolRating;
  if (
    (phase !== 'primary' && phase !== 'secondary') ||
    (rating !== 'good' && rating !== 'outstanding')
  ) {
    return null;
  }

  return {
    phase,
    rating,
    featureName: getSchoolFeatureName(phase, rating),
  };
}

export function getSchoolBackendFeatureName(name: string): string | null {
  if (isBackendSchoolFeatureName(name)) return name;
  return parseSchoolFilterKey(name)?.featureName ?? null;
}

export function replaceSchoolFilterKeySelection(
  key: string,
  next: {
    phase?: SchoolPhase;
    rating?: SchoolRating;
  }
): string {
  const config = getSchoolFilterConfig(key) ?? SCHOOL_FILTERS[0];
  const parts = key.startsWith(SCHOOL_FILTER_KEY_PREFIX) ? key.split(':') : [];
  const id = parts[3] ?? '0';
  return createSchoolFilterKey(next.phase ?? config.phase, next.rating ?? config.rating, id);
}

export function getDefaultSchoolFeatureName(features: FeatureMeta[]): string | null {
  return (
    SCHOOL_FILTERS.find((filter) => features.some((feature) => feature.name === filter.featureName))
      ?.featureName ?? null
  );
}

export function getActiveSchoolFeatureName(filters: FeatureFilters): string | null {
  return Object.keys(filters).find(isSchoolFilterName) ?? null;
}

export function normalizeSchoolFilters(filters: FeatureFilters): FeatureFilters {
  let changed = false;
  const next: FeatureFilters = {};
  for (const [name, value] of Object.entries(filters)) {
    if (isBackendSchoolFeatureName(name)) {
      const config = getSchoolFilterConfig(name);
      if (!config) continue;
      next[createSchoolFilterKey(config.phase, config.rating, Object.keys(next).length)] = value;
      changed = true;
      continue;
    }
    next[name] = value;
  }

  return changed ? next : filters;
}

export function getSchoolFilterMeta(features: FeatureMeta[]): FeatureMeta {
  const sourceFeatureName = getDefaultSchoolFeatureName(features);
  const sourceFeature = sourceFeatureName
    ? features.find((feature) => feature.name === sourceFeatureName)
    : undefined;

  return {
    name: SCHOOL_FILTER_NAME,
    type: 'numeric',
    group: 'Schools',
    min: sourceFeature?.min ?? 0,
    max: sourceFeature?.max ?? 10,
    step: 1,
    description: 'Rated schools whose catchment area likely covers the postcode',
    detail:
      'Filter by how many Good+ or Outstanding primary or secondary schools have a historical catchment area covering the postcode. Catchments are modelled from each school’s pupil numbers and local child population, approximating distance-based admissions.',
    source: 'ofsted',
    raw: true,
  };
}

export function clampSchoolRange(value: [number, number], feature?: FeatureMeta): [number, number] {
  const min = feature?.histogram?.min ?? feature?.min ?? 0;
  const max = feature?.histogram?.max ?? feature?.max ?? Math.max(1, value[1]);
  return [Math.max(min, Math.min(value[0], max)), Math.max(min, Math.min(value[1], max))];
}
