/**
 * @file AuthFlowRouter.ts
 * Intelligent authentication flow router
 *
 * Determines the correct action for any authentication scenario:
 * - Public routes: allow access
 * - Protected routes without session: redirect to login
 * - Protected routes with session + correct role: allow access
 * - Protected routes with session + wrong role: show permission error
 */

import { routes, routeMatchers } from '@/lib/routing/RouteConfig';
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
import { SearchParamBuilder } from '@/lib/routing/search-params/SearchParamBuilder';

const logger = new ConsoleLogger();

// ============================================================================
// CORE TYPES
// ============================================================================

export interface AuthSession {
  userId: string;
  role: string;
  roles?: string[];
}

export interface LoginFlowInput {
  session: AuthSession | null;
  requestedPath: string;
}

// ============================================================================
// AUTH FLOW ROUTER
// ============================================================================

export class AuthFlowRouter {
  private readonly _session: AuthSession | null;
  private readonly _requestedPath: string;
  private readonly _isPublic: boolean;
  private readonly _requiredRoles: string[] | null;

  private constructor(session: AuthSession | null, requestedPath: string) {
    this._session = session;
    this._requestedPath = requestedPath;
    this._isPublic = routeMatchers.isPublic(requestedPath);
    this._requiredRoles = routeMatchers.requiresRole(requestedPath);
  }

  /**
   * Factory method
   */
  static create(input: LoginFlowInput): AuthFlowRouter {
    return new AuthFlowRouter(input.session, input.requestedPath);
  }

  /**
   * Check if user has required roles
   */
  private hasRequiredRoles(): boolean {
    logger.info('[AuthFlowRouter] Checking required roles', {
      hasSession: !!this._session,
      requiredRoles: this._requiredRoles,
      userRole: this._session?.role,
      userRoles: this._session?.roles
    });

    if (!this._session) {
      logger.info('[AuthFlowRouter] No session, returning false');
      return false;
    }
    
    if (!this._requiredRoles) {
      logger.info('[AuthFlowRouter] No required roles, returning true');
      return true;
    }

    const userRoles = this._session.roles || [this._session.role];
    const hasRoles = this._requiredRoles.some(role => userRoles.includes(role));
    
    logger.info('[AuthFlowRouter] Role check result', {
      userRoles,
      requiredRoles: this._requiredRoles,
      hasRoles
    });
    
    return hasRoles;
  }

  /**
   * Get the action to take - pure function
   */
  getAction(): AuthAction {
    logger.info('[AuthFlowRouter] getAction called', {
      requestedPath: this._requestedPath,
      isPublic: this._isPublic,
      hasSession: !!this._session,
      requiredRoles: this._requiredRoles
    });

    // Public route - always accessible
    if (this._isPublic) {
      logger.info('[AuthFlowRouter] Public route, showing page');
      return { type: AuthActionType.SHOW_PAGE };
    }

    // No session - must login
    if (!this._session) {
      logger.info('[AuthFlowRouter] No session, redirecting to login');
      return {
        type: AuthActionType.REDIRECT_TO_LOGIN,
        returnTo: this._requestedPath
      };
    }

    // Has session + has required roles
    if (this.hasRequiredRoles()) {
      logger.info('[AuthFlowRouter] Has required roles, redirecting to destination');
      return {
        type: AuthActionType.REDIRECT_TO_DESTINATION,
        path: this._requestedPath
      };
    }

    // Has session but missing roles
    logger.info('[AuthFlowRouter] Missing required roles, showing permission error');
    return {
      type: AuthActionType.SHOW_PERMISSION_ERROR,
      requestedPath: this._requestedPath,
      userRoles: this._session.roles || [this._session.role],
      requiredRoles: this._requiredRoles!
    };
  }

