/**
 * AI service module - OpenAI GPT-4o-mini integration
 * Handles AI-powered server recommendations and response parsing
 */

import type {
  Env,
  RecommendRequest,
  Server,
  BenchmarkData,
  VPSBenchmark,
  TechSpec,
  BandwidthEstimate,
  RecommendationResult,
  AIRecommendationResponse,
  BenchmarkReference,
} from '../types';
import { i18n, LIMITS } from '../config';
import {
  sanitizeForAIPrompt,
  isValidAIRecommendation,
  calculateBandwidthInfo,
} from '../utils';

/**
 * Get AI-powered recommendations using OpenAI GPT-4o-mini
 */
export async function getAIRecommendations(
  env: Env,
  apiKey: string,
  req: RecommendRequest,
  candidates: Server[],
  benchmarkData: BenchmarkData[],
  vpsBenchmarks: VPSBenchmark[],
  techSpecs: TechSpec[],
  bandwidthEstimate: BandwidthEstimate,
  lang: string = 'en',
  exchangeRate: number = 1
): Promise<{ recommendations: RecommendationResult[]; infrastructure_tips?: string[] }> {
  // Validate API key before making any API calls
  if (!apiKey || !apiKey.trim()) {
    console.error('[AI] OPENAI_API_KEY is not configured or empty');
    throw new Error('OPENAI_API_KEY not configured. Please set the secret via: wrangler secret put OPENAI_API_KEY');
  }
  if (!apiKey.startsWith('sk-')) {
    console.error('[AI] OPENAI_API_KEY has invalid format (should start with sk-)');
    throw new Error('Invalid OPENAI_API_KEY format');
  }
  console.log('[AI] API key validated (format: sk-***)');

  // Build dynamic tech specs prompt from database
  const techSpecsPrompt = formatTechSpecsForPrompt(techSpecs);

  // Ensure lang is valid
  const validLang = ['en', 'zh', 'ja', 'ko'].includes(lang) ? lang : 'en';
  const languageInstruction = i18n[validLang].aiLanguageInstruction;

  // Build system prompt with benchmark awareness
  const systemPrompt = `You are a cloud infrastructure expert focused on COST-EFFECTIVE solutions. Your goal is to recommend the SMALLEST and CHEAPEST server that can handle the user's requirements.

CRITICAL RULES:
1. NEVER over-provision. Recommend the minimum specs needed.
2. Cost efficiency is the PRIMARY factor - cheaper is better if it meets requirements.
3. A 1-2 vCPU server can handle 100-500 concurrent users for most web workloads.
4. Nginx/reverse proxy needs very little resources - 1 vCPU can handle 1000+ req/sec.
5. Provide 3 options: Budget (cheapest viable), Balanced (some headroom), Premium (growth ready).
6. NEVER recommend the same server twice. Each recommendation MUST have a DIFFERENT server_id.
7. If only 2 suitable servers exist, recommend only 2. Do NOT duplicate.

BANDWIDTH CONSIDERATIONS:
- Estimated monthly bandwidth is provided based on concurrent users and use case.
- TOTAL COST = Base server price + Bandwidth overage charges
- Always mention bandwidth implications in cost_efficiency analysis

${techSpecsPrompt}

Use REAL BENCHMARK DATA to validate capacity estimates.

${languageInstruction}`;

  // Build user prompt with requirements and candidates
  console.log('[AI] Bandwidth estimate:', bandwidthEstimate);

  // Detect high-traffic based on bandwidth estimate (more accurate than keyword matching)
  const isHighTraffic = bandwidthEstimate.category === 'heavy' || bandwidthEstimate.category === 'very_heavy';

  // Format benchmark data for the prompt
  const benchmarkSummary = formatBenchmarkSummary(benchmarkData);
  const vpsBenchmarkSummary = formatVPSBenchmarkSummary(vpsBenchmarks);

  // Pre-filter candidates to reduce AI prompt size and cost
  // Ensure BOTH spec diversity AND region diversity when no region_preference is specified
  let topCandidates: Server[];
  const hasRegionPreference = req.region_preference && req.region_preference.length > 0;

  if (hasRegionPreference) {
    // If region preference specified, just take top 15 cheapest
    topCandidates = candidates
      .sort((a, b) => a.monthly_price - b.monthly_price)
      .slice(0, 15);
  } else {
    // No region preference: ensure SPEC DIVERSITY + REGION DIVERSITY
    // Group servers by spec tier (based on instance_name which reflects vcpu+memory)
    const specGroups = new Map<string, Server[]>();
    for (const server of candidates) {
      const specKey = server.instance_name; // e.g., "Basic 1GB", "Standard 4GB", "Pro 8GB"
      const existing = specGroups.get(specKey) || [];
      existing.push(server);
      specGroups.set(specKey, existing);
    }

    // Sort spec groups by price (cheapest spec first)
    const sortedSpecGroups = Array.from(specGroups.entries())
      .map(([spec, servers]) => ({
        spec,
        servers: servers.sort((a, b) => a.monthly_price - b.monthly_price),
        minPrice: Math.min(...servers.map(s => s.monthly_price))
      }))
      .sort((a, b) => a.minPrice - b.minPrice);

    // Select servers ensuring spec diversity with region diversity within each tier
    // Pick 5 servers from each of the first 3 spec tiers (different regions)
    topCandidates = [];
    const usedRegions = new Set<string>();

    for (const group of sortedSpecGroups.slice(0, 5)) { // Up to 5 spec tiers
      let addedFromThisTier = 0;
      for (const server of group.servers) {
        // Prefer different regions within the same spec tier
        if (addedFromThisTier < 3 && !usedRegions.has(server.region_name)) {
          topCandidates.push(server);
          usedRegions.add(server.region_name);
          addedFromThisTier++;
        } else if (addedFromThisTier < 2) {
          // Allow same region if we don't have enough
          topCandidates.push(server);
          addedFromThisTier++;
        }
        if (topCandidates.length >= 15) break;
      }
      if (topCandidates.length >= 15) break;
    }

    // Sort final list by price
    topCandidates.sort((a, b) => a.monthly_price - b.monthly_price);

    const specDiversity = new Set(topCandidates.map(s => s.instance_name));
    const regionDiversity = new Set(topCandidates.map(s => s.region_name));
    console.log(`[AI] Spec diversity: ${specDiversity.size} specs (${Array.from(specDiversity).join(', ')})`);
    console.log(`[AI] Region diversity: ${regionDiversity.size} regions (${Array.from(regionDiversity).join(', ')})`);
  }

  console.log(`[AI] Filtered ${candidates.length} candidates to ${topCandidates.length} for AI analysis`);

  // Sanitize user inputs to prevent prompt injection
  const sanitizedTechStack = req.tech_stack.map(t => sanitizeForAIPrompt(t, 50)).join(', ');
  const sanitizedUseCase = sanitizeForAIPrompt(req.use_case, 200);

  const userPrompt = `Analyze these server options and recommend the top 3 best matches.

## User Requirements
- Tech Stack: ${sanitizedTechStack}
- Expected Concurrent Users: ${req.expected_users} ${req.traffic_pattern === 'spiky' ? '(with traffic spikes)' : req.traffic_pattern === 'growing' ? '(growing user base)' : '(steady traffic)'}
- **Estimated DAU (Daily Active Users)**: ${bandwidthEstimate.estimated_dau_min.toLocaleString()}-${bandwidthEstimate.estimated_dau_max.toLocaleString()}명 (동시 접속 ${req.expected_users}명 기준)
- Use Case: ${sanitizedUseCase}
- Traffic Pattern: ${req.traffic_pattern || 'steady'}
- **Estimated Monthly Bandwidth**: ${bandwidthEstimate.monthly_tb >= 1 ? `${bandwidthEstimate.monthly_tb} TB` : `${bandwidthEstimate.monthly_gb} GB`} (${bandwidthEstimate.category})
${isHighTraffic ? `- ⚠️ HIGH BANDWIDTH WORKLOAD (${bandwidthEstimate.monthly_tb} TB/month): Consider bandwidth overage costs when evaluating total cost.` : ''}
${req.budget_limit ? `- Budget Limit: $${req.budget_limit}/month` : ''}

## Real VPS Benchmark Data (Geekbench 6 normalized - actual VPS tests)
${vpsBenchmarkSummary || 'No similar VPS benchmark data available.'}

## CPU Benchmark Reference (from Phoronix Test Suite)
${benchmarkSummary || 'No relevant CPU benchmark data available.'}

## Available Servers (IMPORTANT: Use the server_id value, NOT the list number!)
${topCandidates.map((s) => `[server_id=${s.id}] ${s.provider_name} - ${s.instance_name}
   vCPU: ${s.vcpu} | RAM: ${s.memory_gb}GB | Storage: ${s.storage_gb}GB${s.gpu_count > 0 ? ` | GPU: ${s.gpu_count}x ${s.gpu_type}` : ''}
   Price: ${s.currency === 'KRW' ? '₩' : '$'}${s.currency === 'KRW' ? Math.round(s.monthly_price).toLocaleString() : s.monthly_price.toFixed(2)}/mo | Region: ${s.region_name}`).join('\n')}

Return ONLY a valid JSON object (no markdown, no code blocks) with this exact structure:
{
  "recommendations": [
    {
      "server_id": 2045,  // Use the actual server_id from [server_id=XXXX] above, NOT list position!
      "score": 95,
      "analysis": {
        "tech_fit": "Why this server fits the tech stack",
        "capacity": "MUST mention: '동시 접속 X명 요청 (DAU A-B명), 최대 동시 Y명까지 처리 가능' format",
        "cost_efficiency": "MUST include: base price + bandwidth cost estimate. Example: '$5/month + ~$X bandwidth = ~$Y total'",
        "scalability": "Scalability potential including bandwidth headroom"
      },
      "estimated_capacity": {
        "max_concurrent_users": 7500,
        "requests_per_second": 1000
      }
    }
  ],
  "infrastructure_tips": [
    "Practical tip 1",
    "Practical tip 2"
  ]
}

Provide exactly 3 recommendations:
1. BUDGET option: Cheapest TOTAL cost (base + bandwidth) that can handle the load
2. BALANCED option: Some headroom for traffic spikes
3. PREMIUM option: Ready for 2-3x growth

SCORING (100 points total):
- Total Cost Efficiency (40%): Base price + estimated bandwidth overage. Lower total = higher score.
- Capacity Fit (30%): Can it handle the concurrent users and bandwidth?
- Scalability (30%): Room for growth in CPU, memory, AND bandwidth allowance.

The option with the LOWEST TOTAL MONTHLY COST (including bandwidth) should have the HIGHEST score.`;

  // Use AI Gateway if configured (bypasses regional restrictions like HKG)
  // AI Gateway URL format: https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_name}/openai
  const useAIGateway = !!env.AI_GATEWAY_URL;
  const apiEndpoint = useAIGateway
    ? `${env.AI_GATEWAY_URL}/chat/completions`
    : 'https://api.openai.com/v1/chat/completions';

  console.log(`[AI] Sending request to ${useAIGateway ? 'AI Gateway → ' : ''}OpenAI GPT-4o-mini`);
  if (useAIGateway) {
    console.log('[AI] Using Cloudflare AI Gateway to bypass regional restrictions');
  }

  // Create AbortController with 30 second timeout
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), 30000);

  try {
    const openaiResponse = await fetch(apiEndpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${apiKey}`,
      },
      body: JSON.stringify({
        model: 'gpt-4o-mini',
        messages: [
          { role: 'system', content: systemPrompt },
          { role: 'user', content: userPrompt },
        ],
        max_tokens: 2000,
        temperature: 0.3,
      }),
      signal: controller.signal,
    });

    clearTimeout(timeoutId);

    if (!openaiResponse.ok) {
      const errorText = await openaiResponse.text();

      // Parse error details for better debugging
      let errorDetails = '';
      try {
        const errorObj = JSON.parse(errorText);
        errorDetails = errorObj?.error?.message || errorObj?.error?.type || '';
      } catch {
        errorDetails = errorText.slice(0, 200);
      }

      // Sanitize API keys from error messages
      const sanitized = errorDetails.replace(/sk-[a-zA-Z0-9-_]+/g, 'sk-***');

      // Enhanced logging for specific error codes
      if (openaiResponse.status === 403) {
        const isRegionalBlock = errorDetails.includes('Country') || errorDetails.includes('region') || errorDetails.includes('territory');
        if (isRegionalBlock && !useAIGateway) {
          console.error('[AI] ❌ REGIONAL BLOCK (403) - OpenAI blocked this region');
          console.error('[AI]   Worker is running in a blocked region (e.g., HKG)');
          console.error('[AI]   FIX: Set AI_GATEWAY_URL secret to use Cloudflare AI Gateway');
          console.error('[AI]   1. Create AI Gateway: https://dash.cloudflare.com → AI → AI Gateway');
          console.error('[AI]   2. Run: wrangler secret put AI_GATEWAY_URL');
          console.error('[AI]   3. Enter: https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_name}/openai');
        } else {
          console.error('[AI] ❌ AUTH FAILED (403) - Possible causes:');
          console.error('[AI]   1. Invalid or expired OPENAI_API_KEY');
          console.error('[AI]   2. API key not properly set in Cloudflare secrets');
          console.error('[AI]   3. Account billing issue or quota exceeded');
        }
        console.error('[AI] Error details:', sanitized);
      } else if (openaiResponse.status === 429) {
        console.error('[AI] ⚠️ RATE LIMITED (429) - Too many requests');
        console.error('[AI] Error details:', sanitized);
      } else if (openaiResponse.status === 401) {
        console.error('[AI] ❌ UNAUTHORIZED (401) - API key invalid');
        console.error('[AI] Error details:', sanitized);
      } else {
        console.error('[AI] OpenAI API error:', openaiResponse.status, sanitized);
      }

      throw new Error(`OpenAI API error: ${openaiResponse.status}`);
    }

    const openaiResult = await openaiResponse.json() as {
      choices: Array<{ message: { content: string } }>;
    };

    const response = openaiResult.choices[0]?.message?.content || '';

    console.log('[AI] Response received from OpenAI, length:', response.length);

    // Parse AI response
    const aiResult = parseAIResponse(response);
    console.log('[AI] Parsed recommendations count:', aiResult.recommendations.length);

    // Pre-index VPS benchmarks by provider for O(1) lookups
    const vpsByProvider = new Map<string, VPSBenchmark[]>();
    for (const vps of vpsBenchmarks) {
      const providerKey = vps.provider_name.toLowerCase();
      const existing = vpsByProvider.get(providerKey) || [];
      existing.push(vps);
      vpsByProvider.set(providerKey, existing);
    }

    // Map AI recommendations to full results (with deduplication)
    const results: RecommendationResult[] = [];
    const seenServerIds = new Set<number>();

    for (const aiRec of aiResult.recommendations) {
      // Handle both string and number server_id from AI
      const serverId = Number(aiRec.server_id);

      // Skip duplicate server IDs
      if (seenServerIds.has(serverId)) {
        console.warn('[AI] Skipping duplicate server_id:', serverId);
        continue;
      }

      const server = candidates.find((s) => s.id === serverId);
      if (!server) {
        console.warn('[AI] Server not found:', aiRec.server_id);
        continue;
      }

      seenServerIds.add(serverId);

      // Get benchmark reference for this server's CPU count
      const benchmarkRef = getBenchmarkReference(benchmarkData, server.vcpu);

      // Find matching VPS benchmark using pre-indexed data
      const providerName = server.provider_name.toLowerCase();
      let matchingVPS: VPSBenchmark | undefined;

      // Try to find from indexed provider benchmarks
      for (const [providerKey, benchmarks] of vpsByProvider.entries()) {
        if (providerKey.includes(providerName) || providerName.includes(providerKey)) {
          // First try exact or close vCPU match
          matchingVPS = benchmarks.find(
            (v) => v.vcpu === server.vcpu || (v.vcpu >= server.vcpu - 1 && v.vcpu <= server.vcpu + 1)
          );
          // Fallback to any from this provider
          if (!matchingVPS && benchmarks.length > 0) {
            matchingVPS = benchmarks[0];
          }
          if (matchingVPS) break;
        }
      }

      // Final fallback: similar specs from any provider
      if (!matchingVPS) {
        matchingVPS = vpsBenchmarks.find(
          (v) => v.vcpu === server.vcpu || (v.vcpu >= server.vcpu - 1 && v.vcpu <= server.vcpu + 1)
        );
      }

      // Calculate bandwidth info for this server (with currency conversion for Korean)
      const bandwidthInfo = calculateBandwidthInfo(server, bandwidthEstimate, lang, exchangeRate);

      // Find all available regions for the same server spec
      const availableRegions = candidates
        .filter(c =>
          c.provider_name === server.provider_name &&
          c.instance_id === server.instance_id &&
          c.region_code !== server.region_code  // Exclude current region
        )
        .map(c => ({
          region_name: c.region_name,
          region_code: c.region_code,
          monthly_price: c.monthly_price
        }))
        .sort((a, b) => a.monthly_price - b.monthly_price);

      results.push({
        server: server,
        score: aiRec.score,
        analysis: aiRec.analysis,
        estimated_capacity: aiRec.estimated_capacity,
        bandwidth_info: bandwidthInfo,
        benchmark_reference: benchmarkRef,
        vps_benchmark_reference: matchingVPS
          ? {
              plan_name: matchingVPS.plan_name,
              geekbench_single: matchingVPS.geekbench_single,
              geekbench_multi: matchingVPS.geekbench_multi,
              monthly_price_usd: matchingVPS.monthly_price_usd,
              performance_per_dollar: matchingVPS.performance_per_dollar,
            }
          : undefined,
        available_regions: availableRegions.length > 0 ? availableRegions : undefined,
      });

      if (results.length >= 3) break;
    }

    return {
      recommendations: results,
      infrastructure_tips: aiResult.infrastructure_tips,
    };
  } catch (error) {
    clearTimeout(timeoutId);
    // Handle timeout specifically
    if (error instanceof Error && error.name === 'AbortError') {
      console.error('[AI] Request timed out after 30 seconds');
      throw new Error('AI request timed out - please try again');
    }
    console.error('[AI] Error:', error);
    throw new Error(`AI processing failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
  }
}

