import { createContext, useCallback, useContext, useRef, useState } from "react";
import type { ReactNode } from "react";
import { cloneWithoutAnimations } from "./Liftable";

type LiftContextValue = {
  liftedIds: Set<string>;
  alwaysLiftedIds: Set<string>;
  modalOpen: boolean;
  setLiftedIds: (ids: string[]) => void;
  registerAlways: (id: string) => void;
  unregisterAlways: (id: string) => void;
  registerModal: () => void;
  beginModalClose: () => void;
  endModalClose: () => void;
  portalContainer: HTMLElement | null;
  setPortalContainer: (el: HTMLElement | null) => void;
  setCloneContainer: (el: HTMLElement | null) => void;
};

const LiftContext = createContext<LiftContextValue | null>(null);

export function useLift(): LiftContextValue {
  const ctx = useContext(LiftContext);
  if (!ctx) throw new Error("useLift must be used within LiftProvider");
  return ctx;
}

export function LiftProvider({ children }: { children: ReactNode }) {
  const [liftedIds, setLiftedIdsRaw] = useState<Set<string>>(new Set());
  const [alwaysLiftedIds, setAlwaysLiftedIds] = useState<Set<string>>(new Set());
  const [modalOpen, setModalOpen] = useState(false);
  const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(null);
  const alwaysRef = useRef<Set<string>>(new Set());
  const modalCountRef = useRef(0);
  const cloneContainerRef = useRef<HTMLElement | null>(null);

  const setLiftedIds = useCallback((ids: string[]) => {
    setLiftedIdsRaw(new Set(ids));
  }, []);

  const registerModal = useCallback(() => {
    modalCountRef.current++;
    setModalOpen(true);
  }, []);

  const beginModalClose = useCallback(() => {
    if (portalContainer && cloneContainerRef.current) {
      cloneWithoutAnimations(portalContainer, cloneContainerRef.current);
    }
    modalCountRef.current--;
    if (modalCountRef.current === 0) {
      setModalOpen(false);
    }
  }, [portalContainer]);

  const endModalClose = useCallback(() => {
    if (cloneContainerRef.current) {
      cloneContainerRef.current.innerHTML = "";
    }
  }, []);

  const setCloneContainer = useCallback((el: HTMLElement | null) => {
    cloneContainerRef.current = el;
  }, []);

  const registerAlways = useCallback((id: string) => {
    alwaysRef.current.add(id);
    setAlwaysLiftedIds(new Set(alwaysRef.current));
  }, []);

  const unregisterAlways = useCallback((id: string) => {
    alwaysRef.current.delete(id);
    setAlwaysLiftedIds(new Set(alwaysRef.current));
  }, []);

  return (
    <LiftContext
      value={{
        liftedIds,
        alwaysLiftedIds,
        modalOpen,
        setLiftedIds,
        registerAlways,
        unregisterAlways,
        registerModal,
        beginModalClose,
        endModalClose,
        portalContainer,
        setPortalContainer,
        setCloneContainer,
      }}
    >
      {children}
    </LiftContext>
  );
}
