import { useEffect, useReducer, useState } from "react";
import { completeAccountLogin, completeAccountLoginAttempt, connectAccount, deleteAccount, startAccountLoginAttempt, updateAccount } from "./accounts-api.js";
import { accountMutationError, initialAccountsState, reduceAccountsState } from "./accounts-state.js";

export function useAccounts({ replaceAccounts, accounts = [], maxAccounts = Infinity, onProRequired = () => {} }) {
  const [state, dispatch] = useReducer(reduceAccountsState, initialAccountsState);
  const [login, setLogin] = useState(null);

  useEffect(() => {
    if (login?.kind !== "new" || !login.attemptId) return undefined;
    let checking = false;
    const poll = async () => {
      if (checking) return;
      checking = true;
      try { await checkConnection(true); } finally { checking = false; }
    };
    const timer = setInterval(() => void poll(), 1000);
    return () => clearInterval(timer);
  }, [login?.kind, login?.attemptId]);

  function add({ bypassPro = false } = {}) {
    if (!bypassPro && accounts.filter(account => !account.historyOnly).length >= maxAccounts) { onProRequired(); return false; }
    dispatch({ type: "mutation.completed" });
    setLogin({ kind: "new" });
    return true;
  }

  async function requestLoginCode() {
    if (login?.kind !== "new") return false;
    dispatch({ type: "mutation.started" });
    try {
      const result = await startAccountLoginAttempt();
      setLogin({ ...result, kind: "new" });
      dispatch({ type: "mutation.completed" });
      return true;
    } catch (error) {
      if (error?.message === "pro_required") { setLogin(null); onProRequired(); return false; }
      dispatch({ type: "mutation.failed", error: accountMutationError(error, "account_add_failed") });
      return false;
    }
  }

  async function remove(accountId) {
    dispatch({ type: "mutation.started", accountId });
    try {
      const result = await deleteAccount(accountId);
      replaceAccounts(result.accounts);
      dispatch({ type: "mutation.completed" });
    } catch (error) {
      dispatch({ type: "mutation.failed", error: accountMutationError(error, "account_remove_failed") });
    }
  }

  async function rename(accountId, label) {
    dispatch({ type: "mutation.started", accountId });
    try {
      const result = await updateAccount(accountId, label);
      replaceAccounts(result.accounts);
      dispatch({ type: "mutation.completed" });
      return true;
    } catch (error) {
      dispatch({ type: "mutation.failed", error: accountMutationError(error, "account_rename_failed") });
      return false;
    }
  }

  async function connect(accountId) {
    dispatch({ type: "mutation.started", accountId });
    try {
      const result = await connectAccount(accountId);
      setLogin({ ...result, kind: "existing", accountId });
      dispatch({ type: "mutation.completed" });
      return true;
    } catch (error) {
      dispatch({ type: "mutation.failed", error: accountMutationError(error, "account_login_start_failed") });
      return false;
    }
  }

  async function checkConnection(silent = false) {
    if (!login?.attemptId && login?.kind === "new") return false;
    if (!login) return false;
    if (!silent) dispatch({ type: "mutation.started", accountId: login.accountId ?? "" });
    try {
      const result = login.kind === "new"
        ? await completeAccountLoginAttempt(login.attemptId)
        : await completeAccountLogin(login.accountId);
      const connected = result.connected;
      if (connected) {
        replaceAccounts(result.accounts);
        setLogin((current) => login.kind === "new"
          ? current?.attemptId === login.attemptId ? null : current
          : current?.accountId === login.accountId ? null : current);
        dispatch({ type: "mutation.completed" });
      } else if (!silent) {
        dispatch({ type: "mutation.completed" });
      }
      return connected;
    } catch (error) {
      if (silent && error?.message === "account_login_attempt_not_found") {
        setLogin((current) => current?.attemptId === login.attemptId ? { kind: "new" } : current);
        return false;
      }
      if (!silent) dispatch({ type: "mutation.failed", error: accountMutationError(error, "account_check_failed") });
      return false;
    }
  }

  function dismissLogin() {
    setLogin(null);
  }

  return { ...state, login, add, requestLoginCode, remove, rename, connect, checkConnection, dismissLogin };
}
