import {PastWorkout, WorkoutState} from "../models/Workouts";
import {createContext, useCallback, useContext, useEffect, useState} from "react";
import {unimplemented} from "../helpers/misc";
import {WithChildren} from "../primitives/Shared";
import workoutRepo from "../actions/workouts";

interface WorkoutContextValue {
  workouts: PastWorkout[]
  loadingWorkouts: boolean
  expanded: boolean

  getWorkout(workoutId: string): PastWorkout | null
  fetchWorkout(workoutId: string): void

  getStates(workoutId: string): WorkoutState[] | null
  fetchStates(workoutId: string): void

  refreshWorkouts(): void
  showMoreWorkouts(): void
}

const WorkoutContext = createContext<WorkoutContextValue>({
  workouts: [],
  loadingWorkouts: false,
  expanded: false,
  getWorkout: unimplemented,
  fetchWorkout: unimplemented,
  getStates: unimplemented,
  fetchStates: unimplemented,
  refreshWorkouts: unimplemented,
  showMoreWorkouts: unimplemented,
});

export function WorkoutContextProvider({children}: WithChildren) {
  const [workouts, setWorkouts] = useState<PastWorkout[]>([]);
  const [cache, setCache] = useState<Record<string, PastWorkout>>({});
  const [loadingWorkouts, setLoadingWorkouts] = useState<boolean>(false);
  const [expanded, setExpanded] = useState<boolean>(false);
  const [ver, setVer] = useState(0);
  const [stateMap, setStateMap] = useState<Record<string, WorkoutState[]>>({});

  const getWorkout = useCallback((workoutId: string) => {
    return cache[workoutId] || workouts.find(w => w.id === workoutId);
  }, [cache, workouts]);

  const fetchWorkout = useCallback((workoutId: string) => {
    workoutRepo().findById(workoutId)
      .then(result => {
        if (result) {
          setCache(prev => ({...prev, [workoutId]: result}));
        }
      });
  }, []);

  const getStates = useCallback((workoutId: string) => {
    return stateMap[workoutId] || null;
  }, [stateMap]);

  const fetchStates = useCallback((workoutId: string) => {
    workoutRepo().fetchStates(workoutId)
      .then(result => setStateMap(prev => ({...prev, [workoutId]: result})));
  }, []);

  const refreshWorkouts = useCallback(() => {
    setVer(prev => prev + 1);
  }, []);

  const showMoreWorkouts = useCallback(() => {
    setExpanded(true);
  }, []);

  useEffect(() => {
    if (ver === 0) {
      return;
    }

    setLoadingWorkouts(true);
    workoutRepo().fetchByFilter({daysBack: expanded ? undefined : 6, includeTest: false})
      .then(setWorkouts)
      .finally(() => setLoadingWorkouts(false));
  }, [expanded, ver]);

  return (
    <WorkoutContext.Provider value={{
      workouts, loadingWorkouts, expanded,
      getWorkout, fetchWorkout,
      getStates, fetchStates,
      refreshWorkouts, showMoreWorkouts,
    }}>
      {children}
    </WorkoutContext.Provider>
  );
}

export default WorkoutContext;

