import React, {
  createContext,
  useContext,
  useState,
  useCallback,
  useRef,
} from "react";
import { useUser, useAuth } from "@clerk/clerk-expo";
import {
  getRecommendations,
  generateRecommendation,
  type Recommendation,
  type GenerateRecommendationRequest,
} from "../api/recommendations";
import log from "../utils/logger";

interface RecommendationsContextValue {
  recommendations: Recommendation[];
  loading: boolean;
  error: Error | null;
  refetchRecommendations: () => Promise<void>;
  generateNewRecommendation: (
    data: GenerateRecommendationRequest,
  ) => Promise<Recommendation>;
  clearCache: () => void;
}

const RecommendationsContext = createContext<
  RecommendationsContextValue | undefined
>(undefined);

export function RecommendationsProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  const { user } = useUser();
  const { getToken } = useAuth();
  const [recommendations, setRecommendations] = useState<Recommendation[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);
  const [lastFetchTime, setLastFetchTime] = useState<number>(0);
  const fetchInProgress = useRef(false);

  // Cache recommendations for 30 seconds
  const CACHE_DURATION = 30000; // 30 seconds

  const refetchRecommendations = useCallback(async () => {
    if (!user?.id) return;

    // Prevent concurrent fetches
    if (fetchInProgress.current) {
      log.debug("Recommendations fetch already in progress, skipping");
      return;
    }

    // Check if we have recent cached data
    const now = Date.now();
    if (recommendations.length > 0 && now - lastFetchTime < CACHE_DURATION) {
      log.debug("Using cached recommendations", {
        count: recommendations.length,
        age: now - lastFetchTime,
        cacheRemaining: CACHE_DURATION - (now - lastFetchTime),
      });
      return;
    }

    try {
      fetchInProgress.current = true;
      setLoading(true);
      setError(null);
      log.debug("Fetching fresh recommendations", { userId: user.id });

      const token = await getToken();
      const data = await getRecommendations(user.id, token);

      setRecommendations(data);
      setLastFetchTime(now);
      log.debug("Recommendations fetched and cached", { count: data.length });
    } catch (err) {
      const error = err instanceof Error ? err : new Error(String(err));
      log.error("Failed to fetch recommendations", error);
      setError(error);
    } finally {
      setLoading(false);
      fetchInProgress.current = false;
    }
  }, [user?.id, getToken, recommendations.length, lastFetchTime]);

  const generateNewRecommendation = useCallback(
    async (data: GenerateRecommendationRequest): Promise<Recommendation> => {
      if (!user?.id) throw new Error("User not authenticated");

      const token = await getToken();
      const newRecommendation = await generateRecommendation(data, token);

      // Optimistically update cache
      setRecommendations((prev) => [...prev, newRecommendation]);
      setLastFetchTime(Date.now());
      log.debug("Recommendation generated and added to cache", {
        recommendationId: newRecommendation.id,
      });

      return newRecommendation;
    },
    [user?.id, getToken],
  );

  const clearCache = useCallback(() => {
    setRecommendations([]);
    setLastFetchTime(0);
    setError(null);
    fetchInProgress.current = false;
    log.debug("Recommendations cache cleared");
  }, []);

  return (
    <RecommendationsContext.Provider
      value={{
        recommendations,
        loading,
        error,
        refetchRecommendations,
        generateNewRecommendation,
        clearCache,
      }}
    >
      {children}
    </RecommendationsContext.Provider>
  );
}

export function useRecommendations() {
  const context = useContext(RecommendationsContext);
  if (context === undefined) {
    throw new Error(
      "useRecommendations must be used within a RecommendationsProvider",
    );
  }
  return context;
}
