import { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
  FURNITURE_DEFS,
  FURNITURE_CATEGORIES,
  type FurnitureDef,
  type FurnitureCategory,
} from '../symbols/furniture';
import styles from './item-picker.module.css';

interface FurniturePaletteProps {
  readonly selectedIndex: number | null;
  readonly onSelect: (index: number) => void;
}

interface IndexedDef {
  readonly def: FurnitureDef;
  readonly index: number;
}

interface CategoryGroup {
  readonly category: FurnitureCategory;
  readonly items: readonly IndexedDef[];
}

/**
 * Display metadata for each furniture category. The icon is purely visual
 * (the chip + section header use it). i18n keys live in `furnitureCategory.*`.
 */
const CATEGORY_META: Record<FurnitureCategory, { icon: string; key: string }> = {
  sleeping: { icon: '\u{1F6CF}', key: 'furnitureCategory.sleeping' },
  seating: { icon: '\u{1FA91}', key: 'furnitureCategory.seating' },
  tables: { icon: '\u{1F37D}', key: 'furnitureCategory.tables' },
  storage: { icon: '\u{1F4DA}', key: 'furnitureCategory.storage' },
  electronics: { icon: '\u{1F4FA}', key: 'furnitureCategory.electronics' },
  climate: { icon: '\u{1F525}', key: 'furnitureCategory.climate' },
  decor: { icon: '\u{1F5BC}', key: 'furnitureCategory.decor' },
  pets: { icon: '\u{1F431}', key: 'furnitureCategory.pets' },
};

type CategoryFilter = FurnitureCategory | 'all';

export function FurniturePalette({ selectedIndex, onSelect }: FurniturePaletteProps) {
  const { t, i18n } = useTranslation();
  const [search, setSearch] = useState('');
  const [activeCategory, setActiveCategory] = useState<CategoryFilter>('all');

  const handleSelect = useCallback(
    (index: number) => {
      onSelect(index);
    },
    [onSelect],
  );

  // Pre-compute the indexed list once. Indexes here MUST match positions in
  // FURNITURE_DEFS so the picker continues to satisfy the EditorCanvas
  // contract: `FURNITURE_DEFS[selectedFurnitureIndex]`.
  const allIndexed = useMemo<readonly IndexedDef[]>(
    () => FURNITURE_DEFS.map((def, index) => ({ def, index })),
    [],
  );

  // Filter by search term and active category, then group by category for
  // display. Empty search + "all" reproduces the original ordering.
  const visibleGroups = useMemo<readonly CategoryGroup[]>(() => {
    const trimmed = search.trim().toLowerCase();
    const matches = (item: IndexedDef): boolean => {
      if (activeCategory !== 'all' && item.def.category !== activeCategory) return false;
      if (!trimmed) return true;
      // Allow matching the type code (e.g. "tv", "radiator") and label.
      return (
        item.def.label.toLowerCase().includes(trimmed) ||
        item.def.type.toLowerCase().includes(trimmed)
      );
    };

    const buckets = new Map<FurnitureCategory, IndexedDef[]>();
    for (const item of allIndexed) {
      if (!matches(item)) continue;
      const list = buckets.get(item.def.category) ?? [];
      list.push(item);
      buckets.set(item.def.category, list);
    }

    // Preserve canonical category order from FURNITURE_CATEGORIES.
    return FURNITURE_CATEGORIES.flatMap((category) => {
      const items = buckets.get(category);
      return items && items.length > 0 ? [{ category, items }] : [];
    });
  }, [allIndexed, search, activeCategory]);

  const categoryLabel = (category: FurnitureCategory): string => {
    const meta = CATEGORY_META[category];
    return i18n.exists(meta.key) ? t(meta.key) : category;
  };

  const totalVisible = visibleGroups.reduce((acc, g) => acc + g.items.length, 0);

  return (
    <div className={styles.palette}>
      <div className={styles.header}>{t('furniture.title')}</div>

      <div className={styles.searchRow}>
        <span className={styles.searchIcon} aria-hidden>
          {'\u{1F50D}'}
        </span>
        <input
          className={styles.searchInput}
          type="text"
          value={search}
          onChange={(e) => setSearch(e.target.value)}
          placeholder={
            i18n.exists('furniture.searchPlaceholder')
              ? t('furniture.searchPlaceholder')
              : 'Search furniture…'
          }
          aria-label={
            i18n.exists('furniture.searchPlaceholder')
              ? t('furniture.searchPlaceholder')
              : 'Search furniture'
          }
        />
        {search && (
          <button
            type="button"
            className={styles.searchClear}
            onClick={() => setSearch('')}
            aria-label="Clear search"
          >
            {'\u00D7'}
          </button>
        )}
      </div>

      <div className={styles.categoryChips}>
        <CategoryChip
          label={i18n.exists('furnitureCategory.all') ? t('furnitureCategory.all') : 'All'}
          active={activeCategory === 'all'}
          onClick={() => setActiveCategory('all')}
        />
        {FURNITURE_CATEGORIES.map((category) => (
          <CategoryChip
            key={category}
            label={`${CATEGORY_META[category].icon} ${categoryLabel(category)}`}
            active={activeCategory === category}
            onClick={() => setActiveCategory(category)}
          />
        ))}
      </div>

      <div className={styles.scrollArea}>
        {totalVisible === 0 ? (
          <div className={styles.empty}>
            {i18n.exists('furniture.noResults') ? t('furniture.noResults') : 'No matches'}
          </div>
        ) : (
          visibleGroups.map((group) => (
            <div key={group.category} className={styles.section}>
              <div className={styles.sectionHeader}>
                <span aria-hidden>{CATEGORY_META[group.category].icon}</span>
                <span>{categoryLabel(group.category)}</span>
                <span className={styles.sectionCount}>{group.items.length}</span>
              </div>
              <div className={styles.itemGrid}>
                {group.items.map(({ def, index }) => (
                  <FurnitureItemBtn
                    key={index}
                    def={def}
                    index={index}
                    isActive={selectedIndex === index}
                    onSelect={handleSelect}
                  />
                ))}
              </div>
            </div>
          ))
        )}
      </div>
    </div>
  );
}

interface CategoryChipProps {
  readonly label: string;
  readonly active: boolean;
  readonly onClick: () => void;
}

function CategoryChip({ label, active, onClick }: CategoryChipProps) {
  return (
    <button
      type="button"
      className={[styles.categoryChip, active ? styles.categoryChipActive : ''].join(' ')}
      onClick={onClick}
    >
      {label}
    </button>
  );
}

interface FurnitureItemBtnProps {
  readonly def: FurnitureDef;
  readonly index: number;
  readonly isActive: boolean;
  readonly onSelect: (index: number) => void;
}

function FurnitureItemBtn({ def, index, isActive, onSelect }: FurnitureItemBtnProps) {
  return (
    <button
      type="button"
      className={[styles.itemBtn, isActive ? styles.itemBtnActive : ''].join(' ')}
      onClick={() => onSelect(index)}
      title={`${def.label} (${def.width}m × ${def.depth}m × ${def.height}m)`}
    >
      <span className={styles.itemIcon}>{def.icon}</span>
      <span className={styles.itemLabel}>{def.label}</span>
      <span className={styles.itemDims}>
        {def.width}×{def.depth}m
      </span>
    </button>
  );
}
