import React, {
  createContext,
  useContext,
  useState,
  useCallback,
  useMemo,
  useEffect,
} from "react";

const LeaderboardContext = createContext();

// Helper pour mettre à jour l'URL
const updateURL = (params) => {
  const url = new URL(window.location);
  Object.entries(params).forEach(([key, value]) => {
    if (value) {
      url.searchParams.set(key, value);
    } else {
      url.searchParams.delete(key);
    }
  });
  window.history.pushState({}, "", url);
};

// Helper pour lire les paramètres de l'URL
const getURLParams = () => {
  const params = new URLSearchParams(window.location.search);
  return {
    category: params.get("category"),
    search: params.get("search"),
    arena: params.get("arena") === "true",
    language: params.get("language"),
  };
};

export const LeaderboardProvider = ({ children }) => {
  // Lire les paramètres initiaux depuis l'URL
  const initialParams = getURLParams();

  const [leaderboards, setLeaderboards] = useState([]);
  const [searchQuery, setSearchQuery] = useState(initialParams.search || "");
  const [arenaOnly, setArenaOnly] = useState(initialParams.arena);
  const [selectedCategory, setSelectedCategory] = useState(
    initialParams.category
  );
  const [selectedLanguage, setSelectedLanguage] = useState(
    initialParams.language
  );
  const [expandedSections, setExpandedSections] = useState(new Set());

  // Mettre à jour l'URL quand les filtres changent
  useEffect(() => {
    updateURL({
      category: selectedCategory,
      search: searchQuery,
      arena: arenaOnly ? "true" : null,
      language: selectedLanguage,
    });
  }, [selectedCategory, searchQuery, arenaOnly, selectedLanguage]);

  // Écouter les changements d'URL (navigation back/forward)
  useEffect(() => {
    const handleURLChange = () => {
      const params = getURLParams();
      setSearchQuery(params.search || "");
      setArenaOnly(params.arena);
      setSelectedCategory(params.category);
      setSelectedLanguage(params.language);
    };

    window.addEventListener("popstate", handleURLChange);
    return () => window.removeEventListener("popstate", handleURLChange);
  }, []);

  // Wrapper pour setSelectedCategory qui gère aussi l'expansion des sections
  const handleCategorySelection = useCallback((categoryId) => {
    // On réinitialise toujours la langue sélectionnée
    setSelectedLanguage(null);

    setSelectedCategory((prev) => {
      if (prev === categoryId) {
        // Si on désélectionne, on replie toutes les sections
        setExpandedSections(new Set());
        return null;
      }
      // Si on sélectionne une nouvelle catégorie, on la déploie
      setExpandedSections(new Set([categoryId]));
      return categoryId;
    });
  }, []);

  // Wrapper pour la sélection de langue
  const handleLanguageSelection = useCallback((language) => {
    setSelectedLanguage((prev) => (prev === language ? null : language));
  }, []);

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

      let filtered = [...boards];

      // Filter by search query (text only)
      if (searchQuery) {
        const query = searchQuery.toLowerCase();
        filtered = filtered.filter((board) =>
          board.card_data?.title?.toLowerCase().includes(query)
        );
      }

      // Filter arena only
      if (arenaOnly) {
        filtered = filtered.filter((board) =>
          board.tags?.includes("judge:humans")
        );
      }

      return filtered;
    },
    [searchQuery, arenaOnly]
  );

  // Filter leaderboards based on all criteria including category and language selection
  const filterLeaderboards = useCallback(
    (boards) => {
      if (!boards) return [];

      let filtered = filterLeaderboardsForCount(boards);

      // Filter by selected language if any
      if (selectedLanguage) {
        filtered = filtered.filter((board) =>
          board.tags?.some(
            (tag) =>
              tag.toLowerCase() === `language:${selectedLanguage.toLowerCase()}`
          )
        );
      }

      // Filter by selected category if any
      if (selectedCategory) {
        filtered = filtered.filter((board) => {
          const { tags = [] } = board;
          switch (selectedCategory) {
            case "agentic":
              return tags.includes("modality:agent");
            case "code":
              return tags.includes("eval:code");
            case "math":
              return tags.includes("eval:math");
            case "language":
              return tags.some((tag) => tag.startsWith("language:"));
            case "vision":
              return tags.some(
                (tag) => tag === "modality:video" || tag === "modality:image"
              );
            case "threeD":
              return tags.includes("modality:3d");
            case "audio":
              return tags.includes("modality:audio");
            case "financial":
              return tags.includes("domain:financial");
            case "medical":
              return tags.includes("domain:medical");
            case "legal":
              return tags.includes("domain:legal");
            case "safety":
              return tags.includes("eval:safety");
            case "uncategorized":
              return !tags.some(
                (tag) =>
                  [
                    "modality:agent",
                    "eval:code",
                    "eval:math",
                    "modality:video",
                    "modality:image",
                    "modality:3d",
                    "modality:audio",
                    "domain:financial",
                    "domain:medical",
                    "domain:legal",
                    "eval:safety",
                  ].includes(tag) || tag.startsWith("language:")
              );
            default:
              return true;
          }
        });
      }

      return filtered;
    },
    [filterLeaderboardsForCount, selectedCategory, selectedLanguage]
  );

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

  // Fonction pour compter les leaderboards par langue
  const getLanguageStats = useCallback((boards) => {
    const stats = new Map();

    boards.forEach((board) => {
      board.tags?.forEach((tag) => {
        if (tag.startsWith("language:")) {
          const language = tag.split(":")[1];
          const capitalizedLang =
            language.charAt(0).toUpperCase() + language.slice(1);
          const count = stats.get(capitalizedLang) || 0;
          stats.set(capitalizedLang, count + 1);
        }
      });
    });

    return stats;
  }, []);

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

  // Filter functions for categories
  const filterByTag = useCallback((tag, boards) => {
    const searchTag = tag.toLowerCase();
    console.log("Filtering by tag:", {
      searchTag,
      boards: boards?.map((board) => ({
        id: board.id,
        tags: board.tags,
        matches: {
          tags: board.tags?.some((t) => t.toLowerCase() === searchTag),
        },
      })),
    });
    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:"))
      ) || []
    );
  }, []);

  const filterByVision = useCallback((boards) => {
    return (
      boards?.filter((board) =>
        board.tags?.some(
          (tag) => tag === "modality:video" || tag === "modality:image"
        )
      ) || []
    );
  }, []);

  // Helper function to get the category group of a section
  const getSectionGroup = (id) => {
    const groups = {
      agentic: ["agentic"],
      capabilities: ["code", "math"],
      languages: ["language"],
      modalities: ["vision", "audio"],
      threeD: ["threeD"],
      domains: ["financial", "medical", "legal"],
      evaluation: ["safety"],
      misc: ["uncategorized"],
    };

    for (const [group, ids] of Object.entries(groups)) {
      if (ids.includes(id)) {
        return group;
      }
    }
    return "misc";
  };

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

    // Garder une trace des leaderboards déjà catégorisés
    const categorizedIds = new Set();

    const sections = [
      {
        id: "agentic",
        title: "Agentic",
        data: filterByTag("modality:agent", leaderboards).map((board) => {
          categorizedIds.add(board.id);
          return board;
        }),
      },
      {
        id: "code",
        title: "Code",
        data: filterByTag("eval:code", leaderboards).map((board) => {
          categorizedIds.add(board.id);
          return board;
        }),
      },
      {
        id: "math",
        title: "Math",
        data: filterByTag("eval:math", leaderboards).map((board) => {
          categorizedIds.add(board.id);
          return board;
        }),
      },
      {
        id: "language",
        title: "Language Specific",
        data: filterByLanguage(leaderboards).map((board) => {
          categorizedIds.add(board.id);
          return board;
        }),
      },
      {
        id: "vision",
        title: "Vision",
        data: filterByVision(leaderboards).map((board) => {
          categorizedIds.add(board.id);
          return board;
        }),
      },
      {
        id: "audio",
        title: "Audio",
        data: filterByTag("modality:audio", leaderboards).map((board) => {
          categorizedIds.add(board.id);
          return board;
        }),
      },
      {
        id: "threeD",
        title: "3D",
        data: filterByTag("modality:3d", leaderboards).map((board) => {
          categorizedIds.add(board.id);
          return board;
        }),
      },
      {
        id: "financial",
        title: "Financial",
        data: filterByTag("domain:financial", leaderboards).map((board) => {
          categorizedIds.add(board.id);
          return board;
        }),
      },
      {
        id: "medical",
        title: "Medical",
        data: filterByTag("domain:medical", leaderboards).map((board) => {
          categorizedIds.add(board.id);
          return board;
        }),
      },
      {
        id: "legal",
        title: "Legal",
        data: filterByTag("domain:legal", leaderboards).map((board) => {
          categorizedIds.add(board.id);
          return board;
        }),
      },
      {
        id: "safety",
        title: "Safety",
        data: filterByTag("eval:safety", leaderboards).map((board) => {
          categorizedIds.add(board.id);
          return board;
        }),
      },
      {
        id: "uncategorized",
        title: "Uncategorized",
        // Mettre dans uncategorized uniquement les leaderboards qui n'apparaissent nulle part ailleurs
        data: leaderboards.filter((board) => !categorizedIds.has(board.id)),
      },
    ];

    return sections;
  }, [leaderboards, filterByTag, filterByLanguage, filterByVision]);

  // Get sections with data
  const sections = useMemo(() => {
    console.log("Starting sections filtering...");
    console.log(
      "All sections before filtering:",
      allSections.map((s) => ({
        title: s.title,
        count: s.data.length,
        ids: s.data.map((b) => b.id),
      }))
    );

    // On garde une trace des titres déjà vus
    const seenTitles = new Set();
    const filteredSections = allSections.filter((section) => {
      console.log(`\nAnalyzing section ${section.title}:`, {
        data: section.data,
        count: section.data.length,
        uniqueIds: new Set(section.data.map((b) => b.id)).size,
        boards: section.data.map((board) => ({
          id: board.id,
          tags: board.tags,
        })),
      });

      // On garde la section si elle a des données et qu'on ne l'a pas déjà vue
      if (section.data.length > 0 && !seenTitles.has(section.title)) {
        seenTitles.add(section.title);
        return true;
      }
      return false;
    });

    console.log(
      "\nFinal sections after filtering:",
      filteredSections.map((s) => ({
        title: s.title,
        count: s.data.length,
        uniqueIds: new Set(s.data.map((b) => b.id)).size,
      }))
    );

    return filteredSections;
  }, [allSections]);

  // Get filtered count
  const filteredCount = useMemo(() => {
    return filterLeaderboardsForCount(leaderboards).length;
  }, [filterLeaderboardsForCount, 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:",
    ];

    // 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,
    };
  }, []);

  const value = {
    leaderboards,
    setLeaderboards,
    searchQuery,
    setSearchQuery,
    arenaOnly,
    setArenaOnly,
    totalLeaderboards,
    filteredCount,
    filterLeaderboards,
    filterLeaderboardsForCount,
    sections,
    allSections,
    getHighlightedText,
    selectedCategory,
    setSelectedCategory: handleCategorySelection,
    selectedLanguage,
    setSelectedLanguage: handleLanguageSelection,
    expandedSections,
    setExpandedSections,
    getLanguageStats,
    getSectionLeaderboards,
  };

  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;
};