/**
 * Parse AI response and extract JSON
 */
export function parseAIResponse(response: unknown): AIRecommendationResponse {
  try {
    // Handle different response formats
    let content: string;

    if (typeof response === 'string') {
      content = response;
    } else if (typeof response === 'object' && response !== null) {
      // Type guard for response object with different structures
      const resp = response as Record<string, unknown>;

      if (typeof resp.response === 'string') {
        content = resp.response;
      } else if (typeof resp.result === 'object' && resp.result !== null) {
        const result = resp.result as Record<string, unknown>;
        if (typeof result.response === 'string') {
          content = result.response;
        } else {
          throw new Error('Unexpected AI response format');
        }
      } else if (Array.isArray(resp.choices) && resp.choices.length > 0) {
        const choice = resp.choices[0] as Record<string, unknown>;
        const message = choice?.message as Record<string, unknown>;
        if (typeof message?.content === 'string') {
          content = message.content;
        } else {
          throw new Error('Unexpected AI response format');
        }
      } else {
        console.error('[AI] Unexpected response format:', response);
        throw new Error('Unexpected AI response format');
      }
    } else {
      console.error('[AI] Unexpected response format:', response);
      throw new Error('Unexpected AI response format');
    }

    // Remove markdown code blocks if present
    content = content.replace(/```json\s*/g, '').replace(/```\s*/g, '').trim();

    // Find JSON object in response
    const jsonMatch = content.match(/\{[\s\S]*\}/);
    if (!jsonMatch) {
      throw new Error('No JSON found in AI response');
    }

    const parsed = JSON.parse(jsonMatch[0]);

    if (!parsed.recommendations || !Array.isArray(parsed.recommendations)) {
      throw new Error('Invalid recommendations structure');
    }

    // Validate each recommendation with type guard
    const validRecommendations = parsed.recommendations.filter(isValidAIRecommendation);
    if (validRecommendations.length === 0 && parsed.recommendations.length > 0) {
      console.warn('[AI] All recommendations failed validation, raw:', JSON.stringify(parsed.recommendations[0]).slice(0, 200));
      throw new Error('AI recommendations failed validation');
    }

    return {
      recommendations: validRecommendations,
      infrastructure_tips: Array.isArray(parsed.infrastructure_tips) ? parsed.infrastructure_tips : [],
    } as AIRecommendationResponse;
  } catch (error) {
    console.error('[AI] Parse error:', error);
    console.error('[AI] Response parse failed, length:', typeof response === 'string' ? response.length : 'N/A', 'preview:', typeof response === 'string' ? response.substring(0, 100).replace(/[^\x20-\x7E]/g, '?') : 'Invalid response type');
    throw new Error(`Failed to parse AI response: ${error instanceof Error ? error.message : 'Unknown error'}`);
  }
}

