import type {
  RateLimitConfig,
  BackoffConfig,
  HttpConfig,
  SegmentAPISettings,
  SegmentAPIIntegrations,
  LoggerType,
  DeepPartial,
} from './types';
import { defaultHttpConfig } from './constants';

export const validateRateLimitConfig = (
  config: RateLimitConfig,
  logger?: LoggerType
): RateLimitConfig => {
  const validated = { ...config };

  if (validated.maxRetryInterval < 0.1) {
    logger?.warn(
      `maxRetryInterval ${validated.maxRetryInterval}s clamped to 0.1s`
    );
    validated.maxRetryInterval = 0.1;
  } else if (validated.maxRetryInterval > 86400) {
    logger?.warn(
      `maxRetryInterval ${validated.maxRetryInterval}s clamped to 86400s`
    );
    validated.maxRetryInterval = 86400;
  }

  if (validated.maxRateLimitDuration < 60) {
    logger?.warn(
      `maxRateLimitDuration ${validated.maxRateLimitDuration}s clamped to 60s`
    );
    validated.maxRateLimitDuration = 60;
  } else if (validated.maxRateLimitDuration > 604800) {
    logger?.warn(
      `maxRateLimitDuration ${validated.maxRateLimitDuration}s clamped to 604800s`
    );
    validated.maxRateLimitDuration = 604800;
  }

  if (validated.maxRetryCount < 1) {
    logger?.warn(`maxRetryCount ${validated.maxRetryCount} clamped to 1`);
    validated.maxRetryCount = 1;
  } else if (validated.maxRetryCount > 100) {
    logger?.warn(`maxRetryCount ${validated.maxRetryCount} clamped to 100`);
    validated.maxRetryCount = 100;
  }

  // Relational: maxRateLimitDuration >= 2x maxRetryInterval
  const minRateLimitDuration = validated.maxRetryInterval * 2;
  if (validated.maxRateLimitDuration < minRateLimitDuration) {
    logger?.warn(
      `maxRateLimitDuration ${validated.maxRateLimitDuration}s clamped to ${minRateLimitDuration}s (2x maxRetryInterval)`
    );
    validated.maxRateLimitDuration = minRateLimitDuration;
  }

  return validated;
};

export const validateBackoffConfig = (
  config: BackoffConfig,
  logger?: LoggerType,
  rateLimitConfig?: RateLimitConfig
): BackoffConfig => {
  const validated = { ...config };

  if (validated.maxBackoffInterval < 0.1) {
    logger?.warn(
      `maxBackoffInterval ${validated.maxBackoffInterval}s clamped to 0.1s`
    );
    validated.maxBackoffInterval = 0.1;
  } else if (validated.maxBackoffInterval > 86400) {
    logger?.warn(
      `maxBackoffInterval ${validated.maxBackoffInterval}s clamped to 86400s`
    );
    validated.maxBackoffInterval = 86400;
  }

  if (validated.baseBackoffInterval < 0.1) {
    logger?.warn(
      `baseBackoffInterval ${validated.baseBackoffInterval}s clamped to 0.1s`
    );
    validated.baseBackoffInterval = 0.1;
  } else if (validated.baseBackoffInterval > 300) {
    logger?.warn(
      `baseBackoffInterval ${validated.baseBackoffInterval}s clamped to 300s`
    );
    validated.baseBackoffInterval = 300;
  }

  if (validated.maxTotalBackoffDuration < 60) {
    logger?.warn(
      `maxTotalBackoffDuration ${validated.maxTotalBackoffDuration}s clamped to 60s`
    );
    validated.maxTotalBackoffDuration = 60;
  } else if (validated.maxTotalBackoffDuration > 604800) {
    logger?.warn(
      `maxTotalBackoffDuration ${validated.maxTotalBackoffDuration}s clamped to 604800s`
    );
    validated.maxTotalBackoffDuration = 604800;
  }

  if (validated.jitterPercent < 0) {
    logger?.warn(`jitterPercent ${validated.jitterPercent} clamped to 0`);
    validated.jitterPercent = 0;
  } else if (validated.jitterPercent > 100) {
    logger?.warn(`jitterPercent ${validated.jitterPercent} clamped to 100`);
    validated.jitterPercent = 100;
  }

  if (validated.maxRetryCount < 1) {
    logger?.warn(`maxRetryCount ${validated.maxRetryCount} clamped to 1`);
    validated.maxRetryCount = 1;
  } else if (validated.maxRetryCount > 100) {
    logger?.warn(`maxRetryCount ${validated.maxRetryCount} clamped to 100`);
    validated.maxRetryCount = 100;
  }

  // Relational: baseBackoffInterval <= maxBackoffInterval
  if (validated.baseBackoffInterval > validated.maxBackoffInterval) {
    logger?.warn(
      `baseBackoffInterval ${validated.baseBackoffInterval}s clamped to maxBackoffInterval ${validated.maxBackoffInterval}s`
    );
    validated.baseBackoffInterval = validated.maxBackoffInterval;
  }

  // Relational: maxTotalBackoffDuration >= 2x max(maxBackoffInterval, rateLimitConfig.maxRetryInterval)
  const maxInterval = Math.max(
    validated.maxBackoffInterval,
    rateLimitConfig?.maxRetryInterval ?? 0
  );
  const minTotalDuration = maxInterval * 2;
  if (validated.maxTotalBackoffDuration < minTotalDuration) {
    logger?.warn(
      `maxTotalBackoffDuration ${validated.maxTotalBackoffDuration}s clamped to ${minTotalDuration}s (2x max interval)`
    );
    validated.maxTotalBackoffDuration = minTotalDuration;
  }

  return validated;
};

