import type { ISbStoriesParams } from './interfaces';
import { DEFAULT_PER_PAGE, PER_PAGE_THRESHOLDS } from './constants';

export interface RateLimitConfig {
  // User-provided rate limit
  userRateLimit?: number;
  // Rate limit determined from server response headers
  serverHeadersRateLimit?: number;
  // Whether this is a Management API client (uses oauthToken)
  isManagementApi?: boolean;
}

export interface RateLimitHeaders {
  remaining?: number;
  max?: number;
}

/**
 * Rate limit tiers based on per_page parameter
 * These limits apply to all CDN API requests regardless of version
 */
const RATE_LIMIT_TIERS = {
  SINGLE_OR_SMALL: 50, // Single entries or listings ≤25 entries
  MEDIUM: 15, // 26-50 entries
  LARGE: 10, // 51-75 entries
  VERY_LARGE: 6, // 76-100 entries
} as const;

/**
 * Maximum rate limit that should never be exceeded
 */
const MAX_RATE_LIMIT = 1000;

/**
 * Default rate limit for Management API (when using oauthToken)
 */
export const MANAGEMENT_API_DEFAULT_RATE_LIMIT = 3;

/**
 * Determines if a request is for a single story based on URL and params
 */
function isSingleStoryRequest(url: string, params: ISbStoriesParams): boolean {
  // Single story requests typically have a specific story slug/id in the URL
  // or use find_by parameter
  const isCdnStories = url.includes('/cdn/stories/');
  const hasSpecificPath = url.split('/').length > 3 && !url.endsWith('/cdn/stories');
  const hasFindBy = 'find_by' in params;

  return (isCdnStories && hasSpecificPath) || hasFindBy;
}

/**
 * Calculates the appropriate rate limit tier based on the per_page parameter
 * These tiers match the backend rate limiting logic
 */
function getRateLimitTier(perPage: number): number {
  if (perPage <= PER_PAGE_THRESHOLDS.SMALL) {
    return RATE_LIMIT_TIERS.SINGLE_OR_SMALL;
  }
  else if (perPage <= PER_PAGE_THRESHOLDS.MEDIUM) {
    return RATE_LIMIT_TIERS.MEDIUM;
  }
  else if (perPage <= PER_PAGE_THRESHOLDS.LARGE) {
    return RATE_LIMIT_TIERS.LARGE;
  }
  else {
    return RATE_LIMIT_TIERS.VERY_LARGE;
  }
}

/**
 * Determines the appropriate rate limit for a request based on:
 * - Request type (single vs listing)
 * - Number of entries (per_page)
 * - User configuration
 * - Server headers
 *
 * Rate limits are based on per_page regardless of version (draft/published).
 * The backend enforces per_page-based rate limits on ALL requests before
 * checking the cache, so cached requests still count against rate limits.
 *
 * When url and params are not provided (Management API), uses the defaultRateLimit
 * as the fallback instead of automatic tier calculation.
 */
export function determineRateLimit(
  url?: string,
  params?: ISbStoriesParams,
  config: RateLimitConfig = {},
  defaultRateLimit?: number,
): number {
  // Priority order for all requests:
  // 1. User-provided rate limit (highest priority, applies to all requests)
  // 2. Server-provided rate limit (from response headers)
  // 3. Default rate limit (Management API)
  // 4. Automatic tier calculation based on per_page (CDN)

  if (config.userRateLimit !== undefined) {
    return Math.min(config.userRateLimit, MAX_RATE_LIMIT);
  }

  if (config.serverHeadersRateLimit !== undefined) {
    return Math.min(config.serverHeadersRateLimit, MAX_RATE_LIMIT);
  }

  // If a default rate limit is provided (Management API), use it
  if (defaultRateLimit !== undefined) {
    return defaultRateLimit;
  }

  // For CDN API, calculate based on request type and per_page
  // At this point, url and params should be defined for CDN API calls
  if (!url || !params) {
    return RATE_LIMIT_TIERS.SINGLE_OR_SMALL;
  }

  // Single story requests
  if (isSingleStoryRequest(url, params)) {
    return RATE_LIMIT_TIERS.SINGLE_OR_SMALL;
  }

  // For listings, determine tier based on per_page
  const perPage = params.per_page || DEFAULT_PER_PAGE;
  return getRateLimitTier(perPage);
}

/**
 * Parses X-RateLimit and X-RateLimit-Policy headers from the response
 *
 * Example headers:
 * X-RateLimit: "concurrent-requests";r=29
 * X-RateLimit-Policy: "concurrent-requests";q=30
 *
 * Where:
 * - r = remaining requests
 * - q = maximum requests allowed (quota)
 */
export function parseRateLimitHeaders(headers: any): RateLimitHeaders | null {
  if (!headers) {
    return null;
  }

  const rateLimitHeader = headers['x-ratelimit'] || headers['X-RateLimit'];
  const rateLimitPolicyHeader = headers['x-ratelimit-policy'] || headers['X-RateLimit-Policy'];

  if (!rateLimitHeader && !rateLimitPolicyHeader) {
    return null;
  }

  const result: RateLimitHeaders = {};

  // Parse remaining from X-RateLimit header
  if (rateLimitHeader) {
    const remainingMatch = rateLimitHeader.match(/r=(\d+)/);
    if (remainingMatch) {
      result.remaining = Number.parseInt(remainingMatch[1], 10);
    }
  }

  // Parse max from X-RateLimit-Policy header
  if (rateLimitPolicyHeader) {
    const maxMatch = rateLimitPolicyHeader.match(/q=(\d+)/);
    if (maxMatch) {
      result.max = Number.parseInt(maxMatch[1], 10);
    }
  }

  return Object.keys(result).length > 0 ? result : null;
}

/**
 * Creates a rate limit configuration object
 */
export function createRateLimitConfig(userRateLimit?: number, isManagementApi = false): RateLimitConfig {
  return {
    userRateLimit,
    serverHeadersRateLimit: undefined,
    isManagementApi,
  };
}
