import { memo, useState, useRef, useCallback, useMemo, useEffect } from 'react';
import { Slider } from './ui/slider';
import { Label } from './ui/label';
import type { FeatureMeta, FeatureFilters } from '../types';
import { formatFilterValue } from '../lib/format';
import InfoPopup from './InfoPopup';

interface FiltersProps {
  features: FeatureMeta[];
  filters: FeatureFilters;
  activeFeature: string | null;
  dragValue: [number, number] | null;
  enabledFeatures: Set<string>;
  onAddFilter: (name: string) => void;
  onRemoveFilter: (name: string) => void;
  onFilterChange: (name: string, value: [number, number] | string[]) => void;
  onDragStart: (name: string) => void;
  onDragChange: (value: [number, number]) => void;
  onDragEnd: () => void;
  zoom: number;
  pinnedFeature: string | null;
  onTogglePin: (name: string) => void;
  onCancelPin: () => void;
  onNavigateToSource?: (slug: string, featureName: string) => void;
  openInfoFeature?: string | null;
  onClearOpenInfoFeature?: () => void;
}

function EyeIcon({ filled, className }: { filled: boolean; className?: string }) {
  return (
    <svg
      className={className || 'w-3.5 h-3.5'}
      viewBox="0 0 24 24"
      fill={filled ? 'currentColor' : 'none'}
      stroke="currentColor"
      strokeWidth={2}
    >
      <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
      <circle cx="12" cy="12" r="3" />
    </svg>
  );
}

