import React, {
  createContext,
  useContext,
  useState,
  useCallback,
  useRef,
} from "react";
import { useUser, useAuth } from "@clerk/clerk-expo";
import {
  fitnessGoalsService,
  type FitnessGoal,
  type CreateGoalData,
} from "../services/fitnessGoals";
import log from "../utils/logger";

interface FitnessGoalsContextValue {
  goals: FitnessGoal[];
  loading: boolean;
  error: Error | null;
  refetchGoals: () => Promise<void>;
  createGoal: (goalData: CreateGoalData) => Promise<FitnessGoal>;
  updateGoal: (
    id: string,
    updates: Partial<FitnessGoal>,
  ) => Promise<FitnessGoal>;
  completeGoal: (id: string) => Promise<FitnessGoal>;
  deleteGoal: (id: string) => Promise<void>;
  clearCache: () => void;
}

const FitnessGoalsContext = createContext<FitnessGoalsContextValue | undefined>(
  undefined,
);

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

  // Cache goals for 30 seconds to avoid duplicate calls
  const CACHE_DURATION = 30000; // 30 seconds

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

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

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

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

      const token = await getToken();
      const loadedGoals = await fitnessGoalsService.getGoals(user.id, token);

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

  const createGoal = useCallback(
    async (goalData: CreateGoalData): Promise<FitnessGoal> => {
      if (!user?.id) throw new Error("User not authenticated");

      const token = await getToken();
      const newGoal = await fitnessGoalsService.createGoal(goalData, token);

      // Optimistically update cache
      setGoals((prev) => [...prev, newGoal]);
      setLastFetchTime(Date.now());
      log.debug("Goal created and added to cache", { goalId: newGoal.id });

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

  const updateGoal = useCallback(
    async (id: string, updates: Partial<FitnessGoal>): Promise<FitnessGoal> => {
      if (!user?.id) throw new Error("User not authenticated");

      const token = await getToken();
      const updatedGoal = await fitnessGoalsService.updateGoal(
        id,
        updates,
        token,
      );

      // Optimistically update cache
      setGoals((prev) =>
        prev.map((goal) => (goal.id === id ? updatedGoal : goal)),
      );
      setLastFetchTime(Date.now());
      log.debug("Goal updated in cache", { goalId: id });

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

  const completeGoal = useCallback(
    async (id: string): Promise<FitnessGoal> => {
      if (!user?.id) throw new Error("User not authenticated");

      const token = await getToken();
      const completedGoal = await fitnessGoalsService.completeGoal(id, token);

      // Optimistically update cache
      setGoals((prev) =>
        prev.map((goal) => (goal.id === id ? completedGoal : goal)),
      );
      setLastFetchTime(Date.now());
      log.debug("Goal completed in cache", { goalId: id });

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

  const deleteGoal = useCallback(
    async (id: string): Promise<void> => {
      if (!user?.id) throw new Error("User not authenticated");

      const token = await getToken();
      await fitnessGoalsService.deleteGoal(id, token);

      // Optimistically update cache
      setGoals((prev) => prev.filter((goal) => goal.id !== id));
      setLastFetchTime(Date.now());
      log.debug("Goal deleted from cache", { goalId: id });
    },
    [user?.id, getToken],
  );

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

  return (
    <FitnessGoalsContext.Provider
      value={{
        goals,
        loading,
        error,
        refetchGoals,
        createGoal,
        updateGoal,
        completeGoal,
        deleteGoal,
        clearCache,
      }}
    >
      {children}
    </FitnessGoalsContext.Provider>
  );
}

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