/**
 * Bandwidth estimation utility functions
 */

import type { BandwidthEstimate, BandwidthInfo, UseCaseConfig } from '../types';
import { USE_CASE_CONFIGS } from '../config';

/**
 * Find use case configuration by matching patterns
 */
export function findUseCaseConfig(useCase: string): UseCaseConfig {
  const useCaseLower = useCase.toLowerCase();

  for (const config of USE_CASE_CONFIGS) {
    if (config.patterns.test(useCaseLower)) {
      return config;
    }
  }

  // Default configuration
  return {
    category: 'default',
    patterns: /.*/,
    dauMultiplier: { min: 10, max: 14 },
    activeRatio: 0.5,
    cdnCacheHitRate: 0.50  // 기본값: 50%
  };
}

/**
 * Get CDN cache hit rate based on use case
 * Returns default rate for the use case category
 */
export function getCdnCacheHitRate(useCase: string): number {
  return findUseCaseConfig(useCase).cdnCacheHitRate;
}

/**
 * Get DAU multiplier based on use case (how many daily active users per concurrent user)
 */
export function getDauMultiplier(useCase: string): { min: number; max: number } {
  return findUseCaseConfig(useCase).dauMultiplier;
}

/**
 * Get active user ratio (what percentage of DAU actually performs the bandwidth-heavy action)
 */
export function getActiveUserRatio(useCase: string): number {
  return findUseCaseConfig(useCase).activeRatio;
}

export interface CdnOptions {
  enabled?: boolean;        // CDN 사용 여부 (기본: true)
  cacheHitRate?: number;    // 캐시 히트율 override (0.0-1.0)
}

/**
 * Estimate monthly bandwidth based on concurrent users and use case
 * @param concurrentUsers Expected concurrent users
 * @param useCase Use case description
 * @param trafficPattern Traffic pattern (steady, spiky, growing)
 * @param cdnOptions CDN configuration options
 */
