import React, {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from "react";
import { readJSON, storageKeys, writeJSON } from "../storage";
import type { SearchResult } from "../types";
import { addSavedPlace, getHome, getWork, removeSavedPlace } from "./reducer";
import type { SavedPlace, SavedPlaceKind } from "./reducer";

export type { SavedPlace, SavedPlaceKind } from "./reducer";

type SavedPlacesContextValue = {
  saved: SavedPlace[];
  ready: boolean;
  addSaved: (place: SearchResult, kind: SavedPlaceKind, label?: string) => void;
  removeSaved: (id: string) => void;
  /** Convenience getters — home/work are singletons within `saved`. */
  home: SavedPlace | undefined;
  work: SavedPlace | undefined;
};

const SavedPlacesContext = createContext<SavedPlacesContextValue | undefined>(
  undefined
);

export function SavedPlacesProvider({
  children,
}: {
  children: React.ReactNode;
}): React.JSX.Element {
  const [saved, setSaved] = useState<SavedPlace[]>([]);
  const [ready, setReady] = useState(false);

  useEffect(() => {
    let cancelled = false;
    readJSON<SavedPlace[]>(storageKeys.saved, []).then((loaded) => {
      if (cancelled) return;
      setSaved(loaded);
      setReady(true);
    });
    return () => {
      cancelled = true;
    };
  }, []);

  const addSaved = useCallback(
    (place: SearchResult, kind: SavedPlaceKind, label?: string) => {
      setSaved((prev) => {
        const next = addSavedPlace(prev, place, kind, label);
        void writeJSON(storageKeys.saved, next);
        return next;
      });
    },
    []
  );

  const removeSaved = useCallback((id: string) => {
    setSaved((prev) => {
      const next = removeSavedPlace(prev, id);
      void writeJSON(storageKeys.saved, next);
      return next;
    });
  }, []);

  const home = useMemo(() => getHome(saved), [saved]);
  const work = useMemo(() => getWork(saved), [saved]);

  const value = useMemo(
    () => ({ saved, ready, addSaved, removeSaved, home, work }),
    [saved, ready, addSaved, removeSaved, home, work]
  );

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

export function useSavedPlaces(): SavedPlacesContextValue {
  const ctx = useContext(SavedPlacesContext);
  if (!ctx) {
    throw new Error("useSavedPlaces must be used within a SavedPlacesProvider");
  }
  return ctx;
}
