import React, {
  createContext,
  useContext,
  useState,
  useCallback,
  useMemo,
  useEffect,
} from "react";
import { normalizeTags } from "../utils/tagFilters";
import { useUrlState } from "../hooks/useUrlState";
import {
  CATEGORIZATION_TAGS,
  isUncategorized,
  filterLeaderboards as filterLeaderboardsUtil,
  generateSections,
} from "../utils/filterUtils";

const LeaderboardContext = createContext();

// Helper pour déterminer si un leaderboard est non catégorisé
const isUncategorizedBoard = isUncategorized;

export const LeaderboardProvider = ({ children }) => {
  const { params, updateParams } = useUrlState();

  const [leaderboards, setLeaderboards] = useState([]);
  const [searchQuery, setSearchQuery] = useState(params.search || "");
  const [arenaOnly, setArenaOnly] = useState(params.arena === "true");
  const [selectedCategories, setSelectedCategories] = useState(
    new Set(params.categories || [])
  );
  const [selectedLanguage, setSelectedLanguage] = useState(
    params.language ? new Set(params.language.split(",")) : new Set()
  );
  const [expandedSections, setExpandedSections] = useState(
    new Set(params.categories || [])
  );
  const [isLanguageExpanded, setIsLanguageExpanded] = useState(
    params.languageExpanded === "true"
  );

  useEffect(() => {
    updateParams({
      categories: Array.from(selectedCategories),
      search: searchQuery,
      arena: arenaOnly ? "true" : null,
      language:
        selectedLanguage.size > 0
          ? Array.from(selectedLanguage).join(",")
          : null,
      languageExpanded: isLanguageExpanded ? "true" : null,
    });
  }, [
    selectedCategories,
    searchQuery,
    arenaOnly,
    selectedLanguage,
    isLanguageExpanded,
    updateParams,
  ]);

  useEffect(() => {
    if (leaderboards.length > 0) {
      const uncategorizedLeaderboards = leaderboards.filter(
        (board) =>
          board.approval_status === "approved" && isUncategorizedBoard(board)
      );
    }
  }, [leaderboards]);

  const handleCategorySelection = useCallback((categoryId) => {
    setSelectedCategories((prev) => {
      const newCategories = new Set(prev);
      if (newCategories.has(categoryId)) {
        newCategories.delete(categoryId);
        setExpandedSections((prev) => {
          const newExpanded = new Set(prev);
          newExpanded.delete(categoryId);
          return newExpanded;
        });
      } else {
        newCategories.add(categoryId);
        // Si on sélectionne, on déploie la section
        setExpandedSections((prev) => {
          const newExpanded = new Set(prev);
          newExpanded.add(categoryId);
          return newExpanded;
        });
      }
      return newCategories;
    });

    // On réinitialise la langue sélectionnée seulement si on désélectionne "language"
    if (categoryId === "language") {
      setSelectedLanguage(new Set());
    }
  }, []);

  // Wrapper pour la sélection de langue
  const handleLanguageSelection = useCallback((language) => {
    setSelectedLanguage((prev) => {
      const newSet = new Set(prev);
      if (newSet.has(language)) {
        newSet.delete(language);
      } else {
        newSet.add(language);
      }
      return newSet;
    });
  }, []);

  // Filter leaderboards based on search query and arena toggle, ignoring category selection
  const filterLeaderboardsForCount = useCallback(
    (boards) => {
      return filterLeaderboardsUtil({
        boards,
        searchQuery,
        arenaOnly,
      });
    },
    [searchQuery, arenaOnly]
  );

  // Filter leaderboards based on all criteria including categories and language selection
  const filterLeaderboards = useCallback(
    (boards) => {
      return filterLeaderboardsUtil({
        boards,
        searchQuery,
        arenaOnly,
        selectedCategories,
        selectedLanguage,
      });
    },
    [searchQuery, arenaOnly, selectedCategories, selectedLanguage]
  );

  // Fonction pour obtenir les leaderboards bruts d'une section
  const getSectionLeaderboards = useCallback((boards) => {
    if (!boards) return [];
    return [...boards];
  }, []);

  // Filter functions for categories
  const filterByTag = useCallback((tag, boards) => {
    const searchTag = tag.toLowerCase();
    return (
      boards?.filter((board) =>
        board.tags?.some((t) => t.toLowerCase() === searchTag)
      ) || []
    );
  }, []);

  const filterByLanguage = useCallback((boards) => {
    return (
      boards?.filter((board) =>
        board.tags?.some((tag) => tag.startsWith("language:"))
      ) || []
    );
  }, []);

  // Define sections with raw data
  const allSections = useMemo(() => {
    if (!leaderboards) return [];
    return generateSections(leaderboards, filterByTag, filterByLanguage);
  }, [leaderboards, filterByTag, filterByLanguage]);

  // Get sections with data
  const sections = useMemo(() => {
    return allSections.filter((section) => section.data.length > 0);
  }, [allSections]);

  // Sections triées par nombre de leaderboards (pour l'affichage sur la page d'accueil)
  const sectionsSortedByCount = useMemo(() => {
    return [...sections].sort((a, b) => {
      // Filtrer pour n'avoir que les leaderboards approuvés
      const approvedA = a.data.filter(
        (board) => board.approval_status === "approved"
      );
      const approvedB = b.data.filter(
        (board) => board.approval_status === "approved"
      );
      return approvedB.length - approvedA.length; // Tri décroissant
    });
  }, [sections]);

  // Calculate total number of unique leaderboards (excluding duplicates)
  const totalLeaderboards = useMemo(() => {
    const uniqueIds = new Set(
      leaderboards
        .filter((board) => board.approval_status === "approved")
        .map((board) => board.id)
    );
    return uniqueIds.size;
  }, [leaderboards]);

  // Get filtered count
  const filteredCount = useMemo(() => {
    return filterLeaderboards(leaderboards).length;
  }, [filterLeaderboards, leaderboards]);

  // Function to get highlighted parts of text
  const getHighlightedText = useCallback((text, searchTerm) => {
    if (!searchTerm || !text) return { text, shouldHighlight: false };

    const query = searchTerm.toLowerCase();
    const searchableTagPrefixes = [
      "domain:",
      "language:",
      "judge:",
      "test:",
      "modality:",
      "submission:",
      "eval:",
    ];

    // Si c'est une recherche par tag, on ne highlight rien
    if (searchableTagPrefixes.some((prefix) => query.startsWith(prefix))) {
      return { text, shouldHighlight: false };
    }

    // Sinon on highlight les parties qui matchent
    const index = text.toLowerCase().indexOf(query);
    if (index === -1) return { text, shouldHighlight: false };

    return {
      text,
      shouldHighlight: true,
      highlightStart: index,
      highlightEnd: index + query.length,
    };
  }, []);

  // Wrapper pour setLeaderboards qui normalise les tags
  const setNormalizedLeaderboards = useCallback((boards) => {
    const normalizedBoards = boards.map((board) => ({
      ...board,
      tags: normalizeTags(board.tags),
    }));
    setLeaderboards(normalizedBoards);
  }, []);

  const resetState = useCallback(() => {
    setSearchQuery("");
    setArenaOnly(false);
    setSelectedCategories(new Set());
    setSelectedLanguage(new Set());
    setExpandedSections(new Set());
    setIsLanguageExpanded(false);
  }, []);

  const value = {
    leaderboards,
    setLeaderboards: setNormalizedLeaderboards,
    searchQuery,
    setSearchQuery,
    arenaOnly,
    setArenaOnly,
    totalLeaderboards,
    filteredCount,
    filterLeaderboards,
    filterLeaderboardsForCount,
    sections,
    sectionsSortedByCount,
    allSections,
    getHighlightedText,
    selectedCategories,
    setSelectedCategories: handleCategorySelection,
    selectedLanguage,
    setSelectedLanguage: handleLanguageSelection,
    expandedSections,
    setExpandedSections,
    resetState,
    isLanguageExpanded,
    setIsLanguageExpanded,
  };

  return (
    <LeaderboardContext.Provider value={value}>
      {children}
    </LeaderboardContext.Provider>
  );
};

export const useLeaderboard = () => {
  const context = useContext(LeaderboardContext);
  if (!context) {
    throw new Error("useLeaderboard must be used within a LeaderboardProvider");
  }
  return context;
};
