import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
  type ReactNode,
} from 'react';
import { stripOAuthParamsFromLocation } from '@dukang/weixin-sdk';
import { isWxAuthorizeEnabled } from '@dukang/shared-types';
import {
  clearAuth,
  ensureSession,
  saveAuth,
  type ShopSessionPayload,
  type StoreSessionStore,
} from '../lib/api';
import {
  fetchClientConfig,
  handleShopWechatCallback,
  handleShopWechatCallbackOnce,
  handleShopWechatLoginResult,
  isShopWechatUnboundError,
  SHOP_WX_NEED_PHONE_LOGIN_MSG,
  stashShopWechatLoginHint,
} from '../lib/wechat-auth';
import { isWechatEnv } from '../lib/weixin';

type StoreSessionContextValue = {
  ready: boolean;
  authenticated: boolean;
  needsSelectStore: boolean;
  store: StoreSessionStore | null;
  applySession: (session: ShopSessionPayload) => void;
  resetSession: () => void;
};

const StoreSessionContext = createContext<StoreSessionContextValue | null>(null);

function deriveSelectStore(session: ShopSessionPayload, nextStore: StoreSessionStore | null) {
  const storeId = nextStore?.storeId || session.selectedStoreId || '';
  const stores = session.stores ?? nextStore?.stores ?? [];
  return stores.length > 1 && !storeId;
}

export function StoreSessionProvider({ children }: { children: ReactNode }) {
  const [ready, setReady] = useState(false);
  const [authenticated, setAuthenticated] = useState(false);
  const [needsSelectStore, setNeedsSelectStore] = useState(false);
  const [store, setStore] = useState<StoreSessionStore | null>(null);

  const applySession = useCallback((session: ShopSessionPayload) => {
    saveAuth(session);
    setAuthenticated(true);
    const nextStore = session.store
      ? {
          ...session.store,
          stores: session.stores ?? session.store.stores,
          isPrimary: session.account?.isPrimary ?? session.store.isPrimary,
        }
      : null;
    setStore(nextStore);
    setNeedsSelectStore(deriveSelectStore(session, nextStore));
  }, []);

  const resetSession = useCallback(() => {
    clearAuth();
    setAuthenticated(false);
    setNeedsSelectStore(false);
    setStore(null);
  }, []);

  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const params = new URLSearchParams(window.location.search);
        if (isWechatEnv() && params.get('code')) {
          try {
            const config = await fetchClientConfig();
            if (isWxAuthorizeEnabled(config)) {
              const result = await handleShopWechatCallbackOnce();
              if (result && !cancelled) {
                const session = handleShopWechatLoginResult(result);
                if (session) applySession(session);
              }
              stripOAuthParamsFromLocation();
            }
          } catch (e) {
            const raw = e instanceof Error ? e.message : '';
            if (isShopWechatUnboundError(raw)) {
              stashShopWechatLoginHint(SHOP_WX_NEED_PHONE_LOGIN_MSG);
            }
            stripOAuthParamsFromLocation();
          }
        }

        const result = await ensureSession();
        if (cancelled) return;
        setAuthenticated(result.authenticated);
        setStore(result.store);
        setNeedsSelectStore(result.needsSelectStore);
      } catch {
        if (!cancelled) resetSession();
      } finally {
        if (!cancelled) setReady(true);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [applySession, resetSession]);

  const value = useMemo(
    () => ({ ready, authenticated, needsSelectStore, store, applySession, resetSession }),
    [ready, authenticated, needsSelectStore, store, applySession, resetSession],
  );

  return <StoreSessionContext.Provider value={value}>{children}</StoreSessionContext.Provider>;
}

export function useStoreSession() {
  const ctx = useContext(StoreSessionContext);
  if (!ctx) throw new Error('useStoreSession must be used within StoreSessionProvider');
  return ctx;
}
