"use client";

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

import type { UserPreferences } from "@rental/shared";

import { getUserPreferencesRequest, updateUserPreferencesRequest } from "../../lib/api";
import { defaultUserPreferences } from "../../lib/user-ordering";
import { useSessionContext } from "./session-provider";

type UserPreferencesContextValue = {
  preferences: UserPreferences;
  ready: boolean;
  saving: boolean;
  updatePreferences: (patch: Partial<UserPreferences>) => Promise<UserPreferences>;
};

const UserPreferencesContext = createContext<UserPreferencesContextValue | undefined>(undefined);

export const UserPreferencesProvider = ({ children }: { children: React.ReactNode }) => {
  const { session } = useSessionContext();
  const [preferences, setPreferences] = useState<UserPreferences>(defaultUserPreferences);
  const [ready, setReady] = useState(false);
  const [saving, setSaving] = useState(false);

  useEffect(() => {
    let active = true;

    if (!session) {
      setPreferences(defaultUserPreferences);
      setReady(true);
      return;
    }

    setReady(false);
    void getUserPreferencesRequest(session)
      .then((nextPreferences) => {
        if (!active) {
          return;
        }

        setPreferences(nextPreferences);
        setReady(true);
      })
      .catch(() => {
        if (!active) {
          return;
        }

        setPreferences(defaultUserPreferences);
        setReady(true);
      });

    return () => {
      active = false;
    };
  }, [session]);

  const value = useMemo<UserPreferencesContextValue>(
    () => ({
      preferences,
      ready,
      saving,
      updatePreferences: async (patch) => {
        if (!session) {
          return preferences;
        }

        setSaving(true);

        try {
          const nextPreferences = await updateUserPreferencesRequest(session, patch);
          setPreferences(nextPreferences);
          return nextPreferences;
        } finally {
          setSaving(false);
        }
      }
    }),
    [preferences, ready, saving, session]
  );

  return <UserPreferencesContext.Provider value={value}>{children}</UserPreferencesContext.Provider>;
};

export const useUserPreferences = () => {
  const context = useContext(UserPreferencesContext);

  if (!context) {
    throw new Error("useUserPreferences must be used within UserPreferencesProvider");
  }

  return context;
};