/**
 * Format tech specs for AI prompt
 */
export function formatTechSpecsForPrompt(techSpecs: TechSpec[]): string {
  if (!techSpecs || techSpecs.length === 0) {
    return `Tech stack resource guidelines:
- Default: 1 vCPU per 100-300 users, 1-2GB RAM`;
  }

  const lines = ['Tech stack resource guidelines (MUST follow minimum RAM requirements):'];

  for (const spec of techSpecs) {
    const vcpuRange = spec.vcpu_per_users_max
      ? `${spec.vcpu_per_users}-${spec.vcpu_per_users_max}`
      : `${spec.vcpu_per_users}`;

    // Convert MB to GB for readability
    const minMemoryGB = (spec.min_memory_mb / 1024).toFixed(1).replace('.0', '');
    const maxMemoryGB = spec.max_memory_mb ? (spec.max_memory_mb / 1024).toFixed(1).replace('.0', '') : null;
    const memoryRange = maxMemoryGB ? `${minMemoryGB}-${maxMemoryGB}GB` : `${minMemoryGB}GB+`;

    let line = `- ${spec.name}: 1 vCPU per ${vcpuRange} users, MINIMUM ${minMemoryGB}GB RAM`;

    // Add warnings for special requirements
    const warnings: string[] = [];
    if (spec.is_memory_intensive) warnings.push('⚠️ MEMORY-INTENSIVE: must have at least ' + minMemoryGB + 'GB RAM');
    if (spec.is_cpu_intensive) warnings.push('⚠️ CPU-INTENSIVE');
    if (warnings.length > 0) {
      line += ` [${warnings.join(', ')}]`;
    }

    lines.push(line);
  }

  // Add explicit warning for memory-intensive apps
  const memoryIntensive = techSpecs.filter(s => s.is_memory_intensive);
  if (memoryIntensive.length > 0) {
    const maxMinMemory = Math.max(...memoryIntensive.map(s => s.min_memory_mb));
    lines.push('');
    lines.push(`⚠️ CRITICAL: This tech stack includes memory-intensive apps. Servers with less than ${(maxMinMemory / 1024).toFixed(0)}GB RAM will NOT work properly!`);
  }

  return lines.join('\n');
}

