import { inject } from '@angular/core';
import { Router, CanActivateFn } from '@angular/router';
import { AuthService, UserType } from '../services/auth.service';
import { StorageService } from '../services/storage.service';
import { NotificationService } from '../services/notification.service';
import { TokenValidator } from '../utils/token-validator';

/**
 * Helper to verify token before role check
 * Prevents role bypass by ensuring valid authentication first
 */
function verifyTokenFirst(): { valid: boolean; authService: AuthService; router: Router; notification: NotificationService } {
  const authService = inject(AuthService);
  const storage = inject(StorageService);
  const router = inject(Router);
  const notification = inject(NotificationService);

  const token = storage.getToken();

  // Must have valid token first
  if (!token || !TokenValidator.validate(token).valid) {
    storage.clear();
    router.navigate(['/login'], { queryParams: { reason: 'invalid_session' } });
    return { valid: false, authService, router, notification };
  }

  return { valid: true, authService, router, notification };
}

/**
 * Role Guard - Checks if user has required role(s)
 *
 * Security: Validates token before checking role
 */
export const roleGuard: CanActivateFn = (route, state) => {
  const { valid, authService, router, notification } = verifyTokenFirst();

  if (!valid) {
    return false;
  }

  const requiredRoles = route.data['roles'] as UserType[] | undefined;

  // Validate roles data is properly typed
  if (requiredRoles && !Array.isArray(requiredRoles)) {
    console.error('Role guard: Invalid roles configuration');
    return false;
  }

  if (!requiredRoles || requiredRoles.length === 0) {
    return true;
  }

  // Validate each role is a valid UserType
  const validRoles: UserType[] = ['ADMIN', 'DEPARTMENT', 'APPLICANT'];
  const sanitizedRoles = requiredRoles.filter((role) => validRoles.includes(role));

  if (sanitizedRoles.length !== requiredRoles.length) {
    console.error('Role guard: Invalid role types in configuration');
  }

  if (authService.hasAnyRole(sanitizedRoles)) {
    return true;
  }

  notification.error('You do not have permission to access this page.');
  router.navigate(['/dashboard']);
  return false;
};

/**
 * Department Guard - Only allows department users
 */
export const departmentGuard: CanActivateFn = (route, state) => {
  const { valid, authService, router, notification } = verifyTokenFirst();

  if (!valid) {
    return false;
  }

  if (authService.isDepartment()) {
    return true;
  }

  notification.error('This page is only accessible to department users.');
  router.navigate(['/dashboard']);
  return false;
};

/**
 * Applicant Guard - Only allows applicant users
 */
export const applicantGuard: CanActivateFn = (route, state) => {
  const { valid, authService, router, notification } = verifyTokenFirst();

  if (!valid) {
    return false;
  }

  if (authService.isApplicant()) {
    return true;
  }

  notification.error('This page is only accessible to applicants.');
  router.navigate(['/dashboard']);
  return false;
};

/**
 * Admin Guard - Only allows admin users
 *
 * Note: Admin access is most sensitive - extra validation
 */
export const adminGuard: CanActivateFn = (route, state) => {
  const { valid, authService, router, notification } = verifyTokenFirst();

  if (!valid) {
    return false;
  }

  // Trust the auth service signal - it's set from the validated API response
  // Note: localStorage checks removed due to race condition issues with storage events
  if (authService.isAdmin()) {
    console.log('[ADMIN GUARD] Access granted - user is admin');
    return true;
  }

  console.log('[ADMIN GUARD] Access denied - isAdmin():', authService.isAdmin());
  notification.error('This page is only accessible to administrators.');
  router.navigate(['/dashboard']);
  return false;
};