function FeatureBrowser({
  availableFeatures,
  allFeatures,
  pinnedFeature,
  onAddFilter,
  onTogglePin,
  onNavigateToSource,
  openInfoFeature,
  onClearOpenInfoFeature,
}: {
  availableFeatures: FeatureMeta[];
  allFeatures: FeatureMeta[];
  pinnedFeature: string | null;
  onAddFilter: (name: string) => void;
  onTogglePin: (name: string) => void;
  onNavigateToSource?: (slug: string, featureName: string) => void;
  openInfoFeature?: string | null;
  onClearOpenInfoFeature?: () => void;
}) {
  const [search, setSearch] = useState('');
  const [infoFeature, setInfoFeature] = useState<FeatureMeta | null>(null);

  useEffect(() => {
    if (openInfoFeature) {
      const feat = allFeatures.find((f) => f.name === openInfoFeature);
      if (feat) setInfoFeature(feat);
      onClearOpenInfoFeature?.();
    }
  }, [openInfoFeature, allFeatures, onClearOpenInfoFeature]);

  const filtered = useMemo(() => {
    if (!search) return availableFeatures;
    const lower = search.toLowerCase();
    return availableFeatures.filter((f) => f.name.toLowerCase().includes(lower));
  }, [availableFeatures, search]);

  const grouped = useMemo(() => {
    const groups: { name: string; features: FeatureMeta[] }[] = [];
    const seen = new Map<string, FeatureMeta[]>();
    for (const f of filtered) {
      const g = f.group || 'Other';
      let arr = seen.get(g);
      if (!arr) {
        arr = [];
        seen.set(g, arr);
        groups.push({ name: g, features: arr });
      }
      arr.push(f);
    }
    return groups;
  }, [filtered]);

  return (
    <>
      <div className="p-2 border-b border-warm-200 dark:border-navy-700">
        <input
          type="text"
          placeholder="Search features..."
          value={search}
          onChange={(e) => setSearch(e.target.value)}
          className="w-full px-2 py-1 text-sm border rounded bg-white dark:bg-navy-800 dark:text-warm-200 border-warm-200 dark:border-navy-700 placeholder-warm-400 dark:placeholder-warm-500 focus:outline-none focus:ring-1 focus:ring-teal-400"
        />
      </div>
      <div className="flex-1 overflow-y-auto">
        {grouped.map((group) => (
          <div key={group.name}>
            <div className="px-3 py-1.5 text-xs font-bold text-warm-500 bg-warm-50 dark:bg-navy-950 dark:text-warm-400 sticky top-0">
              {group.name}
            </div>
            {group.features.map((f) => {
              const isPinned = pinnedFeature === f.name;
              return (
                <div
                  key={f.name}
                  className="flex items-start justify-between px-3 py-1.5 hover:bg-teal-50 dark:hover:bg-teal-900/30 dark:text-warm-300"
                >
                  <div className="min-w-0 mr-2">
                    <span className="text-sm truncate block">{f.name}</span>
                    {f.description && (
                      <span className="text-xs text-warm-400 dark:text-warm-500 truncate block">
                        {f.description}
                      </span>
                    )}
                  </div>
                  <div className="flex items-center gap-1 shrink-0 mt-0.5">
                    {f.detail && (
                      <button
                        onClick={() => setInfoFeature(f)}
                        className="text-warm-400 hover:text-warm-700 dark:hover:text-warm-300 p-0.5 rounded"
                        title="Feature info"
                      >
                        <svg
                          className="w-3.5 h-3.5"
                          viewBox="0 0 24 24"
                          fill="none"
                          stroke="currentColor"
                          strokeWidth={2}
                        >
                          <circle cx="12" cy="12" r="10" />
                          <path strokeLinecap="round" d="M12 16v-4m0-4h.01" />
                        </svg>
                      </button>
                    )}
                    <button
                      onClick={() => onTogglePin(f.name)}
                      className={`p-0.5 rounded ${isPinned ? 'text-teal-600 dark:text-teal-400' : 'text-warm-400 hover:text-warm-700 dark:hover:text-warm-300'}`}
                      title={isPinned ? 'Unpin color view' : 'Color map by this feature'}
                    >
                      <EyeIcon filled={isPinned} />
                    </button>
                    <button
                      onClick={() => onAddFilter(f.name)}
                      className="text-warm-400 hover:text-warm-700 dark:hover:text-warm-300 p-0.5 rounded"
                      title="Add filter"
                    >
                      <svg
                        className="w-3.5 h-3.5"
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        strokeWidth={2}
                      >
                        <path strokeLinecap="round" strokeLinejoin="round" d="M12 5v14m-7-7h14" />
                      </svg>
                    </button>
                  </div>
                </div>
              );
            })}
          </div>
        ))}
        {grouped.length === 0 && (
          <div className="px-3 py-4 text-sm text-warm-400 dark:text-warm-500 text-center">
            {search ? 'No matching features' : 'All features are active'}
          </div>
        )}
      </div>
      {infoFeature && (
        <InfoPopup
          title={infoFeature.name}
          onClose={() => setInfoFeature(null)}
          sourceLink={
            infoFeature.source && onNavigateToSource
              ? {
                  label: 'View data source',
                  onClick: () => {
                    onNavigateToSource(infoFeature.source!, infoFeature.name);
                    setInfoFeature(null);
                  },
                }
              : undefined
          }
        >
          {infoFeature.description && (
            <p className="text-xs text-warm-500 dark:text-warm-400 mb-2">
              {infoFeature.description}
            </p>
          )}
          {infoFeature.detail && (
            <p className="text-sm text-warm-700 dark:text-warm-300 mb-4 leading-relaxed">
              {infoFeature.detail}
            </p>
          )}
        </InfoPopup>
      )}
    </>
  );
}

