import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
  type ReactNode,
} from "react";
import { Navigate, useLocation } from "react-router-dom";
import { useAuth } from "../auth/AuthContext";
import { useRepos } from "../data/DataContext";
import { isFirstRunAllowedPath } from "./paths";

export type FirstRunStepId = "crew";

export type FirstRunStep = {
  id: FirstRunStepId;
  done: boolean;
  to: string;
};

type FirstRunValue = {
  active: boolean;
  busy: boolean;
  steps: FirstRunStep[];
  current: FirstRunStep | null;
};

const INACTIVE: FirstRunValue = {
  active: false,
  busy: false,
  steps: [],
  current: null,
};

const FirstRunContext = createContext<FirstRunValue | null>(null);

function isTerminal(status?: string): boolean {
  return status === "skipped" || status === "completed";
}

export function FirstRunProvider({ children }: { children: ReactNode }) {
  const { member, loading, updateProfile } = useAuth();
  const repos = useRepos();
  const { pathname } = useLocation();
  const [busy, setBusy] = useState(false);
  const [crewDone, setCrewDone] = useState(false);
  const wroteRef = useRef(false);

  const pending = Boolean(member) && !loading && !isTerminal(member?.onboarding_status);

  const loadProgress = useCallback(async () => {
    if (!pending) return;
    const accounts = await repos.accounts.list().catch(() => []);
    setCrewDone(accounts.some((a) => a.is_usable) || accounts.length > 0);
  }, [pending, repos.accounts]);

  useEffect(() => {
    void loadProgress();
  }, [loadProgress, pathname]);

  const finish = useCallback(async () => {
    if (!pending || wroteRef.current) return;
    wroteRef.current = true;
    setBusy(true);
    try {
      await updateProfile({ onboarding_status: "completed" });
    } catch {
      wroteRef.current = false;
    } finally {
      setBusy(false);
    }
  }, [pending, updateProfile]);

  const steps = useMemo<FirstRunStep[]>(
    () => [{ id: "crew", done: crewDone, to: "/app/crew" }],
    [crewDone],
  );

  const current = steps.find((s) => !s.done) ?? null;
  const allDone = steps.length > 0 && steps.every((s) => s.done);

  useEffect(() => {
    if (!pending || busy || !allDone) return;
    void finish();
  }, [pending, busy, allDone, finish]);

  const value = useMemo<FirstRunValue>(
    () => ({
      active: pending && !allDone,
      busy,
      steps,
      current,
    }),
    [pending, allDone, busy, steps, current],
  );

  const gateStep = value.active && !isFirstRunAllowedPath(pathname) ? value.current : null;

  return (
    <FirstRunContext.Provider value={value}>
      {gateStep ? <Navigate to={gateStep.to} replace /> : children}
    </FirstRunContext.Provider>
  );
}

export function useFirstRun(): FirstRunValue {
  return useContext(FirstRunContext) ?? INACTIVE;
}
