import { Api, type ApiOptions, type AuthState } from "Api";
import { isDebug } from "core/env";
import { createContext, type ReactNode, useContext, useMemo, useState } from "react";
import type { AdminBkndWindowContext } from "modules/server/AdminController";

export type BkndClientContext = {
   baseUrl: string;
   api: Api;
   authState?: Partial<AuthState>;
};

const ClientContext = createContext<BkndClientContext>(undefined!);

export type ClientProviderProps = {
   children?: ReactNode;
   baseUrl?: string;
   api?: Api;
} & ApiOptions;

export const ClientProvider = ({
   children,
   host,
   baseUrl: _baseUrl = host,
   api: _api,
   ...props
}: ClientProviderProps) => {
   const winCtx = useBkndWindowContext();
   const _ctx = useClientContext();
   let actualBaseUrl = _baseUrl ?? _ctx?.baseUrl ?? "";
   let user: any;

   if (winCtx) {
      user = winCtx.user;
   }

   if (!actualBaseUrl) {
      try {
         actualBaseUrl = window.location.origin;
      } catch (e) {}
   }

   const apiProps = { user, ...props, host: actualBaseUrl };
   const api = useMemo(
      () =>
         _api ??
         new Api({
            ...apiProps,
            verbose: isDebug(),
            onAuthStateChange: (state) => {
               props.onAuthStateChange?.(state);
               if (!authState?.token || state.token !== authState?.token) {
                  setAuthState(state);
               }
            },
         }),
      [_api, JSON.stringify(apiProps)],
   );

   const [authState, setAuthState] = useState<Partial<AuthState> | undefined>(api.getAuthState());

   return (
      <ClientContext.Provider value={{ baseUrl: api.baseUrl, api, authState }}>
         {children}
      </ClientContext.Provider>
   );
};

export const useApi = (host?: ApiOptions["host"]): Api => {
   const context = useContext(ClientContext);

   if (!context?.api || (host && host.length > 0 && host !== context.baseUrl)) {
      console.info("creating new api", { host });
      return new Api({ host: host ?? "" });
   }
   if (!context) {
      throw new Error("useApi must be used within a ClientProvider");
   }

   return context.api;
};

export const useClientContext = () => {
   return useContext(ClientContext);
};

/**
 * @deprecated use useApi().baseUrl instead
 */
export const useBaseUrl = () => {
   const context = useClientContext();
   return context?.baseUrl;
};

export function useBkndWindowContext(): AdminBkndWindowContext {
   const defaults = {
      logout_route: "/api/auth/logout",
      admin_basepath: "",
   };

   if (typeof window !== "undefined" && window.__BKND__) {
      return {
         ...defaults,
         ...window.__BKND__,
      };
   }

   return defaults;
}