export default memo(function Filters({
  features,
  filters,
  activeFeature,
  dragValue,
  enabledFeatures,
  onAddFilter,
  onRemoveFilter,
  onFilterChange,
  onDragStart,
  onDragChange,
  onDragEnd,
  zoom,
  pinnedFeature,
  onTogglePin,
  onCancelPin: _onCancelPin,
  onNavigateToSource,
  openInfoFeature,
  onClearOpenInfoFeature,
}: FiltersProps) {
  const availableFeatures = features.filter((f) => !enabledFeatures.has(f.name));
  const enabledFeatureList = features.filter((f) => enabledFeatures.has(f.name));

  const containerRef = useRef<HTMLDivElement>(null);
  const [splitFraction, setSplitFraction] = useState(0.65);
  const draggingRef = useRef(false);

  const handleSeparatorPointerDown = useCallback((e: React.PointerEvent) => {
    e.preventDefault();
    (e.target as HTMLElement).setPointerCapture(e.pointerId);
    draggingRef.current = true;
  }, []);

  const handleSeparatorPointerMove = useCallback((e: React.PointerEvent) => {
    if (!draggingRef.current || !containerRef.current) return;
    const rect = containerRef.current.getBoundingClientRect();
    const y = e.clientY - rect.top;
    const fraction = Math.min(0.8, Math.max(0.15, y / rect.height));
    setSplitFraction(fraction);
  }, []);

  const handleSeparatorPointerUp = useCallback(() => {
    draggingRef.current = false;
  }, []);

  return (
    <div
      ref={containerRef}
      className="w-80 flex flex-col bg-white dark:bg-navy-950 shadow-lg overflow-hidden"
    >
      <div className="min-h-0 flex flex-col" style={{ height: `${splitFraction * 100}%` }}>
        <div className="shrink-0 flex items-center justify-between px-3 py-2 border-b border-warm-200 dark:border-navy-700">
          <div className="flex items-center gap-2">
            <span className="text-sm font-semibold text-navy-950 dark:text-warm-100">
              Active Filters
            </span>
            {enabledFeatureList.length > 0 && (
              <span className="text-xs font-medium px-1.5 py-0.5 rounded-full bg-teal-50 dark:bg-teal-900/30 text-teal-600 dark:text-teal-400">
                {enabledFeatureList.length}
              </span>
            )}
          </div>
          <span className="text-xs text-warm-500 dark:text-warm-400">Zoom {zoom.toFixed(1)}</span>
        </div>

        <div className="flex-1 overflow-y-auto p-3 space-y-3">
          {enabledFeatureList.length === 0 && (
            <div className="flex flex-col items-center justify-center py-8 text-center">
              <svg
                className="w-8 h-8 text-warm-300 dark:text-warm-600 mb-2"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                strokeWidth={1.5}
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  d="M12 3c2.755 0 5.455.232 8.083.678.533.09.917.556.917 1.096v1.044a2.25 2.25 0 01-.659 1.591l-5.432 5.432a2.25 2.25 0 00-.659 1.591v2.927a2.25 2.25 0 01-1.244 2.013L9.75 21v-6.568a2.25 2.25 0 00-.659-1.591L3.659 7.409A2.25 2.25 0 013 5.818V4.774c0-.54.384-1.006.917-1.096A48.32 48.32 0 0112 3z"
                />
              </svg>
              <span className="text-sm font-medium text-warm-400 dark:text-warm-500">
                No active filters
              </span>
              <span className="text-xs text-warm-400 dark:text-warm-500 mt-1">
                Browse features below and click + to add a filter
              </span>
            </div>
          )}

          {enabledFeatureList.map((feature) => {
            if (feature.type === 'enum') {
              const selectedValues = (filters[feature.name] as string[]) || [];
              const allValues = feature.values || [];
              return (
                <div
                  key={feature.name}
                  className={`space-y-1 p-3 rounded ${pinnedFeature === feature.name ? 'ring-2 ring-teal-400 bg-teal-50/50 dark:bg-teal-900/20' : ''}`}
                >
                  <div className="flex items-center justify-between">
                    <Label>{feature.name}</Label>
                    <div className="flex items-center gap-0.5">
                      <button
                        onClick={() => onTogglePin(feature.name)}
                        className={`p-0.5 rounded ${pinnedFeature === feature.name ? 'text-teal-600 dark:text-teal-400' : 'text-warm-400 hover:text-warm-700 dark:hover:text-warm-300'}`}
                        title={
                          pinnedFeature === feature.name
                            ? 'Unpin color view'
                            : 'Color map by this feature'
                        }
                      >
                        <EyeIcon filled={pinnedFeature === feature.name} />
                      </button>
                      <button
                        onClick={() => onRemoveFilter(feature.name)}
                        className="text-warm-400 hover:text-warm-700 dark:hover:text-warm-300 text-sm px-1"
                        title="Remove filter"
                      >
                        x
                      </button>
                    </div>
                  </div>
                  <div className="flex gap-2 text-sm mb-1">
                    <button
                      className="text-teal-600 dark:text-teal-400 hover:underline"
                      onClick={() => onFilterChange(feature.name, [...allValues])}
                    >
                      All
                    </button>
                    <button
                      className="text-teal-600 dark:text-teal-400 hover:underline"
                      onClick={() => onFilterChange(feature.name, [])}
                    >
                      None
                    </button>
                  </div>
                  <div className="space-y-0.5 max-h-40 overflow-y-auto">
                    {allValues.map((val) => (
                      <label
                        key={val}
                        className="flex items-center gap-1.5 text-sm cursor-pointer dark:text-warm-300"
                      >
                        <input
                          type="checkbox"
                          checked={selectedValues.includes(val)}
                          onChange={() => {
                            const next = selectedValues.includes(val)
                              ? selectedValues.filter((v) => v !== val)
                              : [...selectedValues, val];
                            onFilterChange(feature.name, next);
                          }}
                          className="rounded accent-teal-600"
                        />
                        {val}
                      </label>
                    ))}
                  </div>
                </div>
              );
            }

            const isActive = activeFeature === feature.name;
            const isPinned = pinnedFeature === feature.name;
            const displayValue =
              isActive && dragValue
                ? dragValue
                : (filters[feature.name] as [number, number]) || [feature.min!, feature.max!];
            const step = feature.step ?? (feature.max! - feature.min!) / 100;

            return (
              <div
                key={feature.name}
                className={`space-y-1 p-3 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="flex items-center justify-between">
                  <Label>
                    {feature.name}: {formatFilterValue(displayValue[0])} -{' '}
                    {formatFilterValue(displayValue[1])}
                  </Label>
                  <div className="flex items-center gap-0.5">
                    <button
                      onClick={() => onTogglePin(feature.name)}
                      className={`p-0.5 rounded ${isPinned ? 'text-teal-600 dark:text-teal-400' : 'text-warm-400 hover:text-warm-700 dark:hover:text-warm-300'}`}
                      title={isPinned ? 'Unpin color view' : 'Color map by this feature'}
                    >
                      <EyeIcon filled={isPinned} />
                    </button>
                    <button
                      onClick={() => onRemoveFilter(feature.name)}
                      className="text-warm-400 hover:text-warm-700 dark:hover:text-warm-300 text-sm px-1"
                      title="Remove filter"
                    >
                      x
                    </button>
                  </div>
                </div>
                <Slider
                  min={feature.min!}
                  max={feature.max!}
                  step={step}
                  value={[displayValue[0], displayValue[1]]}
                  onValueChange={([min, max]) => onDragChange([min, max])}
                  onPointerDown={() => onDragStart(feature.name)}
                  onPointerUp={() => onDragEnd()}
                />
              </div>
            );
          })}
        </div>
      </div>

      <div
        className="shrink-0 h-1.5 cursor-row-resize flex items-center justify-center bg-warm-100 dark:bg-navy-800 hover:bg-warm-200 dark:hover:bg-navy-700 border-y border-warm-200 dark:border-navy-700"
        onPointerDown={handleSeparatorPointerDown}
        onPointerMove={handleSeparatorPointerMove}
        onPointerUp={handleSeparatorPointerUp}
      >
        <div className="w-8 h-0.5 rounded bg-warm-300 dark:bg-navy-600" />
      </div>

      <div className="min-h-0 flex-1 flex flex-col">
        <div className="shrink-0 px-3 py-2 border-b border-warm-200 dark:border-navy-700">
          <span className="text-sm font-semibold text-navy-950 dark:text-warm-100">Add Filter</span>
        </div>
        <div className="min-h-0 flex-1 flex flex-col">
          <FeatureBrowser
            availableFeatures={availableFeatures}
            allFeatures={features}
            pinnedFeature={pinnedFeature}
            onAddFilter={onAddFilter}
            onTogglePin={onTogglePin}
            onNavigateToSource={onNavigateToSource}
            openInfoFeature={openInfoFeature}
            onClearOpenInfoFeature={onClearOpenInfoFeature}
          />
        </div>
      </div>
    </div>
  );
});
