import React, {
  createContext,
  useContext,
  useState,
  useCallback,
  useEffect,
} from "react";
import { useUser, useAuth } from "@clerk/clerk-expo";
import {
  getNutritionByDate,
  saveDailyNutrition,
  addMealEntry,
  getMealEntriesByDate,
  type NutritionEntry,
  type MealEntry,
} from "../api/nutrition";
import log from "../utils/logger";

interface NutritionContextValue {
  nutrition: NutritionEntry | null;
  meals: MealEntry[];
  loading: boolean;
  error: Error | null;
  calorieGoal: number;
  todayCalories: number;
  percentage: number;
  addMeal: (
    data: Omit<MealEntry, "id" | "createdAt" | "dailyNutritionId">,
  ) => Promise<void>;
  updateGoal: (goal: number) => void;
  refetch: () => Promise<void>;
}

const NutritionContext = createContext<NutritionContextValue | undefined>(
  undefined,
);

export function NutritionProvider({ children }: { children: React.ReactNode }) {
  const { user } = useUser();
  const { getToken } = useAuth();
  const [nutrition, setNutrition] = useState<NutritionEntry | null>(null);
  const [meals, setMeals] = useState<MealEntry[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);
  const [calorieGoal, setCalorieGoal] = useState(2000); // Default goal: 2000 cal

  const today = new Date().toISOString().split("T")[0];

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

    try {
      setLoading(true);
      setError(null);

      const token = await getToken();

      // Fetch both nutrition data and meal entries
      const [nutritionData, mealsData] = await Promise.all([
        getNutritionByDate(today, token),
        getMealEntriesByDate(today, token),
      ]);

      if (nutritionData) {
        setNutrition(nutritionData);
        if (nutritionData.calorieGoal) {
          setCalorieGoal(nutritionData.calorieGoal);
        }
      } else {
        setNutrition(null);
      }

      setMeals(mealsData);
      log.debug("Today's nutrition fetched", {
        nutritionData,
        mealsCount: mealsData.length,
      });
    } catch (err) {
      const error = err instanceof Error ? err : new Error(String(err));
      log.error("Failed to fetch nutrition", error);
      setError(error);
    } finally {
      setLoading(false);
    }
  }, [user?.id, getToken, today]);

  useEffect(() => {
    fetchTodayNutrition();
  }, [fetchTodayNutrition]);

  const addMeal = useCallback(
    async (data: Omit<MealEntry, "id" | "createdAt" | "dailyNutritionId">) => {
      if (!user?.id) return;

      try {
        const token = await getToken();

        // Add the meal entry
        const meal = await addMealEntry(data, token);

        // Recalculate total calories
        const currentTotal = nutrition?.totalCalories || 0;
        const newTotal = currentTotal + data.calories;

        // Update the daily nutrition
        const updatedNutrition = await saveDailyNutrition(
          {
            date: today,
            totalCalories: newTotal,
            calorieGoal,
            meals: [
              ...(nutrition?.meals || []),
              {
                type: data.mealType,
                name: data.foodName,
                calories: data.calories,
                time: new Date().toISOString(),
              },
            ],
          },
          token,
        );

        setNutrition(updatedNutrition);
        setMeals([...meals, meal]);
        log.debug("Meal added successfully", { meal, newTotal });
      } catch (err) {
        const error = err instanceof Error ? err : new Error(String(err));
        log.error("Failed to add meal", error);
        setError(error);
        throw error;
      }
    },
    [user?.id, getToken, today, nutrition, calorieGoal, meals],
  );

  const updateGoal = useCallback(
    async (goal: number) => {
      setCalorieGoal(goal);
      if (user?.id && nutrition) {
        try {
          const token = await getToken();
          await saveDailyNutrition(
            {
              date: today,
              totalCalories: nutrition.totalCalories,
              calorieGoal: goal,
              meals: nutrition.meals,
            },
            token,
          );
        } catch (err) {
          log.error("Failed to update calorie goal", err);
        }
      }
    },
    [user?.id, nutrition, today, getToken],
  );

  const todayCalories = nutrition?.totalCalories || 0;
  const percentage =
    calorieGoal > 0 ? Math.round((todayCalories / calorieGoal) * 100) : 0;

  const value: NutritionContextValue = {
    nutrition,
    meals,
    loading,
    error,
    calorieGoal,
    todayCalories,
    percentage,
    addMeal,
    updateGoal,
    refetch: fetchTodayNutrition,
  };

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

export function useNutrition() {
  const context = useContext(NutritionContext);
  if (context === undefined) {
    throw new Error("useNutrition must be used within a NutritionProvider");
  }
  return context;
}
