'use client';

import { useCallback, useState } from 'react';

import { auth } from '../../_api/generated/helpers/auth';
import { CfgAccountsOauth } from '../../_api/generated/sdk.gen';
import { Analytics, AnalyticsCategory, AnalyticsEvent } from '../utils/analytics';
import { authLogger } from '../utils/logger';
import { useCfgRouter } from './useCfgRouter';

export interface UseGithubAuthOptions {
  sourceUrl?: string;
  /** Keep the completed browser session for 30 days. */
  rememberMe?: boolean;
  onSuccess?: (user: any, isNewUser: boolean) => void;
  onError?: (error: string) => void;
  /** Callback when 2FA is required */
  onRequires2FA?: (sessionId: string, shouldPrompt2FA: boolean) => void;
  redirectUrl?: string;
  /** Skip automatic redirect after success (caller handles navigation) */
  skipRedirect?: boolean;
}

export interface UseGithubAuthReturn {
  isLoading: boolean;
  error: string | null;
  startGithubAuth: () => Promise<void>;
  handleGithubCallback: (code: string, state: string) => Promise<void>;
}

/**
 * Hook for GitHub OAuth authentication flow.
 *
 * Usage:
 * 1. Call startGithubAuth() to redirect user to GitHub
 * 2. After GitHub redirects back, call handleGithubCallback(code, state)
 *
 * @example
 * ```tsx
 * const { isLoading, error, startGithubAuth } = useGithubAuth({
 *   onSuccess: (user) => router.push('/dashboard'),
 *   onError: (error) => console.error(error),
 * });
 *
 * <Button onClick={startGithubAuth} disabled={isLoading}>
 *   Continue with GitHub
 * </Button>
 * ```
 */
export const useGithubAuth = (options: UseGithubAuthOptions = {}): UseGithubAuthReturn => {
  const { sourceUrl, rememberMe = false, onSuccess, onError, onRequires2FA, redirectUrl, skipRedirect = false } = options;
  const router = useCfgRouter();

  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  /**
   * Start GitHub OAuth flow - redirects user to GitHub authorization page.
   */
  const startGithubAuth = useCallback(async () => {
    setIsLoading(true);
    setError(null);
    // Match the OTP flow: a new login must not leave an older persistent
    // session available after this browser is intentionally made session-only.
    auth.clearSession();

    try {
      authLogger.info('Starting GitHub OAuth flow...');

      // Track OAuth start
      Analytics.event(AnalyticsEvent.AUTH_OAUTH_START, {
        category: AnalyticsCategory.AUTH,
        label: 'github',
      });

      // Call API to get authorization URL
      // The API will auto-generate redirect_uri from config if not provided
      const result = await CfgAccountsOauth.cfgAccountsOauthGithubAuthorizeCreate({
        body: {
          source_url: sourceUrl || (typeof window !== 'undefined' ? window.location.href : ''),
        },
        throwOnError: true,
      });
      const response = result.data;

      if (!response.authorization_url) {
        throw new Error('Failed to get authorization URL');
      }

      authLogger.info('Redirecting to GitHub...', response.authorization_url);

      if (typeof window !== 'undefined') {
        sessionStorage.setItem('oauth_state', response.state);
        sessionStorage.setItem('oauth_provider', 'github');
        sessionStorage.setItem('cfg.oauth.remember_me', String(rememberMe));
      }

      window.location.href = response.authorization_url;

    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'Failed to start GitHub authentication';
      authLogger.error('GitHub OAuth start error:', err);
      setError(errorMessage);
      onError?.(errorMessage);

      // Track OAuth error
      Analytics.event(AnalyticsEvent.AUTH_OAUTH_FAIL, {
        category: AnalyticsCategory.AUTH,
        label: 'github',
      });
    } finally {
      setIsLoading(false);
    }
  }, [sourceUrl, rememberMe, onError]);

  /**
   * Handle GitHub OAuth callback - exchanges code for JWT tokens.
   *
   * @param code - Authorization code from GitHub callback
   * @param state - State token for CSRF verification
   */
  const handleGithubCallback = useCallback(async (code: string, state: string) => {
    setIsLoading(true);
    setError(null);

    try {
      authLogger.info('Processing GitHub OAuth callback...');

      // Verify state matches what we stored
      let rememberMeForSession = false;
      if (typeof window !== 'undefined') {
        const storedState = sessionStorage.getItem('oauth_state');
        if (storedState && storedState !== state) {
          throw new Error('Invalid OAuth state - possible CSRF attack');
        }
        rememberMeForSession = sessionStorage.getItem('cfg.oauth.remember_me') === 'true';
        // Clear stored state
        sessionStorage.removeItem('oauth_state');
        sessionStorage.removeItem('oauth_provider');
        sessionStorage.removeItem('cfg.oauth.remember_me');

      }

      const result = await CfgAccountsOauth.cfgAccountsOauthGithubCallbackCreate({
        body: { code, state, remember_me: rememberMeForSession },
        throwOnError: true,
      });
      const response = result.data;

      // Check if 2FA is required
      if (response.requires_2fa && response.session_id) {
          authLogger.info('GitHub OAuth requires 2FA, session:', response.session_id);

          // Track 2FA requirement
          Analytics.event(AnalyticsEvent.AUTH_OAUTH_START, {
            category: AnalyticsCategory.AUTH,
            label: 'github-2fa-required',
          });

          // Call 2FA callback
          onRequires2FA?.(response.session_id, response.should_prompt_2fa || false);
        return;
      }

      if (!response.access || !response.refresh) {
        throw new Error('Invalid response from OAuth callback');
      }

      authLogger.info('GitHub OAuth successful, user:', response.user);

        // The ONE write path — atomic pair + session notification. Storage is
        // always localStorage; session length is the server's call via
        // `remember_me`. See AccountsContext.verifyOTP.
      auth.setSession({ access: response.access, refresh: response.refresh });

        // Track successful OAuth
      Analytics.event(AnalyticsEvent.AUTH_LOGIN_SUCCESS, {
          category: AnalyticsCategory.AUTH,
          label: 'github',
      });

        // Set user ID for future tracking
      if (response.user?.id) {
        Analytics.setUser(String(response.user.id));
      }

        // Call success callback
      onSuccess?.(response.user, response.is_new_user || false);

        // Redirect (unless skipRedirect is true)
      if (!skipRedirect) {
          // Use hardPush for full page reload - ensures all React contexts reinitialize
        const finalRedirectUrl = redirectUrl || '/private';
        router.hardPush(finalRedirectUrl);
      }

      return;

    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'GitHub authentication failed';
      authLogger.error('GitHub OAuth callback error:', err);
      setError(errorMessage);
      onError?.(errorMessage);

      // Track OAuth error
      Analytics.event(AnalyticsEvent.AUTH_OAUTH_FAIL, {
        category: AnalyticsCategory.AUTH,
        label: 'github',
      });
    } finally {
      setIsLoading(false);
    }
  }, [onSuccess, onError, onRequires2FA, redirectUrl, router, skipRedirect]);

  return {
    isLoading,
    error,
    startGithubAuth,
    handleGithubCallback,
  };
};
