package com.saas.voip.service.ai;

import com.saas.shared.dto.AiCostCalculationResult;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Unit tests for OpenAI Realtime API Cost Calculator
 * 
 * Test Coverage:
 * - Cost calculation accuracy
 * - Edge cases (zero tokens, null input)
 * - Different usage scenarios
 * - Pricing correctness
 */
class OpenAiRealtimeCostCalculatorTest {
    
    private OpenAiRealtimeCostCalculator calculator;
    
    @BeforeEach
    void setUp() {
        calculator = new OpenAiRealtimeCostCalculator();
    }
    
    @Test
    void testCalculateCost_StandardUsage() {
        // Given: Standard usage metrics
        Map<String, Object> usageMetrics = new HashMap<>();
        usageMetrics.put("input_audio_tokens", 10000);
        usageMetrics.put("output_audio_tokens", 5000);
        usageMetrics.put("model", "gpt-4o-realtime-preview");
        
        // When: Calculate cost
        AiCostCalculationResult result = calculator.calculateCost(usageMetrics);
        
        // Then: Verify calculation
        assertNotNull(result);
        assertEquals("OPENAI", result.getAiProvider());
        assertEquals("REALTIME_API", result.getCostType());
        assertEquals("USD", result.getCurrency());
        
        // Cost = (10000 * 0.000005) + (5000 * 0.000020) = 0.05 + 0.10 = 0.15
        BigDecimal expectedCost = new BigDecimal("0.150000");
        assertEquals(expectedCost, result.getCost());
        
        // Verify usage details
        Map<String, Object> details = result.getUsageDetails();
        assertEquals(10000, details.get("input_audio_tokens"));
        assertEquals(5000, details.get("output_audio_tokens"));
    }
    
    @Test
    void testCalculateCost_ZeroTokens() {
        // Given: Zero tokens
        Map<String, Object> usageMetrics = new HashMap<>();
        usageMetrics.put("input_audio_tokens", 0);
        usageMetrics.put("output_audio_tokens", 0);
        
        // When: Calculate cost
        AiCostCalculationResult result = calculator.calculateCost(usageMetrics);
        
        // Then: Cost should be zero
        assertEquals(BigDecimal.ZERO, result.getCost());
        assertTrue(result.isValid());
    }
    
    @Test
    void testCalculateCost_OnlyInputTokens() {
        // Given: Only input tokens
        Map<String, Object> usageMetrics = new HashMap<>();
        usageMetrics.put("input_audio_tokens", 20000);
        usageMetrics.put("output_audio_tokens", 0);
        
        // When: Calculate cost
        AiCostCalculationResult result = calculator.calculateCost(usageMetrics);
        
        // Then: Cost = 20000 * 0.000005 = 0.10
        BigDecimal expectedCost = new BigDecimal("0.100000");
        assertEquals(expectedCost, result.getCost());
    }
    
    @Test
    void testCalculateCost_OnlyOutputTokens() {
        // Given: Only output tokens
        Map<String, Object> usageMetrics = new HashMap<>();
        usageMetrics.put("input_audio_tokens", 0);
        usageMetrics.put("output_audio_tokens", 10000);
        
        // When: Calculate cost
        AiCostCalculationResult result = calculator.calculateCost(usageMetrics);
        
        // Then: Cost = 10000 * 0.000020 = 0.20
        BigDecimal expectedCost = new BigDecimal("0.200000");
        assertEquals(expectedCost, result.getCost());
    }
    
    @Test
    void testCalculateCost_LargeUsage() {
        // Given: Large usage (1M tokens each)
        Map<String, Object> usageMetrics = new HashMap<>();
        usageMetrics.put("input_audio_tokens", 1000000);
        usageMetrics.put("output_audio_tokens", 1000000);
        
        // When: Calculate cost
        AiCostCalculationResult result = calculator.calculateCost(usageMetrics);
        
        // Then: Cost = (1M * $5/1M) + (1M * $20/1M) = $5 + $20 = $25
        BigDecimal expectedCost = new BigDecimal("25.000000");
        assertEquals(expectedCost, result.getCost());
    }
    
    @Test
    void testCalculateCost_NullInput() {
        // When: Calculate cost with null input
        AiCostCalculationResult result = calculator.calculateCost(null);
        
        // Then: Should return zero-cost result
        assertNotNull(result);
        assertEquals(BigDecimal.ZERO, result.getCost());
        assertTrue(result.isValid());
    }
    
    @Test
    void testCalculateCost_EmptyInput() {
        // When: Calculate cost with empty map
        AiCostCalculationResult result = calculator.calculateCost(new HashMap<>());
        
        // Then: Should return zero-cost result
        assertNotNull(result);
        assertEquals(BigDecimal.ZERO, result.getCost());
    }
    
    @Test
    void testCalculateCost_MissingTokens() {
        // Given: Missing token fields
        Map<String, Object> usageMetrics = new HashMap<>();
        usageMetrics.put("model", "gpt-4o-realtime-preview");
        
        // When: Calculate cost
        AiCostCalculationResult result = calculator.calculateCost(usageMetrics);
        
        // Then: Should default to zero
        assertEquals(BigDecimal.ZERO, result.getCost());
    }
    
    @Test
    void testGetProviderName() {
        assertEquals("OPENAI", calculator.getProviderName());
    }
    
    @Test
    void testGetSupportedCostTypes() {
        String[] types = calculator.getSupportedCostTypes();
        assertNotNull(types);
        assertEquals(1, types.length);
        assertEquals("REALTIME_API", types[0]);
    }
    
    @Test
    void testResultIsValid() {
        // Given: Valid usage
        Map<String, Object> usageMetrics = new HashMap<>();
        usageMetrics.put("input_audio_tokens", 1000);
        usageMetrics.put("output_audio_tokens", 500);
        
        // When: Calculate cost
        AiCostCalculationResult result = calculator.calculateCost(usageMetrics);
        
        // Then: Result should be valid
        assertTrue(result.isValid());
    }
}