export function estimateBandwidth(
  concurrentUsers: number,
  useCase: string,
  trafficPattern?: string,
  cdnOptions?: CdnOptions
): BandwidthEstimate {
  const useCaseLower = useCase.toLowerCase();

  // Get use case configuration
  const config = findUseCaseConfig(useCase);
  const useCaseCategory = config.category;

  // Calculate DAU estimate from concurrent users with use-case-specific multipliers
  const dauMultiplier = config.dauMultiplier;
  const estimatedDauMin = Math.round(concurrentUsers * dauMultiplier.min);
  const estimatedDauMax = Math.round(concurrentUsers * dauMultiplier.max);
  const dailyUniqueVisitors = Math.round((estimatedDauMin + estimatedDauMax) / 2);
  const activeUserRatio = config.activeRatio;
  const activeDau = Math.round(dailyUniqueVisitors * activeUserRatio);

  // Traffic pattern adjustment
  let patternMultiplier = 1.0;
  if (trafficPattern === 'spiky') {
    patternMultiplier = 1.5; // Account for peak loads
  } else if (trafficPattern === 'growing') {
    patternMultiplier = 1.3; // Headroom for growth
  }

  let dailyBandwidthGB: number;
  let bandwidthModel: string;

  // ========== IMPROVED BANDWIDTH MODELS ==========
  // Each use case uses the most appropriate calculation method

  switch (useCaseCategory) {
    case 'video': {
      // VIDEO/STREAMING: Bitrate-based model
      const is4K = /4k|uhd|ultra/i.test(useCaseLower);
      const bitrateGBperHour = is4K ? 11.25 : 2.25; // 4K vs HD
      const avgWatchTimeHours = is4K ? 1.0 : 1.5;
      const gbPerActiveUser = bitrateGBperHour * avgWatchTimeHours;
      dailyBandwidthGB = activeDau * gbPerActiveUser * patternMultiplier;
      bandwidthModel = `bitrate-based: ${activeDau} active × ${bitrateGBperHour} GB/hr × ${avgWatchTimeHours}hr`;
      break;
    }

    case 'file': {
      // FILE DOWNLOAD: File-size based model
      const isLargeFiles = /iso|video|backup|대용량/.test(useCaseLower);
      const avgFileSizeGB = isLargeFiles ? 2.0 : 0.2;
      const downloadsPerUser = isLargeFiles ? 1 : 3;
      const gbPerActiveUser = avgFileSizeGB * downloadsPerUser;
      dailyBandwidthGB = activeDau * gbPerActiveUser * patternMultiplier;
      bandwidthModel = `file-based: ${activeDau} active × ${avgFileSizeGB} GB × ${downloadsPerUser} downloads`;
      break;
    }

    case 'gaming': {
      // GAMING: Session-duration based model
      const isMinecraft = /minecraft|마인크래프트/.test(useCaseLower);
      const mbPerHour = isMinecraft ? 150 : 80;
      const avgSessionHours = isMinecraft ? 3 : 2.5;
      const gbPerActiveUser = (mbPerHour * avgSessionHours) / 1024;
      dailyBandwidthGB = activeDau * gbPerActiveUser * patternMultiplier;
      bandwidthModel = `session-based: ${activeDau} active × ${mbPerHour} MB/hr × ${avgSessionHours}hr`;
      break;
    }

    case 'api': {
      // API/SAAS: Request-based model
      const avgRequestKB = 20;
      const requestsPerUserPerDay = 1000;
      const gbPerActiveUser = (avgRequestKB * requestsPerUserPerDay) / (1024 * 1024);
      dailyBandwidthGB = activeDau * gbPerActiveUser * patternMultiplier;
      bandwidthModel = `request-based: ${activeDau} active × ${avgRequestKB}KB × ${requestsPerUserPerDay} req`;
      break;
    }

    case 'ecommerce': {
      // E-COMMERCE: Page-based model (images heavy)
      const avgPageSizeMB = 2.5;
      const pagesPerSession = 20;
      const gbPerActiveUser = (avgPageSizeMB * pagesPerSession) / 1024;
      dailyBandwidthGB = activeDau * gbPerActiveUser * patternMultiplier;
      bandwidthModel = `page-based: ${activeDau} active × ${avgPageSizeMB}MB × ${pagesPerSession} pages`;
      break;
    }

    case 'forum': {
      // FORUM/COMMUNITY: Page-based model (text + some images)
      const avgPageSizeMB = 0.7;
      const pagesPerSession = 30;
      const gbPerActiveUser = (avgPageSizeMB * pagesPerSession) / 1024;
      dailyBandwidthGB = activeDau * gbPerActiveUser * patternMultiplier;
      bandwidthModel = `page-based: ${activeDau} active × ${avgPageSizeMB}MB × ${pagesPerSession} pages`;
      break;
    }

    case 'blog': {
      // STATIC/BLOG: Lightweight page-based model
      const avgPageSizeMB = 1.5;
      const pagesPerSession = 4;
      const gbPerActiveUser = (avgPageSizeMB * pagesPerSession) / 1024;
      dailyBandwidthGB = activeDau * gbPerActiveUser * patternMultiplier;
      bandwidthModel = `page-based: ${activeDau} active × ${avgPageSizeMB}MB × ${pagesPerSession} pages`;
      break;
    }

    case 'chat': {
      // CHAT/MESSAGING: Message-based model
      const textBandwidthMB = (3 * 200) / 1024; // 3KB × 200 messages
      const attachmentBandwidthMB = 20; // occasional images/files
      const gbPerActiveUser = (textBandwidthMB + attachmentBandwidthMB) / 1024;
      dailyBandwidthGB = activeDau * gbPerActiveUser * patternMultiplier;
      bandwidthModel = `message-based: ${activeDau} active × ~20MB/user (text+attachments)`;
      break;
    }

    default: {
      // DEFAULT: General web app (page-based)
      const avgPageSizeMB = 1.0;
      const pagesPerSession = 10;
      const gbPerActiveUser = (avgPageSizeMB * pagesPerSession) / 1024;
      dailyBandwidthGB = activeDau * gbPerActiveUser * patternMultiplier;
      bandwidthModel = `page-based (default): ${activeDau} active × ${avgPageSizeMB}MB × ${pagesPerSession} pages`;
      break;
    }
  }

  // CDN configuration
  const cdnEnabled = cdnOptions?.enabled !== false; // 기본값: true
  const cdnCacheHitRate = cdnOptions?.cacheHitRate ?? config.cdnCacheHitRate;

  console.log(`[Bandwidth] Model: ${bandwidthModel}`);
  console.log(`[Bandwidth] DAU: ${dailyUniqueVisitors} (${dauMultiplier.min}-${dauMultiplier.max}x), Active: ${activeDau} (${(activeUserRatio * 100).toFixed(0)}%), Daily: ${dailyBandwidthGB.toFixed(1)} GB`);

  // Monthly bandwidth (gross - before CDN)
  const grossMonthlyGB = dailyBandwidthGB * 30;
  const grossMonthlyTB = grossMonthlyGB / 1024;

  // Origin bandwidth (after CDN cache hit)
  const originMonthlyTB = cdnEnabled
    ? grossMonthlyTB * (1 - cdnCacheHitRate)
    : grossMonthlyTB;
  const originMonthlyGB = originMonthlyTB * 1024;

  // Use origin traffic for categorization (actual server load)
  const monthlyGB = originMonthlyGB;
  const monthlyTB = originMonthlyTB;

  console.log(`[Bandwidth] CDN: ${cdnEnabled ? 'enabled' : 'disabled'}, Hit Rate: ${(cdnCacheHitRate * 100).toFixed(0)}%`);
  console.log(`[Bandwidth] Gross: ${grossMonthlyTB.toFixed(1)} TB → Origin: ${originMonthlyTB.toFixed(1)} TB (${((1 - cdnCacheHitRate) * 100).toFixed(0)}%)`);

  // Categorize based on ORIGIN traffic (actual server load)
  let category: 'light' | 'moderate' | 'heavy' | 'very_heavy';
  let description: string;

  if (monthlyTB < 0.5) {
    category = 'light';
    description = cdnEnabled
      ? `총 ${grossMonthlyTB.toFixed(1)}TB 중 원본 서버 ~${Math.round(monthlyGB)}GB/월 (CDN ${(cdnCacheHitRate * 100).toFixed(0)}% 캐시)`
      : `~${Math.round(monthlyGB)} GB/month - Most VPS plans include sufficient bandwidth`;
  } else if (monthlyTB < 2) {
    category = 'moderate';
    description = cdnEnabled
      ? `총 ${grossMonthlyTB.toFixed(1)}TB 중 원본 서버 ~${monthlyTB.toFixed(1)}TB/월 (CDN ${(cdnCacheHitRate * 100).toFixed(0)}% 캐시)`
      : `~${monthlyTB.toFixed(1)} TB/month - Check provider bandwidth limits`;
  } else if (monthlyTB < 6) {
    category = 'heavy';
    description = cdnEnabled
      ? `총 ${grossMonthlyTB.toFixed(1)}TB 중 원본 서버 ~${monthlyTB.toFixed(1)}TB/월 (CDN ${(cdnCacheHitRate * 100).toFixed(0)}% 캐시) - 대역폭 여유 있는 플랜 권장`
      : `~${monthlyTB.toFixed(1)} TB/month - Prefer providers with generous bandwidth (Linode: 1-6TB included)`;
  } else {
    category = 'very_heavy';
    description = cdnEnabled
      ? `총 ${grossMonthlyTB.toFixed(1)}TB 중 원본 서버 ~${monthlyTB.toFixed(1)}TB/월 (CDN ${(cdnCacheHitRate * 100).toFixed(0)}% 캐시) - 고대역폭 플랜 필수`
      : `~${monthlyTB.toFixed(1)} TB/month - HIGH BANDWIDTH: Linode strongly recommended for cost savings`;
  }

  return {
    monthly_gb: Math.round(monthlyGB),
    monthly_tb: Math.round(monthlyTB * 10) / 10,
    daily_gb: Math.round(dailyBandwidthGB * 10) / 10,
    category,
    description,
    estimated_dau_min: estimatedDauMin,
    estimated_dau_max: estimatedDauMax,
    active_ratio: activeUserRatio,
    // CDN breakdown
    cdn_enabled: cdnEnabled,
    cdn_cache_hit_rate: cdnCacheHitRate,
    gross_monthly_tb: Math.round(grossMonthlyTB * 10) / 10,
    origin_monthly_tb: Math.round(originMonthlyTB * 10) / 10
  };
}

