package com.saas.voip.service.ai;

import com.saas.shared.dto.AiCostCalculationResult;
import com.saas.shared.service.ai.AiCostCalculator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

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

/**
 * ElevenLabs Cost Calculator
 * 
 * Pricing (as of Oct 2024 - Turbo v2 model):
 * - Turbo v2: $0.30 per 1,000 characters
 * - Multilingual v2: $0.30 per 1,000 characters (higher quality)
 * 
 * Source: https://elevenlabs.io/pricing
 * 
 * Character Counting:
 * - Charged per character of input text
 * - Whitespace typically not counted
 * - Different models may have different pricing
 * 
 * Clean Architecture:
 * - Implements AiCostCalculator interface
 * - Single Responsibility: Calculate ElevenLabs TTS costs
 * - No persistence logic (handled by AiCostTrackingService)
 */
@Service
@Slf4j
public class ElevenLabsCostCalculator implements AiCostCalculator {
    
    // Pricing per 1K characters (USD)
    private static final BigDecimal TURBO_V2_PRICE_PER_1K = new BigDecimal("0.30");
    private static final BigDecimal MULTILINGUAL_V2_PRICE_PER_1K = new BigDecimal("0.30");
    
    // Default model pricing (Turbo v2)
    private static final BigDecimal DEFAULT_PRICE_PER_1K = TURBO_V2_PRICE_PER_1K;
    
    private static final String PROVIDER_NAME = "ELEVENLABS";
    private static final String COST_TYPE = "TTS";
    
    @Override
    public AiCostCalculationResult calculateCost(Map<String, Object> usageMetrics) {
        log.debug("💰 [ElevenLabs] Calculating cost from usage metrics: {}", usageMetrics);
        
        if (usageMetrics == null || usageMetrics.isEmpty()) {
            log.warn("⚠️ [ElevenLabs] Empty usage metrics provided");
            return createZeroCostResult();
        }
        
        try {
            // Extract usage data
            long characters = extractLong(usageMetrics, "characters");
            String model = (String) usageMetrics.getOrDefault("model", "eleven_turbo_v2");
            
            log.info("💰 [ElevenLabs] Usage - Characters: {}, Model: {}", characters, model);
            
            // Determine pricing based on model
            BigDecimal pricePerThousand = getPricingForModel(model);
            
            // Calculate cost: (characters / 1000) * price_per_1k
            BigDecimal cost = BigDecimal.valueOf(characters)
                    .divide(new BigDecimal("1000"), 6, RoundingMode.HALF_UP)
                    .multiply(pricePerThousand)
                    .setScale(6, RoundingMode.HALF_UP);
            
            log.info("💰 [ElevenLabs] Cost - {} characters @ ${}/1K = ${}", 
                    characters, pricePerThousand, cost);
            
            // Build detailed usage map
            Map<String, Object> detailedUsage = new HashMap<>();
            detailedUsage.put("characters", characters);
            detailedUsage.put("model", model);
            detailedUsage.put("price_per_1k_characters", pricePerThousand);
            
            // Add optional metadata
            Map<String, Object> metadata = new HashMap<>();
            if (usageMetrics.containsKey("agent_id")) {
                metadata.put("agent_id", usageMetrics.get("agent_id"));
            }
            if (usageMetrics.containsKey("voice_id")) {
                metadata.put("voice_id", usageMetrics.get("voice_id"));
            }
            if (usageMetrics.containsKey("conversation_id")) {
                metadata.put("conversation_id", usageMetrics.get("conversation_id"));
            }
            
            return AiCostCalculationResult.builder()
                    .aiProvider(PROVIDER_NAME)
                    .costType(COST_TYPE)
                    .cost(cost)
                    .currency("USD")
                    .usageDetails(detailedUsage)
                    .metadata(metadata.isEmpty() ? null : metadata)
                    .build();
            
        } catch (Exception e) {
            log.error("❌ [ElevenLabs] Error calculating cost", e);
            return createZeroCostResult();
        }
    }
    
    @Override
    public String getProviderName() {
        return PROVIDER_NAME;
    }
    
    @Override
    public String[] getSupportedCostTypes() {
        return new String[]{COST_TYPE};
    }
    
    /**
     * Get pricing per 1K characters based on model
     */
    private BigDecimal getPricingForModel(String model) {
        if (model == null) {
            return DEFAULT_PRICE_PER_1K;
        }
        
        // Normalize model name
        String normalizedModel = model.toLowerCase();
        
        if (normalizedModel.contains("turbo")) {
            return TURBO_V2_PRICE_PER_1K;
        } else if (normalizedModel.contains("multilingual")) {
            return MULTILINGUAL_V2_PRICE_PER_1K;
        }
        
        // Default pricing for unknown models
        log.warn("⚠️ [ElevenLabs] Unknown model '{}', using default pricing", model);
        return DEFAULT_PRICE_PER_1K;
    }
    
    /**
     * Extract long value from usage metrics
     * Supports both Integer and Long types
     */
    private long extractLong(Map<String, Object> metrics, String key) {
        Object value = metrics.get(key);
        if (value == null) {
            return 0L;
        }
        if (value instanceof Integer) {
            return ((Integer) value).longValue();
        }
        if (value instanceof Long) {
            return (Long) value;
        }
        if (value instanceof String) {
            try {
                return Long.parseLong((String) value);
            } catch (NumberFormatException e) {
                log.warn("⚠️ [ElevenLabs] Cannot parse {} as long: {}", key, value);
                return 0L;
            }
        }
        log.warn("⚠️ [ElevenLabs] Unexpected type for {}: {}", key, value.getClass());
        return 0L;
    }
    
    /**
     * Create a zero-cost result for error cases
     */
    private AiCostCalculationResult createZeroCostResult() {
        return AiCostCalculationResult.builder()
                .aiProvider(PROVIDER_NAME)
                .costType(COST_TYPE)
                .cost(BigDecimal.ZERO)
                .currency("USD")
                .usageDetails(new HashMap<>())
                .build();
    }
}
