import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { catchError, throwError, timer, retry } from 'rxjs';
import { StorageService } from '../services/storage.service';
import { NotificationService } from '../services/notification.service';

// Retry configuration
const MAX_RETRY_COUNT = 2;
const RETRY_DELAY_MS = 1000;

/**
 * Error Interceptor with Security Enhancements
 *
 * Security features:
 * - Proper handling of auth-related errors (401, 403)
 * - Rate limiting detection (429)
 * - Sanitized error messages to prevent information leakage
 * - Secure redirect on authentication failures
 */
export const errorInterceptor: HttpInterceptorFn = (req, next) => {
  const router = inject(Router);
  const storage = inject(StorageService);
  const notification = inject(NotificationService);

  return next(req).pipe(
    // Retry logic for transient errors (5xx and 429)
    retry({
      count: MAX_RETRY_COUNT,
      delay: (error, retryCount) => {
        // Only retry for 429 (rate limiting) or 5xx errors
        if (error.status === 429 || (error.status >= 500 && error.status < 600)) {
          // Exponential backoff
          const delay = RETRY_DELAY_MS * Math.pow(2, retryCount - 1);
          return timer(delay);
        }
        // Don't retry for other errors
        return throwError(() => error);
      },
    }),
    catchError((error: HttpErrorResponse) => {
      let errorMessage = 'An unexpected error occurred';
      let shouldClearAuth = false;
      let redirectToLogin = false;
      let redirectReason: string | undefined;

      if (error.status === 0) {
        // Network error or CORS issue
        errorMessage = 'Unable to connect to server. Please check your internet connection.';
      } else if (error.error instanceof ErrorEvent) {
        // Client-side error - sanitize message
        errorMessage = sanitizeErrorMessage(error.error.message) || 'Network error occurred.';
      } else {
        // Server-side error
        switch (error.status) {
          case 401:
            errorMessage = 'Session expired. Please login again.';
            shouldClearAuth = true;
            redirectToLogin = true;
            redirectReason = 'session_expired';
            break;

          case 403:
            errorMessage = 'You do not have permission to perform this action.';
            // Check if this is a security violation
            if (error.error?.code === 'FORBIDDEN' || error.error?.code === 'ACCESS_DENIED') {
              console.warn('Security: Access denied for request to', req.url);
            }
            break;

          case 404:
            errorMessage = 'Resource not found.';
            break;

          case 422:
            // Validation error - sanitize server message
            errorMessage = sanitizeErrorMessage(error.error?.message) || 'Validation error.';
            break;

          case 429:
            // Rate limiting
            errorMessage = 'Too many requests. Please wait a moment and try again.';
            console.warn('Security: Rate limit exceeded for', req.url);
            break;

          case 500:
            errorMessage = 'Internal server error. Please try again later.';
            // Don't expose internal server errors
            break;

          case 502:
          case 503:
          case 504:
            errorMessage = 'Service temporarily unavailable. Please try again later.';
            break;

          default:
            // Don't expose raw error messages for unknown errors
            errorMessage = error.status >= 400 && error.status < 500
              ? 'Request could not be processed.'
              : 'An unexpected error occurred.';
        }
      }

      // Clear auth state if needed
      if (shouldClearAuth) {
        storage.clear();
      }

      // Redirect to login if needed
      if (redirectToLogin) {
        router.navigate(['/login'], {
          queryParams: redirectReason ? { reason: redirectReason } : undefined,
        });
      }

      // Show notification (except for certain cases)
      if (!shouldSuppressNotification(error)) {
        notification.error(errorMessage);
      }

      return throwError(() => error);
    })
  );
};

/**
 * Sanitize error messages to prevent XSS and information leakage
 */
function sanitizeErrorMessage(message: string | undefined): string {
  if (!message || typeof message !== 'string') {
    return '';
  }

  // Remove HTML tags
  let sanitized = message.replace(/<[^>]*>/g, '');

  // Remove potential stack traces or file paths
  sanitized = sanitized.replace(/at\s+[\w\.]+\s+\([^)]+\)/g, '');
  sanitized = sanitized.replace(/\/[\w\/\.]+\.(ts|js|html)/g, '');

  // Remove SQL or code snippets
  sanitized = sanitized.replace(/SELECT|INSERT|UPDATE|DELETE|FROM|WHERE/gi, '');

  // Truncate long messages
  if (sanitized.length > 200) {
    sanitized = sanitized.substring(0, 200) + '...';
  }

  return sanitized.trim();
}

/**
 * Determine if notification should be suppressed
 */
function shouldSuppressNotification(error: HttpErrorResponse): boolean {
  // Suppress for cancelled requests (status 0 with Unknown Error)
  if (error.status === 0 && error.statusText === 'Unknown Error') {
    return true;
  }

  // Suppress for aborted requests (check error message as well)
  if (error.message?.includes('abort') || error.message?.includes('cancel')) {
    return true;
  }

  return false;
}