/**
 * Get provider bandwidth allocation based on memory size
 * Returns included transfer in TB/month
 */
export function getProviderBandwidthAllocation(providerName: string, memoryGb: number): {
  included_tb: number;
  overage_per_gb: number;
  overage_per_tb: number;
} {
  const provider = providerName.toLowerCase();

  if (provider.includes('linode')) {
    // Linode: roughly 1TB per 1GB RAM (Nanode 1GB = 1TB, 2GB = 2TB, etc.)
    const includedTb = Math.min(Math.max(memoryGb, 1), 20);
    return {
      included_tb: includedTb,
      overage_per_gb: 0.005,  // $0.005/GB = $5/TB
      overage_per_tb: 5
    };
  } else if (provider.includes('vultr')) {
    // Vultr: varies by plan, roughly 1-2TB for small, up to 10TB for large
    let includedTb: number;
    if (memoryGb <= 2) includedTb = 1;
    else if (memoryGb <= 4) includedTb = 2;
    else if (memoryGb <= 8) includedTb = 3;
    else if (memoryGb <= 16) includedTb = 4;
    else if (memoryGb <= 32) includedTb = 5;
    else includedTb = Math.min(memoryGb / 4, 10);

    return {
      included_tb: includedTb,
      overage_per_gb: 0.01,   // $0.01/GB = $10/TB
      overage_per_tb: 10
    };
  } else {
    // Default/Other providers: conservative estimate
    return {
      included_tb: Math.min(memoryGb, 5),
      overage_per_gb: 0.01,
      overage_per_tb: 10
    };
  }
}

