package com.saas.tenant.service;

import com.saas.shared.core.TenantContext;
import com.saas.shared.enums.AIProvider;
import com.saas.admin.entity.TenantAIConfig;
import com.saas.admin.repository.TenantAIConfigRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalTime;
import java.util.Map;
import java.util.Optional;

/**
 * Tenant AI Configuration Service
 * 
 * Manages AI assistant configuration for tenants
 * - Resolves which AI provider to use
 * - Returns assistant/agent IDs
 * - Handles routing rules (time-based, language-based)
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class TenantAIConfigService {

    private final TenantAIConfigRepository aiConfigRepository;
    private final com.saas.subscription.service.SubscriptionService subscriptionService;

    /**
     * Get AI configuration for a tenant
     */
    @Transactional(readOnly = true)
    public Optional<TenantAIConfig> getConfigForTenant(String tenantId) {
        TenantContext.setTenantId(tenantId);
        try {
            log.info("Getting AI config for tenant: {}", tenantId);
            return aiConfigRepository.findByTenantIdAndEnabledTrue(tenantId);
        } finally {
            TenantContext.clear();
        }
    }

    /**
     * Resolve which AI provider to use based on routing rules
     * 
     * @param tenantId Tenant identifier
     * @param callTime Time of the call (for time-based routing)
     * @return AI provider to use (VAPI, RETELL, or NONE)
     */
    @Transactional(readOnly = true)
    public AIProvider resolveProvider(String tenantId, LocalTime callTime) {
        Optional<TenantAIConfig> configOpt = getConfigForTenant(tenantId);

        if (configOpt.isEmpty()) {
            log.warn("No AI config found for tenant: {}", tenantId);
            return AIProvider.NONE;
        }

        TenantAIConfig config = configOpt.get();

        // Check routing rules
        if (config.getRoutingRules() != null && !config.getRoutingRules().isEmpty()) {
            AIProvider routedProvider = applyRoutingRules(config, callTime);
            if (routedProvider != null) {
                log.info("Routing rules applied - Provider: {}", routedProvider);
                return routedProvider;
            }
        }

        // Use primary provider
        AIProvider provider = config.getPrimaryProvider();
        log.info("Using primary provider for tenant {}: {}", tenantId, provider);

        return provider != null ? provider : AIProvider.NONE;
    }

    /**
     * Create or update AI configuration
     */
    @Transactional
    public TenantAIConfig saveConfig(TenantAIConfig config) {
        TenantContext.setTenantId(config.getTenantId());
        try {
            // Check subscription limit for AI agents
            // Count existing configs for this tenant
            long currentAgentCount = aiConfigRepository.countByTenantId(config.getTenantId());

            // If updating existing config, don't count it against limit
            boolean isUpdate = config.getId() != null;
            if (isUpdate) {
                currentAgentCount--;
            }

            if (!subscriptionService.canCreateAiAgent(config.getTenantId(), currentAgentCount)) {
                throw new com.saas.shared.exception.BusinessException(
                        com.saas.shared.exception.ErrorCode.SUBSCRIPTION_LIMIT_EXCEEDED,
                        "Maximum number of AI agents reached for your subscription plan.");
            }

            log.info("Saving AI config for tenant: {}", config.getTenantId());
            return aiConfigRepository.save(config);
        } finally {
            TenantContext.clear();
        }
    }

    /**
     * Delete AI configuration
     */
    @Transactional
    public void deleteConfig(String tenantId) {
        TenantContext.setTenantId(tenantId);
        try {
            aiConfigRepository.findByTenantId(tenantId).ifPresent(config -> {
                log.info("Deleting AI config for tenant: {}", tenantId);
                aiConfigRepository.delete(config);
            });
        } finally {
            TenantContext.clear();
        }
    }

    /**
     * Apply routing rules to determine provider
     * 
     * Supports:
     * - Time-based routing (business hours vs after hours)
     * - Language-based routing (future)
     * - Load-based routing (future)
     */
    private AIProvider applyRoutingRules(TenantAIConfig config, LocalTime callTime) {
        Map<String, Object> rules = config.getRoutingRules();

        // Time-based routing
        if (rules.containsKey("timeRules")) {
            try {
                @SuppressWarnings("unchecked")
                java.util.List<Map<String, String>> timeRules = (java.util.List<Map<String, String>>) rules
                        .get("timeRules");

                for (Map<String, String> rule : timeRules) {
                    LocalTime start = LocalTime.parse(rule.get("start"));
                    LocalTime end = LocalTime.parse(rule.get("end"));

                    boolean inRange;
                    if (end.isBefore(start)) {
                        // Overnight range (e.g., 17:00 to 09:00)
                        inRange = callTime.isAfter(start) || callTime.isBefore(end);
                    } else {
                        // Same-day range (e.g., 09:00 to 17:00)
                        inRange = callTime.isAfter(start) && callTime.isBefore(end);
                    }

                    if (inRange) {
                        String providerStr = rule.get("provider");
                        return AIProvider.valueOf(providerStr);
                    }
                }
            } catch (Exception e) {
                log.error("Error applying time-based routing rules", e);
            }
        }

        return null;
    }
}
