import React, { useState, useEffect, useRef, useCallback } from 'react';
import { api } from '../../api/client';
import type { GifResult } from '@backspace/shared';
import { useT, type TranslationKey } from '../../i18n';

/**
 * Category shortcuts. The label is translated but the query is not: it is sent
 * to the provider, which indexes in English — a translated query would return
 * nothing.
 */
const CATEGORIES: { key: TranslationKey; query: string }[] = [
  { key: 'gif.category.hello', query: 'hello' },
  { key: 'gif.category.lol', query: 'lol' },
  { key: 'gif.category.love', query: 'love' },
  { key: 'gif.category.birthday', query: 'happy birthday' },
  { key: 'gif.category.dance', query: 'dance' },
  { key: 'gif.category.facepalm', query: 'facepalm' },
];

interface GifPickerProps {
  onGifSelect: (url: string) => void;
  /**
   * Mobile rendering: drop the desktop fixed dimensions and let the picker
   * fill its parent (a bottom sheet that controls width + max-height).
   */
  mobile?: boolean;
}

export function GifPicker({ onGifSelect, mobile = false }: GifPickerProps) {
  const t = useT();
  const [showFavorites, setShowFavorites] = useState(false);
  const [favorites, setFavorites] = useState<GifResult[]>([]);
  const [favoriteIds, setFavoriteIds] = useState<Set<string>>(new Set());
  const [query, setQuery] = useState('');
  const [debouncedQuery, setDebouncedQuery] = useState('');
  const [results, setResults] = useState<GifResult[]>([]);
  const [loading, setLoading] = useState(true);
  const [nextPos, setNextPos] = useState('');
  const [loadingMore, setLoadingMore] = useState(false);
  const scrollRef = useRef<HTMLDivElement>(null);
  const debounceRef = useRef<ReturnType<typeof setTimeout>>();

  // Favourites load once and are kept in memory: the picker is opened and
  // closed constantly, and re-fetching on every open would be visible.
  useEffect(() => {
    let cancelled = false;
    api.gif.favorites()
      .then(({ results }) => {
        if (cancelled) return;
        setFavorites(results);
        setFavoriteIds(new Set(results.map((g) => g.id)));
      })
      .catch(() => { /* favourites are an enhancement; browsing still works */ });
    return () => { cancelled = true; };
  }, []);

  const toggleFavorite = async (gif: GifResult, e: React.MouseEvent) => {
    // The tile behind this button inserts the GIF into the message.
    e.stopPropagation();
    const isFavorite = favoriteIds.has(gif.id);

    // Optimistic: the star must feel instant. Reverted below if the call fails.
    setFavoriteIds((prev) => {
      const next = new Set(prev);
      if (isFavorite) next.delete(gif.id); else next.add(gif.id);
      return next;
    });
    setFavorites((prev) => (isFavorite ? prev.filter((g) => g.id !== gif.id) : [gif, ...prev]));

    try {
      if (isFavorite) await api.gif.removeFavorite(gif.id);
      else await api.gif.addFavorite(gif);
    } catch {
      setFavoriteIds((prev) => {
        const next = new Set(prev);
        if (isFavorite) next.add(gif.id); else next.delete(gif.id);
        return next;
      });
      setFavorites((prev) => (isFavorite ? [gif, ...prev] : prev.filter((g) => g.id !== gif.id)));
    }
  };

  // Debounce search query
  useEffect(() => {
    if (debounceRef.current) clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(() => {
      setDebouncedQuery(query);
    }, 300);
    return () => {
      if (debounceRef.current) clearTimeout(debounceRef.current);
    };
  }, [query]);

  // Fetch results when debounced query changes
  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    setResults([]);
    setNextPos('');

    const fetchGifs = async () => {
      try {
        const data = debouncedQuery.trim()
          ? await api.gif.search(debouncedQuery.trim(), 30)
          : await api.gif.trending(30);
        if (!cancelled) {
          setResults(data.results);
          setNextPos(data.next);
          setLoading(false);
        }
      } catch {
        if (!cancelled) setLoading(false);
      }
    };
    fetchGifs();
    return () => { cancelled = true; };
  }, [debouncedQuery]);

  // Infinite scroll
  const handleScroll = useCallback(() => {
    const el = scrollRef.current;
    // Favourites are a complete local list — nothing to page through.
    if (showFavorites) return;
    if (!el || loadingMore || !nextPos) return;
    if (el.scrollTop + el.clientHeight >= el.scrollHeight - 100) {
      setLoadingMore(true);
      const fetchMore = async () => {
        try {
          const data = debouncedQuery.trim()
            ? await api.gif.search(debouncedQuery.trim(), 30, nextPos)
            : await api.gif.trending(30, nextPos);
          setResults((prev) => [...prev, ...data.results]);
          setNextPos(data.next);
        } finally {
          setLoadingMore(false);
        }
      };
      fetchMore();
    }
  }, [loadingMore, nextPos, debouncedQuery, showFavorites]);

  // Prevent keyboard events from bubbling
  const handleKeyDown = (e: React.KeyboardEvent) => {
    e.stopPropagation();
  };

  // Favourites are a local list; browsing results come from the provider.
  const shown = showFavorites ? favorites : results;

  // Mobile: fill parent (sheet sets width + max-height). Desktop: fixed dims
  // matching the legacy popover footprint.
  const rootClass = mobile
    ? 'flex flex-col flex-1 min-h-0 w-full'
    : 'flex flex-col h-[390px] w-[390px]';

  return (
    <div className={rootClass} onKeyDown={handleKeyDown}>
      {/* Search */}
      <div className="px-3 pt-2 pb-1.5 shrink-0">
        <input
          type="text"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder={t('gif.search')}
          className="input-search w-full"
          // Auto-focus only on desktop. On mobile this would force the OS
          // keyboard up the moment the sheet opens, hiding most of the grid.
          autoFocus={!mobile}
        />
      </div>

      {/* Category shortcuts */}
      <div className="flex gap-1.5 px-3 pb-2 overflow-x-auto no-scrollbar shrink-0">
        <button
          type="button"
          onClick={() => setShowFavorites((v) => !v)}
          className={`px-2.5 py-1 rounded-full text-[12px] font-medium whitespace-nowrap transition-colors flex items-center gap-1 ${
            showFavorites
              ? 'bg-accent-primary text-white'
              : 'bg-surface-elevated text-txt-secondary hover:text-txt-primary'
          }`}
        >
          <svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
            <path d="m12 17.27 6.18 3.73-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
          </svg>
          {t('gif.tab.favorites')}
        </button>
        {CATEGORIES.map((category) => (
          <button
            key={category.query}
            type="button"
            onClick={() => { setShowFavorites(false); setQuery(category.query); }}
            className="px-2.5 py-1 rounded-full text-[12px] font-medium whitespace-nowrap bg-surface-elevated text-txt-secondary hover:text-txt-primary transition-colors"
          >
            {t(category.key)}
          </button>
        ))}
      </div>

      {/* Results grid */}
      <div
        ref={scrollRef}
        className="flex-1 overflow-y-auto scrollbar-thin px-2 pb-1"
        onScroll={handleScroll}
      >
        {loading && !showFavorites ? (
          <div className="grid grid-cols-2 gap-1.5 p-1">
            {Array.from({ length: 6 }).map((_, i) => (
              <div
                key={i}
                className="bg-surface-elevated rounded-lg animate-pulse"
                style={{ height: 100 + Math.random() * 60 }}
              />
            ))}
          </div>
        ) : shown.length === 0 ? (
          <div className="flex items-center justify-center h-full text-txt-tertiary text-sm text-center px-4">
            {showFavorites
              ? t('gif.empty.favorites')
              : debouncedQuery.trim()
                ? t('gif.empty.search')
                : t('gif.empty.trending')}
          </div>
        ) : (
          <div className="columns-2 gap-1.5 p-1">
            {shown.map((gif) => {
              const isFavorite = favoriteIds.has(gif.id);
              return (
                // The star cannot live inside the tile button — a button inside
                // a button is invalid and swallows the click. Siblings instead.
                <div key={gif.id} className="relative group w-full mb-1.5 break-inside-avoid">
                  <button
                    onClick={() => onGifSelect(gif.url)}
                    className="w-full rounded-lg overflow-hidden hover:ring-2 hover:ring-accent-primary transition-all block"
                  >
                    <img
                      src={gif.previewUrl}
                      alt={gif.title}
                      className="w-full object-cover rounded-lg"
                      loading="lazy"
                      style={{
                        aspectRatio: gif.width && gif.height ? `${gif.width}/${gif.height}` : undefined,
                      }}
                    />
                  </button>
                  <button
                    type="button"
                    onClick={(e) => void toggleFavorite(gif, e)}
                    title={isFavorite ? t('gif.favorite.remove') : t('gif.favorite.add')}
                    aria-label={isFavorite ? t('gif.favorite.remove') : t('gif.favorite.add')}
                    className={`absolute top-1.5 right-1.5 w-7 h-7 rounded-full flex items-center justify-center bg-black/55 backdrop-blur-sm transition-opacity ${
                      isFavorite ? 'opacity-100 text-accent-amber' : 'opacity-0 group-hover:opacity-100 focus:opacity-100 text-white'
                    }`}
                  >
                    <svg width="14" height="14" viewBox="0 0 24 24" fill={isFavorite ? 'currentColor' : 'none'} stroke="currentColor" strokeWidth="2">
                      <path d="m12 17.27 6.18 3.73-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
                    </svg>
                  </button>
                </div>
              );
            })}
          </div>
        )}
        {loadingMore && (
          <div className="flex justify-center py-2">
            <div className="w-5 h-5 border-2 border-txt-tertiary border-t-transparent rounded-full animate-spin" />
          </div>
        )}
      </div>

      {/* Attribution */}
      <div className="px-3 py-1 text-[10px] text-txt-tertiary text-right shrink-0">
        Powered by Klipy
      </div>
    </div>
  );
}