  /**
   * Get login redirect URL
   */
  getLoginRedirectUrl(): string {
    const action = this.getAction();
    if (action.type === AuthActionType.REDIRECT_TO_LOGIN) {
      return `${routes.auth.login}${SearchParamBuilder.auth(action.returnTo)}`;
    }
    if (action.type === AuthActionType.SHOW_PERMISSION_ERROR) {
      return `${routes.auth.login}${SearchParamBuilder.auth(action.requestedPath)}`;
    }
    throw new Error("Not in login redirect state");
  }

  /**
   * Get permission error message
   */
  getPermissionError(): string {
    const action = this.getAction();
    if (action.type !== AuthActionType.SHOW_PERMISSION_ERROR) {
      return `Access denied. Please log in with an account that has the required role.`;
    }
    const roleText = action.requiredRoles.join(' or ');
    return `Access denied. Requires ${roleText} role. Your roles: ${action.userRoles.join(', ')}`;
  }

  /**
   * Debug info
   */
  getDebugInfo() {
    return {
      session: this._session ? { userId: this._session.userId, role: this._session.role } : null,
      requestedPath: this._requestedPath,
      isPublic: this._isPublic,
      requiredRoles: this._requiredRoles,
      action: this.getAction()
    };
  }
}

// ============================================================================
// ACTION TYPES
// ============================================================================

export enum AuthActionType {
  SHOW_PAGE = "SHOW_PAGE",
  REDIRECT_TO_LOGIN = "REDIRECT_TO_LOGIN",
  REDIRECT_TO_DESTINATION = "REDIRECT_TO_DESTINATION",
  SHOW_PERMISSION_ERROR = "SHOW_PERMISSION_ERROR"
}

export type AuthAction =
  | { type: AuthActionType.SHOW_PAGE }
  | { type: AuthActionType.REDIRECT_TO_LOGIN; returnTo: string }
  | { type: AuthActionType.REDIRECT_TO_DESTINATION; path: string }
  | { type: AuthActionType.SHOW_PERMISSION_ERROR; requestedPath: string; userRoles: string[]; requiredRoles: string[] };

// ============================================================================
// MIDDLEWARE HELPER
// ============================================================================

export function handleAuthFlow(
  session: AuthSession | null,
  requestedPath: string
): { shouldRedirect: boolean; redirectUrl?: string; shouldShowPage?: boolean } {
  logger.info('[handleAuthFlow] Called', {
    hasSession: !!session,
    sessionRole: session?.role,
    requestedPath
  });

  const router = AuthFlowRouter.create({ session, requestedPath });
  const action = router.getAction();

  logger.info('[handleAuthFlow] Action determined', {
    actionType: action.type,
    action: JSON.stringify(action, null, 2)
  });

  switch (action.type) {
    case AuthActionType.SHOW_PAGE:
      logger.info('[handleAuthFlow] Returning SHOW_PAGE');
      return { shouldRedirect: false, shouldShowPage: true };

    case AuthActionType.REDIRECT_TO_LOGIN:
      const loginUrl = router.getLoginRedirectUrl();
      logger.info('[handleAuthFlow] Returning REDIRECT_TO_LOGIN', { loginUrl });
      return { shouldRedirect: true, redirectUrl: loginUrl };

    case AuthActionType.REDIRECT_TO_DESTINATION:
      logger.info('[handleAuthFlow] Returning REDIRECT_TO_DESTINATION');
      return { shouldRedirect: false, shouldShowPage: true };

    case AuthActionType.SHOW_PERMISSION_ERROR:
      // Redirect to user's home page instead of login (they're already logged in)
      const isAdmin = session?.role === 'admin' || 
                      session?.role === 'league-admin' || 
                      session?.role === 'system-owner' || 
                      session?.role === 'super-admin';
      
      const homeUrl = session?.role === 'sponsor' ? routes.sponsor.dashboard :
                      isAdmin ? routes.admin.root :
                      routes.protected.dashboard;
      logger.info('[handleAuthFlow] Returning SHOW_PERMISSION_ERROR, redirecting to home', { homeUrl, userRole: session?.role });
      return { shouldRedirect: true, redirectUrl: homeUrl };
  }
}
