import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Search, X, ChevronUp, ChevronDown, Clock, User, Filter } from 'lucide-react';
import { Button } from './ui';
import { useChatStore, Message } from '../store/chatStore';

export interface SearchFilters {
  sender: 'all' | 'user' | 'assistant';
  timeRange: 'all' | 'today' | 'week' | 'month';
}

export interface SearchResult {
  message: Message;
  matchIndices: Array<{ start: number; end: number }>;
}

interface MessageSearchProps {
  onNavigateToMessage: (messageId: string) => void;
}

const SEARCH_HISTORY_KEY = 'zclaw-search-history';
const MAX_HISTORY_ITEMS = 10;

export function MessageSearch({ onNavigateToMessage }: MessageSearchProps) {
  const { messages } = useChatStore();

  const [isOpen, setIsOpen] = useState(false);
  const [query, setQuery] = useState('');
  const [filters, setFilters] = useState<SearchFilters>({
    sender: 'all',
    timeRange: 'all',
  });
  const [currentMatchIndex, setCurrentMatchIndex] = useState(0);
  const [showFilters, setShowFilters] = useState(false);
  const [searchHistory, setSearchHistory] = useState<string[]>([]);
  const inputRef = useRef<HTMLInputElement>(null);

  // Load search history from localStorage
  useEffect(() => {
    try {
      const saved = localStorage.getItem(SEARCH_HISTORY_KEY);
      if (saved) {
        setSearchHistory(JSON.parse(saved));
      }
    } catch {
      // Ignore parse errors
    }
  }, []);

  // Save search query to history
  const saveToHistory = useCallback((searchQuery: string) => {
    if (!searchQuery.trim()) return;

    setSearchHistory((prev) => {
      const filtered = prev.filter((item) => item !== searchQuery);
      const updated = [searchQuery, ...filtered].slice(0, MAX_HISTORY_ITEMS);
      try {
        localStorage.setItem(SEARCH_HISTORY_KEY, JSON.stringify(updated));
      } catch {
        // Ignore storage errors
      }
      return updated;
    });
  }, []);

  // Filter messages by time range
  const filterByTimeRange = useCallback((message: Message, timeRange: SearchFilters['timeRange']): boolean => {
    if (timeRange === 'all') return true;

    const messageTime = new Date(message.timestamp).getTime();
    const now = Date.now();
    const day = 24 * 60 * 60 * 1000;

    switch (timeRange) {
      case 'today':
        return messageTime >= now - day;
      case 'week':
        return messageTime >= now - 7 * day;
      case 'month':
        return messageTime >= now - 30 * day;
      default:
        return true;
    }
  }, []);

  // Filter messages by sender
  const filterBySender = useCallback((message: Message, sender: SearchFilters['sender']): boolean => {
    if (sender === 'all') return true;
    if (sender === 'user') return message.role === 'user';
    if (sender === 'assistant') return message.role === 'assistant' || message.role === 'tool';
    return true;
  }, []);

  // Search messages and find matches
  const searchResults = useMemo((): SearchResult[] => {
    if (!query.trim()) return [];

    const searchTerms = query.toLowerCase().split(/\s+/).filter(Boolean);
    if (searchTerms.length === 0) return [];

    const results: SearchResult[] = [];

    for (const message of messages) {
      // Apply filters
      if (!filterBySender(message, filters.sender)) continue;
      if (!filterByTimeRange(message, filters.timeRange)) continue;

      const content = message.content.toLowerCase();
      const matchIndices: Array<{ start: number; end: number }> = [];

      // Find all matches
      for (const term of searchTerms) {
        let startIndex = 0;
        while (true) {
          const index = content.indexOf(term, startIndex);
          if (index === -1) break;
          matchIndices.push({ start: index, end: index + term.length });
          startIndex = index + 1;
        }
      }

      if (matchIndices.length > 0) {
        // Sort and merge overlapping matches
        matchIndices.sort((a, b) => a.start - b.start);
        const merged: Array<{ start: number; end: number }> = [];
        for (const match of matchIndices) {
          if (merged.length === 0 || merged[merged.length - 1].end < match.start) {
            merged.push(match);
          } else {
            merged[merged.length - 1].end = Math.max(merged[merged.length - 1].end, match.end);
          }
        }
        results.push({ message, matchIndices: merged });
      }
    }

    return results;
  }, [query, messages, filters, filterBySender, filterByTimeRange]);

  // Navigate to previous match
  const handlePrevious = useCallback(() => {
    if (searchResults.length === 0) return;
    setCurrentMatchIndex((prev) =>
      prev > 0 ? prev - 1 : searchResults.length - 1
    );
    const result = searchResults[currentMatchIndex > 0 ? currentMatchIndex - 1 : searchResults.length - 1];
    onNavigateToMessage(result.message.id);
  }, [searchResults, currentMatchIndex, onNavigateToMessage]);

  // Navigate to next match
  const handleNext = useCallback(() => {
    if (searchResults.length === 0) return;
    setCurrentMatchIndex((prev) =>
      prev < searchResults.length - 1 ? prev + 1 : 0
    );
    const result = searchResults[currentMatchIndex < searchResults.length - 1 ? currentMatchIndex + 1 : 0];
    onNavigateToMessage(result.message.id);
  }, [searchResults, currentMatchIndex, onNavigateToMessage]);

  // Handle keyboard shortcuts
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      // Ctrl+F or Cmd+F to open search
      if ((e.ctrlKey || e.metaKey) && e.key === 'f') {
        e.preventDefault();
        setIsOpen((prev) => !prev);
        setTimeout(() => inputRef.current?.focus(), 100);
      }

      // Escape to close search
      if (e.key === 'Escape' && isOpen) {
        setIsOpen(false);
        setQuery('');
      }

      // Enter to navigate to next match
      if (e.key === 'Enter' && isOpen && searchResults.length > 0) {
        if (e.shiftKey) {
          handlePrevious();
        } else {
          handleNext();
        }
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [isOpen, searchResults.length, handlePrevious, handleNext]);

  // Reset current match index when results change
  useEffect(() => {
    setCurrentMatchIndex(0);
  }, [searchResults.length]);

  // Handle search submit
  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (query.trim()) {
      saveToHistory(query.trim());
      if (searchResults.length > 0) {
        onNavigateToMessage(searchResults[0].message.id);
      }
    }
  };

  // Clear search
  const handleClear = () => {
    setQuery('');
    inputRef.current?.focus();
  };

  // Toggle search panel
  const toggleSearch = () => {
    setIsOpen((prev) => !prev);
    if (!isOpen) {
      setTimeout(() => inputRef.current?.focus(), 100);
    }
  };

  return (
    <>
      {/* Search toggle button */}
      <Button
        variant="ghost"
        size="sm"
        onClick={toggleSearch}
        className={`flex items-center gap-1.5 ${isOpen ? 'text-orange-600 dark:text-orange-400 bg-orange-50 dark:bg-orange-900/20' : 'text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300'}`}
        title="Search messages (Ctrl+F)"
        aria-label="Search messages"
        aria-expanded={isOpen}
      >
        <Search className="w-3.5 h-3.5" />
        <span className="hidden sm:inline">Search</span>
      </Button>

      {/* Search panel */}
      <AnimatePresence>
        {isOpen && (
          <motion.div
            initial={{ opacity: 0, height: 0 }}
            animate={{ opacity: 1, height: 'auto' }}
            exit={{ opacity: 0, height: 0 }}
            transition={{ duration: 0.2 }}
            className="border-b border-gray-100 dark:border-gray-800 bg-gray-50 dark:bg-gray-800/50 overflow-hidden"
          >
            <div className="px-4 py-3">
              <form onSubmit={handleSubmit} className="flex items-center gap-2">
                {/* Search input */}
                <div className="flex-1 relative">
                  <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
                  <input
                    ref={inputRef}
                    type="text"
                    value={query}
                    onChange={(e) => setQuery(e.target.value)}
                    placeholder="Search messages..."
                    className="w-full pl-9 pr-8 py-2 text-sm bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-orange-500 dark:focus:ring-orange-400 focus:border-transparent"
                    aria-label="Search query"
                  />
                  {query && (
                    <button
                      type="button"
                      onClick={handleClear}
                      className="absolute right-2 top-1/2 -translate-y-1/2 p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
                      aria-label="Clear search"
                    >
                      <X className="w-4 h-4" />
                    </button>
                  )}
                </div>

                {/* Filter toggle */}
                <Button
                  type="button"
                  variant={showFilters ? 'secondary' : 'ghost'}
                  size="sm"
                  onClick={() => setShowFilters((prev) => !prev)}
                  className="flex items-center gap-1"
                  aria-label="Toggle filters"
                  aria-expanded={showFilters}
                >
                  <Filter className="w-4 h-4" />
                  <span className="hidden sm:inline">Filters</span>
                </Button>

                {/* Navigation buttons */}
                {searchResults.length > 0 && (
                  <div className="flex items-center gap-1">
                    <span className="text-xs text-gray-500 dark:text-gray-400 px-2">
                      {currentMatchIndex + 1} / {searchResults.length}
                    </span>
                    <Button
                      type="button"
                      variant="ghost"
                      size="sm"
                      onClick={handlePrevious}
                      className="p-1.5"
                      aria-label="Previous match"
                    >
                      <ChevronUp className="w-4 h-4" />
                    </Button>
                    <Button
                      type="button"
                      variant="ghost"
                      size="sm"
                      onClick={handleNext}
                      className="p-1.5"
                      aria-label="Next match"
                    >
                      <ChevronDown className="w-4 h-4" />
                    </Button>
                  </div>
                )}
              </form>

              {/* Filters panel */}
              <AnimatePresence>
                {showFilters && (
                  <motion.div
                    initial={{ opacity: 0, height: 0 }}
                    animate={{ opacity: 1, height: 'auto' }}
                    exit={{ opacity: 0, height: 0 }}
                    className="mt-3 pt-3 border-t border-gray-200 dark:border-gray-700"
                  >
                    <div className="flex flex-wrap gap-4">
                      {/* Sender filter */}
                      <div className="flex items-center gap-2">
                        <label className="text-xs text-gray-500 dark:text-gray-400 flex items-center gap-1">
                          <User className="w-3.5 h-3.5" />
                          Sender:
                        </label>
                        <select
                          value={filters.sender}
                          onChange={(e) => setFilters((prev) => ({ ...prev, sender: e.target.value as SearchFilters['sender'] }))}
                          className="text-xs bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded px-2 py-1 focus:outline-none focus:ring-1 focus:ring-orange-500"
                        >
                          <option value="all">All</option>
                          <option value="user">User</option>
                          <option value="assistant">Assistant</option>
                        </select>
                      </div>

                      {/* Time range filter */}
                      <div className="flex items-center gap-2">
                        <label className="text-xs text-gray-500 dark:text-gray-400 flex items-center gap-1">
                          <Clock className="w-3.5 h-3.5" />
                          Time:
                        </label>
                        <select
                          value={filters.timeRange}
                          onChange={(e) => setFilters((prev) => ({ ...prev, timeRange: e.target.value as SearchFilters['timeRange'] }))}
                          className="text-xs bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded px-2 py-1 focus:outline-none focus:ring-1 focus:ring-orange-500"
                        >
                          <option value="all">All time</option>
                          <option value="today">Today</option>
                          <option value="week">This week</option>
                          <option value="month">This month</option>
                        </select>
                      </div>
                    </div>
                  </motion.div>
                )}
              </AnimatePresence>

              {/* Search history */}
              {!query && searchHistory.length > 0 && (
                <div className="mt-2">
                  <div className="text-xs text-gray-400 dark:text-gray-500 mb-1">Recent searches:</div>
                  <div className="flex flex-wrap gap-1">
                    {searchHistory.slice(0, 5).map((item, index) => (
                      <button
                        key={index}
                        type="button"
                        onClick={() => setQuery(item)}
                        className="text-xs px-2 py-1 bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors"
                      >
                        {item}
                      </button>
                    ))}
                  </div>
                </div>
              )}

              {/* No results message */}
              {query && searchResults.length === 0 && (
                <div className="mt-2 text-xs text-gray-500 dark:text-gray-400 text-center py-2">
                  No messages found matching "{query}"
                </div>
              )}
            </div>
          </motion.div>
        )}
      </AnimatePresence>
    </>
  );
}

