import { useState, useRef, useCallback } from 'react';
import type { POICategoryGroup } from '../../types';
import { useClickOutside } from '../../hooks/useClickOutside';
import InfoPopup from '../ui/InfoPopup';
import { SearchInput } from '../ui/SearchInput';
import { InfoIcon, ChevronIcon } from '../ui/icons';
import { IconButton } from '../ui/IconButton';

interface POIPaneProps {
  groups: POICategoryGroup[];
  selectedCategories: Set<string>;
  onCategoriesChange: (categories: Set<string>) => void;
  poiCount: number;
  onNavigateToSource?: (slug: string) => void;
}

export default function POIPane({
  groups,
  selectedCategories,
  onCategoriesChange,
  poiCount,
  onNavigateToSource,
}: POIPaneProps) {
  const [dropdownOpen, setDropdownOpen] = useState(false);
  const [searchTerm, setSearchTerm] = useState('');
  const [collapsedGroups, setCollapsedGroups] = useState<Set<string>>(new Set());
  const [showInfo, setShowInfo] = useState(false);
  const dropdownRef = useRef<HTMLDivElement>(null);

  useClickOutside(dropdownRef, () => setDropdownOpen(false));

  const allCategories = groups.flatMap((g) => g.categories);

  const toggleCategory = (category: string) => {
    const newSet = new Set(selectedCategories);
    if (newSet.has(category)) {
      newSet.delete(category);
    } else {
      newSet.add(category);
    }
    onCategoriesChange(newSet);
  };

  const selectAll = () => {
    onCategoriesChange(new Set(allCategories));
  };

  const selectNone = () => {
    onCategoriesChange(new Set());
  };

  const toggleGroup = useCallback(
    (groupName: string) => {
      const group = groups.find((g) => g.name === groupName);
      if (!group) return;
      const allSelected = group.categories.every((c) => selectedCategories.has(c));
      const newSet = new Set(selectedCategories);
      if (allSelected) {
        group.categories.forEach((c) => newSet.delete(c));
      } else {
        group.categories.forEach((c) => newSet.add(c));
      }
      onCategoriesChange(newSet);
    },
    [groups, selectedCategories, onCategoriesChange]
  );

  const toggleCollapse = (groupName: string) => {
    setCollapsedGroups((prev) => {
      const next = new Set(prev);
      if (next.has(groupName)) {
        next.delete(groupName);
      } else {
        next.add(groupName);
      }
      return next;
    });
  };

  const lowerSearch = searchTerm.toLowerCase();

  const filteredGroups = groups
    .map((group) => {
      if (!searchTerm) return group;
      const matchingCats = group.categories.filter((c) => c.toLowerCase().includes(lowerSearch));
      const groupMatches = group.name.toLowerCase().includes(lowerSearch);
      if (groupMatches) return group;
      if (matchingCats.length === 0) return null;
      return { ...group, categories: matchingCats };
    })
    .filter(Boolean) as POICategoryGroup[];

  const selectedCount = selectedCategories.size;

  return (
    <div className="w-72 p-4 bg-white dark:bg-navy-950 shadow-lg space-y-4 overflow-y-auto max-h-screen">
      <div className="flex items-center gap-2">
        <h2 className="text-xl font-bold dark:text-warm-100">Points of Interest</h2>
        <IconButton onClick={() => setShowInfo(true)} title="Data source info">
          <InfoIcon />
        </IconButton>
      </div>

      {showInfo && (
        <InfoPopup
          title="Points of Interest"
          onClose={() => setShowInfo(false)}
          sourceLink={
            onNavigateToSource
              ? {
                  label: 'View data source',
                  onClick: () => {
                    onNavigateToSource('osm-pois');
                    setShowInfo(false);
                  },
                }
              : undefined
          }
        >
          <p className="text-sm text-warm-700 dark:text-warm-300 mb-4 leading-relaxed">
            Points of interest are sourced from OpenStreetMap via Geofabrik extracts. Categories
            include public transport stops, shops, restaurants, healthcare facilities, leisure
            venues, and more. Data is filtered and mapped to friendly names with exhaustive category
            coverage.
          </p>
        </InfoPopup>
      )}

      <div className="space-y-2" ref={dropdownRef}>
        <button
          onClick={() => setDropdownOpen(!dropdownOpen)}
          className="w-full flex items-center justify-between px-3 py-2 text-sm border border-warm-300 dark:border-navy-700 rounded hover:border-warm-400 bg-white dark:bg-navy-800 dark:text-warm-200"
        >
          <span className="truncate text-left">
            {selectedCount === 0
              ? 'Select categories...'
              : selectedCount === allCategories.length
                ? 'All categories'
                : `${selectedCount} selected`}
          </span>
          <ChevronIcon
            direction={dropdownOpen ? 'up' : 'down'}
            className="w-4 h-4 ml-2 flex-shrink-0"
          />
        </button>

        {dropdownOpen && (
          <div className="border border-warm-300 dark:border-navy-700 rounded shadow-lg bg-white dark:bg-navy-800">
            <div className="px-3 py-2 border-b border-warm-200 dark:border-navy-700">
              <SearchInput
                value={searchTerm}
                onChange={setSearchTerm}
                placeholder="Search categories..."
              />
            </div>
            <div className="max-h-96 overflow-y-auto py-1">
              {filteredGroups.map((group) => {
                const groupSelected = group.categories.filter((c) =>
                  selectedCategories.has(c)
                ).length;
                const allInGroupSelected = groupSelected === group.categories.length;
                const someInGroupSelected = groupSelected > 0 && !allInGroupSelected;
                const isCollapsed = collapsedGroups.has(group.name) && !searchTerm;

                return (
                  <div key={group.name}>
                    <div className="flex items-center gap-1 px-3 py-1.5 bg-warm-50 dark:bg-navy-950 border-y border-warm-100 dark:border-navy-700">
                      <button
                        onClick={() => toggleCollapse(group.name)}
                        className={`p-0.5 text-warm-400 hover:text-warm-600 transition-transform ${isCollapsed ? '' : 'rotate-90'}`}
                      >
                        <ChevronIcon direction="right" className="w-3 h-3" />
                      </button>
                      <label className="flex items-center gap-2 flex-1 cursor-pointer">
                        <input
                          type="checkbox"
                          checked={allInGroupSelected}
                          ref={(el) => {
                            if (el) el.indeterminate = someInGroupSelected;
                          }}
                          onChange={() => toggleGroup(group.name)}
                          className="rounded accent-teal-600"
                        />
                        <span className="text-xs font-semibold text-warm-700 dark:text-warm-300">
                          {group.name}
                        </span>
                      </label>
                      <span className="text-xs text-warm-400">
                        {groupSelected}/{group.categories.length}
                      </span>
                    </div>
                    {!isCollapsed &&
                      group.categories.map((category) => (
                        <label
                          key={category}
                          className="flex items-center gap-2 px-3 pl-8 py-1.5 hover:bg-warm-50 dark:hover:bg-navy-700 cursor-pointer dark:text-warm-300"
                        >
                          <input
                            type="checkbox"
                            checked={selectedCategories.has(category)}
                            onChange={() => toggleCategory(category)}
                            className="rounded accent-teal-600"
                          />
                          <span className="text-sm flex-1">{category}</span>
                        </label>
                      ))}
                  </div>
                );
              })}
            </div>
          </div>
        )}
      </div>

      {selectedCount > 0 && (
        <div className="p-3 bg-teal-50 dark:bg-teal-900/30 rounded text-sm">
          <div className="font-medium text-teal-900 dark:text-teal-300">
            {poiCount.toLocaleString()} POI{poiCount !== 1 ? 's' : ''} visible
          </div>
          <div className="text-xs text-teal-700 dark:text-teal-400 mt-1">
            {selectedCount} categor{selectedCount !== 1 ? 'ies' : 'y'} selected
          </div>
        </div>
      )}

      <div className="p-3 bg-warm-100 dark:bg-navy-800 rounded text-xs text-warm-600 dark:text-warm-400">
        <p>Select categories to display POIs on the map.</p>
        <p className="mt-2">Zoom in for better visibility of individual locations.</p>
      </div>
    </div>
  );
}
