import { useEffect, useMemo, useReducer, useRef } from "react";
import { clearSavedSession, readSavedContext, readSavedSession, readSavedView, writeSavedContext, writeSavedSession, writeSavedView } from "./app-persistence.js";
import { request } from "./api.js";
import { initialAppState, reduceAppState, resolveInitialContext } from "./app-state.js";

export function useAppController() {
  const [state, dispatch] = useReducer(reduceAppState, initialAppState);
  const stateRef = useRef(state);
  stateRef.current = state;
  const restoreAttempted = useRef(false);
  const chatTransitionId = useRef(0);
  const activeChatTransitionId = useRef(0);

  useEffect(() => {
    let active = true;
    Promise.allSettled([request("/accounts"), request("/workspaces")])
      .then(([accountResult, workspaceResult]) => {
        const accountsLoaded = accountResult.status === "fulfilled";
        const workspacesLoaded = workspaceResult.status === "fulfilled";
        const accounts = accountsLoaded ? accountResult.value.accounts : [];
        const workspaces = workspacesLoaded ? workspaceResult.value.workspaces : [];
        if (!accountsLoaded && !workspacesLoaded) {
          if (active) dispatch({ type: "context.failed", error: contextLoadError(accountResult.reason) });
          return;
        }
        const error = [
          accountsLoaded ? "" : "Accounts unavailable",
          workspacesLoaded ? "" : "Projects unavailable"
        ].filter(Boolean).join(". ");
        const savedContext = readSavedContext();
        const initialContext = resolveInitialContext({
          accounts,
          workspaces,
          savedContext,
          accountsLoaded,
          workspacesLoaded
        });
        writeSavedContext(undefined, initialContext);
        if (active) dispatch({
          type: "context.loaded",
          accounts,
          workspaces,
          accountsLoaded,
          workspacesLoaded,
          savedContext: initialContext,
          error
        });
        const savedView = readSavedView();
        if (active && savedView !== "chat") dispatch({ type: "view.restored", tab: savedView });
      })
      .catch(() => {
        if (active) dispatch({ type: "context.failed", error: contextLoadError() });
      });
    return () => { active = false; };
  }, []);

  useEffect(() => {
    if (restoreAttempted.current || !state.contextLoaded) return;
    restoreAttempted.current = true;
    const saved = readSavedSession();
    if (!saved) {
      dispatch({ type: "bootstrap.ready" });
      return;
    }
    let active = true;
    request(`/sessions/${encodeURIComponent(saved.sessionId)}`)
      .then((result) => {
        if (active) dispatch({ type: "session.restored", restoreSessionId: saved.sessionId, session: result.session, tab: readSavedView() });
      })
      .catch(() => {
        clearSavedSession();
        if (active) dispatch({ type: "session.restore.failed", restoreSessionId: saved.sessionId });
      })
      .finally(() => {
        if (active) dispatch({ type: "bootstrap.ready" });
      });
    return () => { active = false; };
  }, [state.contextLoaded]);

  useEffect(() => {
    if (!state.contextLoaded) return;
    writeSavedContext(undefined, { accountId: state.accountId, workspaceId: state.workspaceId });
  }, [state.accountId, state.contextLoaded, state.workspaceId]);

  const selectedAccount = useMemo(
    () => state.accounts.find((account) => account.id === state.accountId),
    [state.accounts, state.accountId]
  );
  const selectedWorkspace = useMemo(
    () => state.workspaces.find((workspace) => workspace.id === state.workspaceId),
    [state.workspaces, state.workspaceId]
  );

  return {
    ...state,
    selectedAccount,
    selectedWorkspace,
    selectAccount: (accountId) => {
      writeSavedContext(undefined, { accountId, workspaceId: state.workspaceId });
      dispatch({ type: "account.selected", accountId });
    },
    replaceAccounts: (accounts, preferredId) => dispatch({ type: "accounts.replaced", accounts, preferredId }),
    replaceWorkspaces: (workspaces, preferredId) => dispatch({ type: "workspaces.replaced", workspaces, preferredId }),
    selectWorkspace: (workspaceId) => {
      writeSavedContext(undefined, { accountId: state.accountId, workspaceId });
      dispatch({ type: "workspace.selected", workspaceId });
    },
    selectTab: (tab) => {
      writeSavedView(undefined, tab);
      dispatch({ type: "tab.selected", tab });
    },
    openSettings: () => {
      writeSavedView(undefined, "settings");
      dispatch({ type: "settings.opened" });
    },
    closeSettings: () => {
      const returnTab = stateRef.current.settingsReturnTab && stateRef.current.settingsReturnTab !== "settings"
        ? stateRef.current.settingsReturnTab
        : "threads";
      writeSavedView(undefined, stateRef.current.newChatOpen ? "new" : returnTab);
      dispatch({ type: "settings.dismissed" });
    },
    startNewChat: () => {
      writeSavedView(undefined, "new");
      dispatch({ type: "new-chat.selected" });
    },
    closeNewChat: () => {
      writeSavedView(undefined, state.tab === "chat" ? "chat" : state.tab === "settings" ? "settings" : "threads");
      dispatch({ type: "new-chat.dismissed" });
    },
    startChatTransition: (label, target) => {
      const requestId = ++chatTransitionId.current;
      activeChatTransitionId.current = requestId;
      writeSavedView(undefined, "chat");
      dispatch({ type: "chat.transition.started", requestId, label, target });
      return requestId;
    },
    failChatTransition: (requestId, error) => dispatch({ type: "chat.transition.failed", requestId, error }),
    cancelChatTransition: () => {
      activeChatTransitionId.current = 0;
      writeSavedView(undefined, "threads");
      dispatch({ type: "chat.transition.canceled" });
    },
    isCurrentChatTransition: (requestId) => activeChatTransitionId.current === requestId,
    openSession: (session, requestId, { reveal = false } = {}) => {
      if (requestId != null) activeChatTransitionId.current = 0;
      writeSavedSession(undefined, session);
      writeSavedView(undefined, reveal ? "chat" : stateRef.current.tab === "settings" ? "settings" : "chat");
      writeSavedContext(undefined, {
        accountId: state.accountId,
        workspaceId: session.workspaceId || ""
      });
      dispatch({ type: "session.opened", session, requestId, reveal });
    },
    updateSession: (session) => {
      writeSavedSession(undefined, session);
      writeSavedContext(undefined, {
        accountId: state.accountId,
        workspaceId: session.workspaceId || state.workspaceId
      });
      dispatch({ type: "session.updated", session });
    }
  };
}

function contextLoadError(error) {
  if (error?.message === "pc_unreachable") return "pc_unreachable";
  return "context_unavailable";
}