/**
 * Format benchmark data for AI prompt
 */
export function formatBenchmarkSummary(benchmarks: BenchmarkData[]): string {
  if (benchmarks.length === 0) {
    return '';
  }

  // Group by benchmark type
  const byType = new Map<string, BenchmarkData[]>();
  for (const b of benchmarks) {
    const existing = byType.get(b.benchmark_name) || [];
    existing.push(b);
    byType.set(b.benchmark_name, existing);
  }

  const lines: string[] = [];
  for (const [type, data] of byType) {
    // Get top 3 performers for this benchmark
    const top3 = data.slice(0, 3);
    const scores = top3.map(d =>
      `${d.processor_name}${d.cores ? ` (${d.cores} cores)` : ''}: ${d.score} (${d.percentile}th percentile)`
    );
    lines.push(`### ${type} (${data[0].category})`);
    lines.push(scores.join('\n'));
    lines.push('');
  }

  return lines.join('\n');
}

/**
 * Format VPS benchmark data for AI prompt
 * Uses GB6-normalized scores (GB5 scores converted with ×1.45 factor)
 */
export function formatVPSBenchmarkSummary(benchmarks: VPSBenchmark[]): string {
  if (benchmarks.length === 0) {
    return '';
  }

  const lines = ['Real VPS performance data (Geekbench 6 normalized):'];
  for (const b of benchmarks.slice(0, 5)) {
    const versionNote = b.geekbench_version?.startsWith('5.') ? ' [GB5→6]' : '';
    lines.push(
      `- ${b.plan_name} (${b.country_code}): Single=${b.gb6_single_normalized}, Multi=${b.gb6_multi_normalized}${versionNote}, $${b.monthly_price_usd}/mo, Perf/$=${b.performance_per_dollar.toFixed(1)}`
    );
  }

  return lines.join('\n');
}

