import { useTranslation } from 'react-i18next';
import { Slider } from '../../ui/Slider';
import { FeatureActions } from '../../ui/FeatureIcons';
import { FeatureLabel } from '../../ui/FeatureLabel';
import type { FeatureFilters, FeatureMeta } from '../../../types';
import { formatNumber, type PercentileScale } from '../../../lib/format';
import { getFeatureIcon } from '../../../lib/feature-icons';
import { getGroupIcon } from '../../../lib/group-icons';
import {
  POI_DISTANCE_FILTER_NAME,
  TRANSPORT_DISTANCE_FILTER_NAME,
  clampPoiFilterRange,
  getDefaultPoiFilterFeatureName,
  getPoiDistanceFeatureName,
  getPoiFilterFeatureOptions,
  getPoiFilterMeta,
  getPoiFilterName,
  replacePoiFilterKeySelection,
  usesFixedPoiDistanceScale,
} from '../../../lib/poi-distance-filter';
import { PoiTypeDropdown } from './PoiTypeDropdown';
import { SliderLabels } from './SliderLabels';

export function PoiDistanceFilterCard({
  features,
  poiFeature,
  filters,
  activeFeature,
  dragValue,
  pinnedFeature,
  filterImpact,
  percentileScale,
  onFilterChange,
  onDragStart,
  onDragChange,
  onDragEnd,
  onTogglePin,
  onShowInfo,
  onRemove,
}: {
  features: FeatureMeta[];
  poiFeature: FeatureMeta;
  filters: FeatureFilters;
  activeFeature: string | null;
  dragValue: [number, number] | null;
  pinnedFeature: string | null;
  filterImpact?: number;
  percentileScale?: PercentileScale;
  onFilterChange: (name: string, value: [number, number] | string[]) => void;
  onDragStart: (name: string, initialValue?: [number, number]) => void;
  onDragChange: (value: [number, number]) => void;
  onDragEnd: () => void;
  onTogglePin: (name: string) => void;
  onShowInfo: (feature: FeatureMeta) => void;
  onRemove: () => void;
}) {
  const { t } = useTranslation();
  const filterName = getPoiFilterName(poiFeature.name) ?? POI_DISTANCE_FILTER_NAME;
  const poiMeta = getPoiFilterMeta(features, filterName);
  const poiOptions = getPoiFilterFeatureOptions(features, filterName);
  const selectedFeatureName =
    getPoiDistanceFeatureName(poiFeature.name) ??
    getDefaultPoiFilterFeatureName(features, filterName);
  const selectedFeature = selectedFeatureName
    ? features.find((feature) => feature.name === selectedFeatureName)
    : undefined;

  if (!selectedFeature || poiOptions.length === 0 || !selectedFeatureName) return null;

  const isActive = activeFeature === poiFeature.name;
  const isPinned = pinnedFeature === poiFeature.name;
  const hist = selectedFeature.histogram;
  const fixedDistanceScale = usesFixedPoiDistanceScale(selectedFeature);
  const dataMin = hist?.min ?? selectedFeature.min ?? 0;
  const dataMax = hist?.max ?? selectedFeature.max ?? 5;
  const sliderMin = selectedFeature.min ?? dataMin;
  const sliderMax = selectedFeature.max ?? dataMax;
  const rawDisplayValue =
    isActive && dragValue
      ? dragValue
      : (filters[poiFeature.name] as [number, number]) ||
        (fixedDistanceScale ? [sliderMin, sliderMax] : [dataMin, dataMax]);
  const displayValue = fixedDistanceScale
    ? clampPoiFilterRange(rawDisplayValue, selectedFeature)
    : rawDisplayValue;
  const scale = fixedDistanceScale ? undefined : percentileScale;
  const clampMin = fixedDistanceScale ? displayValue[0] <= sliderMin : displayValue[0] <= dataMin;
  const clampMax = fixedDistanceScale ? displayValue[1] >= sliderMax : displayValue[1] >= dataMax;
  const isAtMin = fixedDistanceScale ? false : displayValue[0] === dataMin;
  const isAtMax = fixedDistanceScale ? false : displayValue[1] === dataMax;
  const sliderValue: [number, number] = scale
    ? [
        clampMin ? 0 : Math.round(scale.toPercentile(displayValue[0])),
        clampMax ? 100 : Math.round(scale.toPercentile(displayValue[1])),
      ]
    : [clampMin ? sliderMin : displayValue[0], clampMax ? sliderMax : displayValue[1]];

  const replacePoiFeature = (nextFeatureName: string) => {
    const nextName = replacePoiFilterKeySelection(poiFeature.name, nextFeatureName);
    if (nextName === poiFeature.name) return;

    const nextFeature = features.find((feature) => feature.name === nextFeatureName);
    const nextFixedDistanceScale = usesFixedPoiDistanceScale(nextFeature);
    const nextDataMin = nextFeature?.histogram?.min ?? nextFeature?.min ?? 0;
    const nextDataMax = nextFeature?.histogram?.max ?? nextFeature?.max ?? Math.max(1, dataMax);
    const nextSliderMin = nextFeature?.min ?? nextDataMin;
    const nextSliderMax = nextFeature?.max ?? nextDataMax;
    const nextRange = clampPoiFilterRange(
      [
        clampMin ? (nextFixedDistanceScale ? nextSliderMin : nextDataMin) : displayValue[0],
        clampMax ? (nextFixedDistanceScale ? nextSliderMax : nextDataMax) : displayValue[1],
      ],
      nextFeature
    );

    onFilterChange(nextName, nextRange);
    if (isPinned) onTogglePin(nextName);
  };

  const mobileIconClass = 'w-4 h-4 text-teal-600 dark:text-teal-400 shrink-0';
  const mobileIcon =
    getFeatureIcon(selectedFeature.name, mobileIconClass) ||
    (() => {
      const G = selectedFeature.group ? getGroupIcon(selectedFeature.group) : null;
      return G ? <G className={mobileIconClass} /> : null;
    })();

  return (
    <div
      data-filter-name={filterName}
      className={`space-y-1.5 px-2 py-1.5 rounded ${
        isActive
          ? 'ring-2 ring-teal-400 bg-teal-50 dark:bg-teal-900/30'
          : isPinned
            ? 'ring-2 ring-teal-400 bg-teal-50/50 dark:bg-teal-900/20'
            : ''
      }`}
    >
      <div className="relative z-10 flex items-center justify-between gap-1">
        <FeatureLabel
          feature={poiMeta}
          size="sm"
          className="min-w-0 shrink"
          hideIconOnMobile
          wrap
        />
        <FeatureActions
          feature={selectedFeature}
          actionName={poiFeature.name}
          isPinned={isPinned}
          isPreviewing={isActive}
          onTogglePin={onTogglePin}
          onShowInfo={onShowInfo}
          onRemove={onRemove}
        />
      </div>

      <div>
        <label className="mb-1 block text-[10px] font-medium uppercase text-warm-400 dark:text-warm-500">
          {t('filters.poiType')}
        </label>
        <PoiTypeDropdown
          options={poiOptions}
          value={selectedFeatureName}
          onChange={replacePoiFeature}
        />
      </div>

      <div className="flex items-start gap-1.5 md:block">
        {mobileIcon && <div className="shrink-0 pt-0.5 md:hidden">{mobileIcon}</div>}
        <div className="min-w-0 flex-1">
          <Slider
            min={scale ? 0 : sliderMin}
            max={scale ? 100 : sliderMax}
            step={scale ? 1 : (selectedFeature.step ?? (sliderMax - sliderMin) / 100)}
            value={sliderValue}
            onValueChange={
              scale
                ? ([pMin, pMax]) => {
                    const step = selectedFeature.step ?? 0.1;
                    const snap = (v: number) => Math.round(v / step) * step;
                    onDragChange([
                      pMin <= 0 ? dataMin : snap(scale.toValue(pMin)),
                      pMax >= 100 ? dataMax : snap(scale.toValue(pMax)),
                    ]);
                  }
                : ([min, max]) =>
                    onDragChange([
                      min <= sliderMin ? sliderMin : min,
                      max >= sliderMax ? sliderMax : max,
                    ])
            }
            onPointerDown={() => onDragStart(poiFeature.name, displayValue)}
            onPointerUp={() => onDragEnd()}
          />
          <SliderLabels
            min={scale ? 0 : sliderMin}
            max={scale ? 100 : sliderMax}
            value={sliderValue}
            displayValues={displayValue}
            isAtMin={isAtMin}
            isAtMax={isAtMax}
            raw={selectedFeature.raw}
            feature={selectedFeature}
            showUnit={
              filterName === POI_DISTANCE_FILTER_NAME ||
              filterName === TRANSPORT_DISTANCE_FILTER_NAME
            }
            onValueChange={(v) =>
              onFilterChange(poiFeature.name, clampPoiFilterRange(v, selectedFeature))
            }
          />
          {filterImpact != null && filterImpact > 0 && (
            <p className="-mt-1 ml-2.5 text-[10px] text-warm-400 dark:text-warm-500">
              {t('filters.filtersOut', { value: formatNumber(filterImpact) })}
            </p>
          )}
        </div>
      </div>
    </div>
  );
}
