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

export const ELECTION_VOTE_SHARE_FILTER_NAME = 'Political vote share';
export const ELECTION_VOTE_SHARE_FILTER_KEY_PREFIX = `${ELECTION_VOTE_SHARE_FILTER_NAME}:`;

export const ELECTION_VOTE_SHARE_FEATURE_NAMES = [
  '% Labour',
  '% Conservative',
  '% Liberal Democrat',
  '% Reform UK',
  '% Green',
  '% Other parties',
] as const;

const ELECTION_VOTE_SHARE_FEATURE_NAME_SET = new Set<string>(ELECTION_VOTE_SHARE_FEATURE_NAMES);

export function isElectionVoteShareFeatureName(name: string): boolean {
  return ELECTION_VOTE_SHARE_FEATURE_NAME_SET.has(name);
}

export function isElectionVoteShareFilterName(name: string): boolean {
  return (
    isElectionVoteShareFeatureName(name) || name.startsWith(ELECTION_VOTE_SHARE_FILTER_KEY_PREFIX)
  );
}

export function createElectionVoteShareFilterKey(featureName: string, id: number | string): string {
  return `${ELECTION_VOTE_SHARE_FILTER_KEY_PREFIX}${encodeURIComponent(featureName)}:${id}`;
}

export function getElectionVoteShareFilterKeyId(name: string): string | null {
  if (!name.startsWith(ELECTION_VOTE_SHARE_FILTER_KEY_PREFIX)) return null;
  const rest = name.substring(ELECTION_VOTE_SHARE_FILTER_KEY_PREFIX.length);
  const lastColon = rest.lastIndexOf(':');
  return lastColon === -1 ? null : rest.substring(lastColon + 1);
}

export function parseElectionVoteShareFilterKey(name: string): string | null {
  if (!name.startsWith(ELECTION_VOTE_SHARE_FILTER_KEY_PREFIX)) return null;
  const rest = name.substring(ELECTION_VOTE_SHARE_FILTER_KEY_PREFIX.length);
  const lastColon = rest.lastIndexOf(':');
  if (lastColon === -1) return null;

  const decoded = decodeURIComponent(rest.substring(0, lastColon));
  return isElectionVoteShareFeatureName(decoded) ? decoded : null;
}

export function getElectionVoteShareFeatureName(name: string): string | null {
  if (isElectionVoteShareFeatureName(name)) return name;
  return parseElectionVoteShareFilterKey(name);
}

export function replaceElectionVoteShareFilterKeySelection(
  key: string,
  featureName: string
): string {
  const id = getElectionVoteShareFilterKeyId(key) ?? '0';
  return createElectionVoteShareFilterKey(featureName, id);
}

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

export function normalizeElectionVoteShareFilters(filters: FeatureFilters): FeatureFilters {
  let changed = false;
  const next: FeatureFilters = {};

  for (const [name, value] of Object.entries(filters)) {
    if (isElectionVoteShareFeatureName(name)) {
      next[createElectionVoteShareFilterKey(name, Object.keys(next).length)] = value;
      changed = true;
      continue;
    }
    next[name] = value;
  }

  return changed ? next : filters;
}

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

  return {
    name: ELECTION_VOTE_SHARE_FILTER_NAME,
    type: 'numeric',
    group: 'Neighbours',
    min: sourceFeature?.min ?? 0,
    max: sourceFeature?.max ?? 100,
    step: 1,
    description: 'Vote share by party in the 2024 General Election',
    detail:
      'Filter by one party vote-share percentage at a time for the constituency covering each postcode.',
    source: sourceFeature?.source ?? 'election-results',
    suffix: '%',
  };
}

export function clampElectionVoteShareRange(
  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))];
}