/**
 * Get benchmark reference for a server
 */
function getBenchmarkReference(
  benchmarks: BenchmarkData[],
  vcpu: number
): BenchmarkReference | undefined {
  // Find benchmarks from processors with similar core count
  const similarBenchmarks = benchmarks.filter(b =>
    b.cores === null || (b.cores >= vcpu - 2 && b.cores <= vcpu + 4)
  );

  if (similarBenchmarks.length === 0) {
    return undefined;
  }

  // Group by processor and get the best match
  const byProcessor = new Map<string, BenchmarkData[]>();
  for (const b of similarBenchmarks) {
    const existing = byProcessor.get(b.processor_name) || [];
    existing.push(b);
    byProcessor.set(b.processor_name, existing);
  }

  // Find processor with most benchmark data
  let bestProcessor = '';
  let maxBenchmarks = 0;
  for (const [name, data] of byProcessor) {
    if (data.length > maxBenchmarks) {
      maxBenchmarks = data.length;
      bestProcessor = name;
    }
  }

  if (!bestProcessor) {
    return undefined;
  }

  const processorBenchmarks = byProcessor.get(bestProcessor)!;
  return {
    processor_name: bestProcessor,
    benchmarks: processorBenchmarks.map(b => ({
      name: b.benchmark_name,
      category: b.category,
      score: b.score,
      percentile: b.percentile,
    })),
  };
}