// Utility function to highlight search matches in text
export function highlightSearchMatches(
  text: string,
  query: string,
  highlightClassName: string = 'bg-yellow-200 dark:bg-yellow-700/50 rounded px-0.5'
): React.ReactNode[] {
  if (!query.trim()) return [text];

  const searchTerms = query.toLowerCase().split(/\s+/).filter(Boolean);
  if (searchTerms.length === 0) return [text];

  const lowerText = text.toLowerCase();
  const matches: Array<{ start: number; end: number }> = [];

  // Find all matches
  for (const term of searchTerms) {
    let startIndex = 0;
    while (true) {
      const index = lowerText.indexOf(term, startIndex);
      if (index === -1) break;
      matches.push({ start: index, end: index + term.length });
      startIndex = index + 1;
    }
  }

  if (matches.length === 0) return [text];

  // Sort and merge overlapping matches
  matches.sort((a, b) => a.start - b.start);
  const merged: Array<{ start: number; end: number }> = [];
  for (const match of matches) {
    if (merged.length === 0 || merged[merged.length - 1].end < match.start) {
      merged.push({ ...match });
    } else {
      merged[merged.length - 1].end = Math.max(merged[merged.length - 1].end, match.end);
    }
  }

  // Build highlighted result
  const result: React.ReactNode[] = [];
  let lastIndex = 0;

  for (let i = 0; i < merged.length; i++) {
    const match = merged[i];

    // Text before match
    if (match.start > lastIndex) {
      result.push(text.slice(lastIndex, match.start));
    }

    // Highlighted match
    result.push(
      <mark key={i} className={highlightClassName}>
        {text.slice(match.start, match.end)}
      </mark>
    );

    lastIndex = match.end;
  }

  // Remaining text
  if (lastIndex < text.length) {
    result.push(text.slice(lastIndex));
  }

  return result;
}