/**
 * Calculate bandwidth cost info for a server
 * Uses actual DB values from anvil_transfer_pricing when available
 * @param server Server object
 * @param bandwidthEstimate Bandwidth estimate
 * @param lang Language code (ko = KRW, others = USD)
 * @param exchangeRate Exchange rate (USD to KRW)
 */
export function calculateBandwidthInfo(
  server: import('../types').Server,
  bandwidthEstimate: BandwidthEstimate,
  lang: string = 'en',
  exchangeRate: number = 1
): BandwidthInfo {
  // Use actual DB values if available (Anvil servers), fallback to provider-based estimation
  let includedTb: number;
  let overagePerGbUsd: number;
  let overagePerTbUsd: number;

  if (server.transfer_tb !== null && server.transfer_price_per_gb !== null) {
    // Use actual values from anvil_instances + anvil_transfer_pricing
    includedTb = server.transfer_tb;
    overagePerGbUsd = server.transfer_price_per_gb;
    overagePerTbUsd = server.transfer_price_per_gb * 1024;
  } else {
    // Fallback to provider-based estimation for non-Anvil servers
    const allocation = getProviderBandwidthAllocation(server.provider_name, server.memory_gb);
    includedTb = allocation.included_tb;
    overagePerGbUsd = allocation.overage_per_gb;
    overagePerTbUsd = allocation.overage_per_tb;
  }

  const estimatedTb = bandwidthEstimate.monthly_tb;
  const overageTb = Math.max(0, estimatedTb - includedTb);
  const overageCostUsd = overageTb * overagePerTbUsd;

  // Get server price in USD for total calculation
  const serverPriceUsd = server.currency === 'KRW'
    ? server.monthly_price / exchangeRate
    : server.monthly_price;

  const totalCostUsd = serverPriceUsd + overageCostUsd;

  // Convert to KRW if Korean language, round to nearest 100
  const isKorean = lang === 'ko';
  const currency: 'USD' | 'KRW' = isKorean ? 'KRW' : 'USD';

  // KRW 반올림: GB당 1원, TB당 500원, 총 비용 1원
  const toKrw = (usd: number) => Math.round(usd * exchangeRate); // 1원 단위
  const toKrw500 = (usd: number) => Math.round((usd * exchangeRate) / 500) * 500; // 500원 단위

  const overagePerGb = isKorean ? toKrw(overagePerGbUsd) : overagePerGbUsd;
  const overagePerTb = isKorean ? toKrw500(overagePerTbUsd) : overagePerTbUsd; // 500원 단위
  const overageCost = isKorean ? toKrw500(overageCostUsd) : overageCostUsd; // 500원 단위
  // totalCost: 서버 가격(500원) + 초과 비용(500원)
  const totalCost = isKorean ? server.monthly_price + toKrw500(overageCostUsd) : totalCostUsd;

  // CDN savings calculation
  const cdnEnabled = bandwidthEstimate.cdn_enabled;
  const cdnCacheHitRate = bandwidthEstimate.cdn_cache_hit_rate;
  const grossMonthlyTb = bandwidthEstimate.gross_monthly_tb;
  const cdnSavingsTb = cdnEnabled ? grossMonthlyTb - estimatedTb : 0;
  const cdnSavingsCostUsd = cdnSavingsTb * overagePerTbUsd;
  const cdnSavingsCost = isKorean ? toKrw500(cdnSavingsCostUsd) : cdnSavingsCostUsd; // 500원 단위

  let warning: string | undefined;
  if (overageTb > includedTb) {
    const costStr = isKorean ? `₩${overageCost.toLocaleString()}` : `$${overageCost.toFixed(0)}`;
    warning = cdnEnabled
      ? `⚠️ CDN 적용 후에도 원본 서버 트래픽(${estimatedTb.toFixed(1)}TB)이 기본 포함량(${includedTb}TB)의 2배 이상입니다. 상위 플랜을 고려하세요.`
      : `⚠️ 예상 트래픽(${estimatedTb.toFixed(1)}TB)이 기본 포함량(${includedTb}TB)의 2배 이상입니다. 상위 플랜을 고려하세요.`;
  } else if (overageTb > 0) {
    const costStr = isKorean ? `₩${overageCost.toLocaleString()}` : `$${overageCost.toFixed(0)}`;
    warning = cdnEnabled
      ? `예상 초과 트래픽: ${overageTb.toFixed(1)}TB (CDN ${(cdnCacheHitRate * 100).toFixed(0)}% 캐시 적용 후, 추가 비용 ~${costStr}/월)`
      : `예상 초과 트래픽: ${overageTb.toFixed(1)}TB (추가 비용 ~${costStr}/월)`;
  }

  return {
    included_transfer_tb: includedTb,
    overage_cost_per_gb: overagePerGb, // 반올림 없음
    overage_cost_per_tb: overagePerTb, // 반올림 없음
    estimated_monthly_tb: Math.round(estimatedTb * 10) / 10,
    estimated_overage_tb: Math.round(overageTb * 10) / 10,
    estimated_overage_cost: overageCost, // 반올림 없음
    total_estimated_cost: totalCost, // 서버 가격(반올림) + 초과 비용(반올림 X)
    currency,
    warning,
    // CDN breakdown
    cdn_enabled: cdnEnabled,
    cdn_cache_hit_rate: cdnCacheHitRate,
    gross_monthly_tb: Math.round(grossMonthlyTb * 10) / 10,
    cdn_savings_tb: Math.round(cdnSavingsTb * 10) / 10,
    cdn_savings_cost: cdnSavingsCost // 반올림 없음
  };
}
