import React, {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from "react";
import { readJSON, storageKeys, writeJSON } from "../storage";
import type { RecentSearch, SearchResult } from "../types";

const MAX_RECENTS = 20;

type RecentsContextValue = {
  recents: RecentSearch[];
  ready: boolean;
  addRecent: (result: SearchResult) => void;
  clearRecents: () => void;
};

const RecentsContext = createContext<RecentsContextValue | undefined>(
  undefined
);

function sameRecent(a: RecentSearch, b: SearchResult): boolean {
  return (
    a.name === b.name &&
    a.position.latitude === b.position.latitude &&
    a.position.longitude === b.position.longitude
  );
}

export function RecentsProvider({
  children,
}: {
  children: React.ReactNode;
}): React.JSX.Element {
  const [recents, setRecents] = useState<RecentSearch[]>([]);
  const [ready, setReady] = useState(false);

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

  const addRecent = useCallback((result: SearchResult) => {
    setRecents((prev) => {
      const withoutDuplicate = prev.filter((entry) => !sameRecent(entry, result));
      const next = [
        { ...result, searchedAtEpochMs: Date.now() },
        ...withoutDuplicate,
      ].slice(0, MAX_RECENTS);
      void writeJSON(storageKeys.recents, next);
      return next;
    });
  }, []);

  const clearRecents = useCallback(() => {
    setRecents([]);
    void writeJSON<RecentSearch[]>(storageKeys.recents, []);
  }, []);

  const value = useMemo(
    () => ({ recents, ready, addRecent, clearRecents }),
    [recents, ready, addRecent, clearRecents]
  );

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

export function useRecents(): RecentsContextValue {
  const ctx = useContext(RecentsContext);
  if (!ctx) {
    throw new Error("useRecents must be used within a RecentsProvider");
  }
  return ctx;
}
