import { useTranslation } from 'react-i18next';
import { ts } from '../../../i18n/server';
import { Slider } from '../../ui/Slider';
import { ChevronIcon } from '../../ui/icons';
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 {
  SPECIFIC_CRIMES_FILTER_NAME,
  SPECIFIC_CRIME_FEATURE_NAMES,
  clampSpecificCrimeRange,
  getDefaultSpecificCrimeFeatureName,
  getSpecificCrimeFeatureName,
  getSpecificCrimeFilterMeta,
  replaceSpecificCrimeFilterKeySelection,
} from '../../../lib/crime-filter';
import { SliderLabels } from './SliderLabels';

export function SpecificCrimeFilterCard({
  features,
  crimeFeature,
  filters,
  activeFeature,
  dragValue,
  pinnedFeature,
  filterImpact,
  percentileScale,
  onFilterChange,
  onDragStart,
  onDragChange,
  onDragEnd,
  onTogglePin,
  onShowInfo,
  onRemove,
}: {
  features: FeatureMeta[];
  crimeFeature: 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 specificCrimeMeta = getSpecificCrimeFilterMeta(features);
  const crimeOptions = SPECIFIC_CRIME_FEATURE_NAMES.map((name) =>
    features.find((feature) => feature.name === name)
  ).filter((feature): feature is FeatureMeta => Boolean(feature));
  const selectedFeatureName =
    getSpecificCrimeFeatureName(crimeFeature.name) ?? getDefaultSpecificCrimeFeatureName(features);
  const selectedFeature = selectedFeatureName
    ? features.find((feature) => feature.name === selectedFeatureName)
    : undefined;

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

  const isActive = activeFeature === crimeFeature.name;
  const isPinned = pinnedFeature === crimeFeature.name;
  const hist = selectedFeature.histogram;
  const dataMin = hist?.min ?? selectedFeature.min ?? 0;
  const dataMax = hist?.max ?? selectedFeature.max ?? 100;
  const displayValue =
    isActive && dragValue
      ? dragValue
      : (filters[crimeFeature.name] as [number, number]) || [dataMin, dataMax];
  const scale = percentileScale;
  const clampMin = displayValue[0] <= dataMin;
  const clampMax = displayValue[1] >= dataMax;
  const isAtMin = displayValue[0] === dataMin;
  const isAtMax = 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 ? (selectedFeature.min ?? dataMin) : displayValue[0],
        clampMax ? (selectedFeature.max ?? dataMax) : displayValue[1],
      ];

  const replaceCrimeFeature = (nextFeatureName: string) => {
    const nextName = replaceSpecificCrimeFilterKeySelection(crimeFeature.name, nextFeatureName);
    if (nextName === crimeFeature.name) return;

    const nextFeature = features.find((feature) => feature.name === nextFeatureName);
    const nextDataMin = nextFeature?.histogram?.min ?? nextFeature?.min ?? 0;
    const nextDataMax = nextFeature?.histogram?.max ?? nextFeature?.max ?? Math.max(1, dataMax);
    const nextRange = clampSpecificCrimeRange(
      [
        displayValue[0] <= dataMin ? nextDataMin : displayValue[0],
        displayValue[1] >= dataMax ? 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={SPECIFIC_CRIMES_FILTER_NAME}
      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={specificCrimeMeta}
          size="sm"
          className="min-w-0 shrink"
          hideIconOnMobile
          wrap
        />
        <FeatureActions
          feature={selectedFeature}
          actionName={crimeFeature.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.crimeType')}
        </label>
        <div className="relative">
          <select
            value={selectedFeatureName}
            onChange={(e) => replaceCrimeFeature(e.target.value)}
            className="w-full appearance-none rounded-md border border-warm-200 bg-warm-50 px-2 py-1.5 pr-8 text-sm font-medium text-navy-950 shadow-inner outline-none transition-colors hover:bg-white focus:border-teal-400 focus:ring-2 focus:ring-teal-200 dark:border-warm-700 dark:bg-navy-900 dark:text-warm-100 dark:hover:bg-navy-800 dark:focus:ring-teal-900/50"
          >
            {crimeOptions.map((option) => (
              <option key={option.name} value={option.name}>
                {ts(option.name)}
              </option>
            ))}
          </select>
          <ChevronIcon
            direction="down"
            className="pointer-events-none absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 text-warm-400 dark:text-warm-500"
          />
        </div>
      </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 : (selectedFeature.min ?? dataMin)}
            max={scale ? 100 : (selectedFeature.max ?? dataMax)}
            step={
              scale
                ? 1
                : (selectedFeature.step ??
                  ((selectedFeature.max ?? dataMax) - (selectedFeature.min ?? dataMin)) / 100)
            }
            value={sliderValue}
            onValueChange={
              scale
                ? ([pMin, pMax]) => {
                    const step = selectedFeature.step ?? 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 <= (selectedFeature.min ?? dataMin) ? dataMin : min,
                      max >= (selectedFeature.max ?? dataMax) ? dataMax : max,
                    ])
            }
            onPointerDown={() => onDragStart(crimeFeature.name, displayValue)}
            onPointerUp={() => onDragEnd()}
          />
          <SliderLabels
            min={scale ? 0 : (selectedFeature.min ?? dataMin)}
            max={scale ? 100 : (selectedFeature.max ?? dataMax)}
            value={sliderValue}
            displayValues={displayValue}
            isAtMin={isAtMin}
            isAtMax={isAtMax}
            raw={selectedFeature.raw}
            feature={selectedFeature}
            onValueChange={(v) =>
              onFilterChange(crimeFeature.name, clampSpecificCrimeRange(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>
  );
}