/**
 * Validates and normalizes integrations from CDN response.
 * Returns null if integrations are malformed (triggers fallback to defaults).
 */
export const validateIntegrations = (
  settings: SegmentAPISettings,
  logger?: LoggerType
): SegmentAPIIntegrations | null => {
  // A valid 200 with missing integrations means "no integrations configured"
  if (settings.integrations == null) {
    return {};
  }

  // Only fall back to defaults for truly malformed types (non-object or array)
  if (
    typeof settings.integrations !== 'object' ||
    Array.isArray(settings.integrations)
  ) {
    logger?.warn(
      'CDN response has invalid integrations, falling back to defaults'
    );
    return null;
  }

  return settings.integrations;
};

/**
 * Extracts, merges, and validates httpConfig from CDN response.
 * Deep-merges with defaults and validates all values.
 */
export const extractHttpConfig = (
  serverConfig: HttpConfig,
  logger?: LoggerType
): HttpConfig => {
  const mergedRateLimit = serverConfig.rateLimitConfig
    ? {
        ...defaultHttpConfig.rateLimitConfig!,
        ...serverConfig.rateLimitConfig,
      }
    : defaultHttpConfig.rateLimitConfig!;

  const mergedBackoff = serverConfig.backoffConfig
    ? {
        ...defaultHttpConfig.backoffConfig!,
        ...serverConfig.backoffConfig,
        statusCodeOverrides: {
          ...defaultHttpConfig.backoffConfig!.statusCodeOverrides,
          ...serverConfig.backoffConfig.statusCodeOverrides,
        },
      }
    : defaultHttpConfig.backoffConfig!;

  const validatedRateLimit = validateRateLimitConfig(mergedRateLimit, logger);
  return {
    rateLimitConfig: validatedRateLimit,
    backoffConfig: validateBackoffConfig(
      mergedBackoff,
      logger,
      validatedRateLimit
    ),
  };
};

/**
 * Merge httpConfig from 3 sources with priority: default < CDN < client overrides
 * Used during settings initialization to combine default, CDN, and user configs.
 */
export const mergeHttpConfig = (
  cdnConfig: HttpConfig | undefined,
  clientConfig: DeepPartial<HttpConfig> | undefined,
  logger?: LoggerType
): HttpConfig => {
  const mergedRateLimit = {
    ...defaultHttpConfig.rateLimitConfig!,
    ...(cdnConfig?.rateLimitConfig ?? {}),
    ...(clientConfig?.rateLimitConfig ?? {}),
  };

  const mergedBackoff = {
    ...defaultHttpConfig.backoffConfig!,
    ...(cdnConfig?.backoffConfig ?? {}),
    ...(clientConfig?.backoffConfig ?? {}),
    statusCodeOverrides: {
      ...defaultHttpConfig.backoffConfig!.statusCodeOverrides,
      ...(cdnConfig?.backoffConfig?.statusCodeOverrides ?? {}),
      ...(clientConfig?.backoffConfig?.statusCodeOverrides ?? {}),
    },
  };

  const validatedRateLimit = validateRateLimitConfig(mergedRateLimit, logger);
  return {
    rateLimitConfig: validatedRateLimit,
    backoffConfig: validateBackoffConfig(
      mergedBackoff,
      logger,
      validatedRateLimit
    ),
  };
};
