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

/**
 * Auth Guard with Enhanced Security
 *
 * Security features:
 * - Validates token existence AND validity
 * - Checks token expiration
 * - Handles race conditions with auth state
 * - Provides secure return URL handling
 */
export const authGuard: CanActivateFn = (route, state) => {
  const authService = inject(AuthService);
  const storage = inject(StorageService);
  const router = inject(Router);

  // Check both signal state AND actual token validity
  const token = storage.getToken();

  if (!token) {
    // No token - redirect to login
    router.navigate(['/login'], {
      queryParams: { returnUrl: sanitizeReturnUrl(state.url) },
    });
    return false;
  }

  // Validate token
  const validation = TokenValidator.validate(token);

  if (!validation.valid) {
    // Invalid or expired token - clear auth state and redirect
    console.warn('Auth guard: Token validation failed -', validation.error);
    authService.logout();
    router.navigate(['/login'], {
      queryParams: {
        returnUrl: sanitizeReturnUrl(state.url),
        reason: validation.error === 'Token has expired' ? 'session_expired' : 'invalid_session',
      },
    });
    return false;
  }

  // Verify auth service state matches token state
  if (!authService.isAuthenticated()) {
    // Token exists but auth state says not authenticated
    // This could be a race condition - try to restore state
    console.warn('Auth guard: State mismatch, attempting recovery');
    // The auth service constructor should handle this on next check
  }

  return true;
};

/**
 * Guest Guard - Only allows unauthenticated users
 */
export const guestGuard: CanActivateFn = (route, state) => {
  const authService = inject(AuthService);
  const storage = inject(StorageService);
  const router = inject(Router);

  const token = storage.getToken();

  // Check if there's a valid token
  if (token && TokenValidator.validate(token).valid) {
    router.navigate(['/dashboard']);
    return false;
  }

  // If token exists but is invalid, clear it
  if (token && !TokenValidator.validate(token).valid) {
    storage.clear();
  }

  return true;
};

/**
 * Sanitize return URL to prevent open redirect attacks
 */
function sanitizeReturnUrl(url: string): string {
  if (!url || typeof url !== 'string') {
    return '/dashboard';
  }

  // Only allow relative URLs
  if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith('//')) {
    return '/dashboard';
  }

  // Ensure URL starts with /
  if (!url.startsWith('/')) {
    return '/dashboard';
  }

  // Check for encoded characters that could bypass validation
  const decodedUrl = decodeURIComponent(url);
  if (decodedUrl !== url && (decodedUrl.includes('://') || decodedUrl.startsWith('//'))) {
    return '/dashboard';
  }

  // Block javascript: and data: URLs
  const lowerUrl = url.toLowerCase();
  if (lowerUrl.includes('javascript:') || lowerUrl.includes('data:')) {
    return '/dashboard';
  }

  return url;
}
