import { useCallback, useEffect, useReducer } from "react";
import { openUrl } from "@tauri-apps/plugin-opener";
import { listen } from "@tauri-apps/api/event";
import {
  AccountInfo,
  startOAuth,
  getAccountInfo,
  checkSubscriptionStatus,
  logoutAccount,
} from "../services/authService";

type AuthStatus = "idle" | "loading" | "authenticated" | "unauthenticated" | "error";

interface AuthState {
  status: AuthStatus;
  account: AccountInfo | null;
  error: string | null;
}

type AuthAction =
  | { type: "LOAD_START" }
  | { type: "LOAD_DONE"; account: AccountInfo | null }
  | { type: "LOGIN_START" }
  | { type: "LOGOUT" }
  | { type: "ERROR"; error: string };

const initialState: AuthState = {
  status: "idle",
  account: null,
  error: null,
};

function reducer(state: AuthState, action: AuthAction): AuthState {
  switch (action.type) {
    case "LOAD_START":
      return { ...state, status: "loading", error: null };
    case "LOAD_DONE":
      return {
        status: action.account ? "authenticated" : "unauthenticated",
        account: action.account,
        error: null,
      };
    case "LOGIN_START":
      return { ...state, status: "loading", error: null };
    case "LOGOUT":
      return { status: "unauthenticated", account: null, error: null };
    case "ERROR":
      return { ...state, status: "error", error: action.error };
  }
}

export function useAuth() {
  const [state, dispatch] = useReducer(reducer, initialState);

  const refresh = useCallback(async () => {
    dispatch({ type: "LOAD_START" });
    try {
      // checkSubscriptionStatus refreshes the token if last check > 24h,
      // otherwise returns cached account info. Graceful on network errors.
      const account = await checkSubscriptionStatus();
      dispatch({ type: "LOAD_DONE", account });
    } catch (e) {
      // Fallback to cached account info if the check command itself fails
      try {
        const cached = await getAccountInfo();
        dispatch({ type: "LOAD_DONE", account: cached });
      } catch {
        dispatch({
          type: "ERROR",
          error: e instanceof Error ? e.message : String(e),
        });
      }
    }
  }, []);

  const login = useCallback(async () => {
    dispatch({ type: "LOGIN_START" });
    try {
      const url = await startOAuth();
      await openUrl(url);
      // The actual auth completion happens via the deep-link callback,
      // which triggers handle_auth_callback on the Rust side.
      // The UI should call refresh() after the callback completes.
    } catch (e) {
      dispatch({
        type: "ERROR",
        error: e instanceof Error ? e.message : String(e),
      });
    }
  }, []);

  const logout = useCallback(async () => {
    try {
      await logoutAccount();
      dispatch({ type: "LOGOUT" });
    } catch (e) {
      dispatch({
        type: "ERROR",
        error: e instanceof Error ? e.message : String(e),
      });
    }
  }, []);

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

  // Listen for deep-link auth callback events from the Rust backend
  useEffect(() => {
    const unlisten: Array<() => void> = [];

    listen<AccountInfo>("auth-callback-success", (event) => {
      dispatch({ type: "LOAD_DONE", account: event.payload });
    }).then((fn) => unlisten.push(fn));

    listen<string>("auth-callback-error", (event) => {
      dispatch({ type: "ERROR", error: event.payload });
    }).then((fn) => unlisten.push(fn));

    return () => {
      unlisten.forEach((fn) => fn());
    };
  }, []);

  return { state, refresh, login, logout };
}
