import { useMemo } from 'react';
import { cellToLatLng } from 'h3-js';

import type { FeatureMeta, HexagonStatsResponse, PostcodeFeature } from '../../../types';
import type { HexagonLocation } from '../../../lib/external-search';
import type { useMapData } from '../../../hooks/useMapData';
import { resolveTransitVariant, type TravelTimeEntry } from '../../../hooks/useTravelTime';
import { getSpecificCrimeFeatureName } from '../../../lib/crime-filter';
import { getElectionVoteShareFeatureName } from '../../../lib/election-filter';
import { getEthnicityFeatureName } from '../../../lib/ethnicity-filter';
import { getPoiDistanceFeatureName } from '../../../lib/poi-distance-filter';
import { getSchoolBackendFeatureName } from '../../../lib/school-filter';

type MapData = ReturnType<typeof useMapData>;

interface SelectedHexagon {
  id: string;
  type: 'hexagon' | 'postcode';
  resolution: number;
}

export function getMapPageBackendFeatureName(featureName: string): string {
  return (
    getSchoolBackendFeatureName(featureName) ??
    getSpecificCrimeFeatureName(featureName) ??
    getElectionVoteShareFeatureName(featureName) ??
    getEthnicityFeatureName(featureName) ??
    getPoiDistanceFeatureName(featureName) ??
    featureName
  );
}

export function useJourneyDestination(entries: TravelTimeEntry[]) {
  return useMemo(() => {
    const entry = entries.find((item) => item.mode === 'transit' && item.slug);
    // The server needs the resolved variant (e.g. transit-no-change-no-bus)
    // to look up the correct parquet directory, not the UI-side base mode.
    return entry ? { mode: resolveTransitVariant(entry), slug: entry.slug } : null;
  }, [entries]);
}

export function useMapViewFeature(viewFeature: string | null) {
  return useMemo(
    () => (viewFeature ? getMapPageBackendFeatureName(viewFeature) : null),
    [viewFeature]
  );
}

export function useMobileLegendMeta(viewFeature: string | null, features: FeatureMeta[]) {
  return useMemo(() => {
    const featureName = viewFeature ? getMapPageBackendFeatureName(viewFeature) : null;
    return featureName ? features.find((feature) => feature.name === featureName) || null : null;
  }, [viewFeature, features]);
}

export function useMobileDensityRange(mapData: MapData): [number, number] {
  return useMemo(() => {
    const items = mapData.usePostcodeView ? mapData.postcodeData : mapData.data;
    if (items.length === 0) return [0, 1];
    let min = Infinity;
    let max = -Infinity;
    for (const item of items) {
      const count = 'count' in item ? item.count : item.properties.count;
      if (count <= 0) continue;
      if (count < min) min = count;
      if (count > max) max = count;
    }
    if (min === Infinity) return [0, 1];
    if (min === max) return [min, min + 1];
    return [min, max];
  }, [mapData.data, mapData.postcodeData, mapData.usePostcodeView]);
}

export function useHexagonLocation(
  selectedHexagon: SelectedHexagon | null,
  postcodeData: PostcodeFeature[],
  resolution: number,
  areaStats: HexagonStatsResponse | null
): HexagonLocation | null {
  return useMemo(() => {
    const hexId = selectedHexagon?.id;
    const isPostcode = selectedHexagon?.type === 'postcode';

    if (isPostcode) {
      const postcodeFeature = postcodeData.find((feature) => feature.properties.postcode === hexId);
      if (!postcodeFeature?.properties.centroid) return null;
      const [lon, lat] = postcodeFeature.properties.centroid;
      return { lat, lon, resolution, postcode: hexId, isPostcode: true };
    }

    if (!hexId) return null;
    const [lat, lon] = cellToLatLng(hexId);
    return {
      lat,
      lon,
      resolution: selectedHexagon?.resolution ?? resolution,
      postcode: areaStats?.central_postcode,
    };
  }, [selectedHexagon, postcodeData, resolution, areaStats?.central_postcode]);
}