/**
 * AI 실패 시 규칙 기반으로 추천 생성
 * 가격순 정렬 → 스펙 필터링 → 상위 3개 선택 (Budget/Balanced/Premium)
 */
export function generateRuleBasedRecommendations(
  candidates: Server[],
  req: RecommendRequest,
  minVcpu: number,
  minMemoryMb: number,
  bandwidthEstimate: BandwidthEstimate,
  lang: string = 'en',
  exchangeRate: number = 1
): RecommendationResult[] {
  // 가격순 정렬
  const sorted = [...candidates].sort((a, b) => a.monthly_price - b.monthly_price);

  if (sorted.length === 0) {
    return [];
  }

  // 3개 티어 선택: 가장 저렴(Budget), 중간(Balanced), 상위 25%(Premium)
  const budget = sorted[0];
  const balanced = sorted[Math.floor(sorted.length / 2)] || sorted[0];
  const premium = sorted[Math.floor(sorted.length * 0.75)] || sorted[sorted.length - 1] || sorted[0];

  const tiers = [
    { server: budget, tier: 'budget' as const, score: 85 },
    { server: balanced, tier: 'balanced' as const, score: 80 },
    { server: premium, tier: 'premium' as const, score: 75 },
  ].filter(t => t.server);

  // 중복 제거
  const seen = new Set<number>();
  const unique = tiers.filter(t => {
    if (seen.has(t.server.id)) return false;
    seen.add(t.server.id);
    return true;
  });

  // RecommendationResult 형식으로 변환
  return unique.map(({ server, score }) => {
    const bandwidthInfo = calculateBandwidthInfo(server, bandwidthEstimate, lang, exchangeRate);

    const fallbackMessage = lang === 'ko'
      ? '규칙 기반 추천 (AI 일시 불가)'
      : 'Rule-based recommendation (AI temporarily unavailable)';

    const capacityMessage = lang === 'ko'
      ? `${server.vcpu} vCPU, ${server.memory_gb}GB RAM (동시 접속 ${req.expected_users}명 기준)`
      : `${server.vcpu} vCPU, ${server.memory_gb}GB RAM (for ${req.expected_users} concurrent users)`;

    const scalabilityMessage = lang === 'ko'
      ? '수동 스케일링 필요'
      : 'Manual scaling required';

    const currencySymbol = server.currency === 'KRW' ? '₩' : '$';
    const formattedPrice = server.currency === 'KRW'
      ? Math.round(server.monthly_price).toLocaleString()
      : server.monthly_price.toFixed(2);

    const costMessage = lang === 'ko'
      ? `월 ${currencySymbol}${formattedPrice}`
      : `${currencySymbol}${formattedPrice}/month`;

    return {
      server,
      score,
      analysis: {
        tech_fit: fallbackMessage,
        capacity: capacityMessage,
        scalability: scalabilityMessage,
        cost_efficiency: costMessage,
      },
      estimated_capacity: {
        max_concurrent_users: Math.floor(server.vcpu * 100), // 간단한 추정: vCPU당 100명
        requests_per_second: Math.floor(server.vcpu * 50),   // vCPU당 50 RPS
      },
      bandwidth_info: bandwidthInfo,
    };
  });
}
