package com.saas.admin.service;

import com.saas.admin.entity.TenantVoipConfig;
import com.saas.admin.repository.TenantVoipConfigRepository;
import com.saas.shared.audit.Auditable;
import com.saas.shared.enums.Provider;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * Admin service for managing tenant-specific VoIP configurations.
 * 
 * Responsibilities:
 * - CRUD operations for VoIP configs (admin only)
 * - Cache eviction after modifications
 * - Used by AdminTenantVoipConfigController
 * 
 * This service is separated from runtime resolution (handled by TenantVoipConfigRuntimeService)
 * to follow Clean Architecture and Single Responsibility Principle.
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class TenantVoipConfigAdminService {
    
    private final TenantVoipConfigRepository voipConfigRepository;
    
    /**
     * Get VoIP configuration by ID (admin use only)
     * For runtime resolution, use TenantVoipConfigRuntimeService instead.
     * 
     * @param id Configuration ID
     * @return Optional VoIP configuration
     */
    @Transactional(readOnly = true)
    public Optional<TenantVoipConfig> getVoipConfigById(Long id) {
        log.debug("Admin fetching VoIP config by ID: {}", id);
        return voipConfigRepository.findById(id);
    }
    
    /**
     * Get VoIP configuration for a tenant and provider (admin use only)
     * Returns database config only, NO environment variable fallback.
     * 
     * @param tenantId The tenant identifier
     * @param provider The VoIP provider (TELNYX, TWILIO, ZIWO)
     * @return Optional VoIP configuration from database
     */
    @Transactional(readOnly = true)
    public Optional<TenantVoipConfig> getVoipConfig(String tenantId, Provider provider) {
        log.debug("Admin fetching VoIP config for tenant: {}, provider: {}", tenantId, provider);
        return voipConfigRepository.findByTenantIdAndProvider(tenantId, provider);
    }
    
    /**
     * Create or update VoIP configuration for a tenant
     * Evicts runtime cache after save
     */
    @CacheEvict(value = "voipConfigs", key = "#config.tenantId + '_' + #config.provider")
    @Transactional
    @Auditable(action = "SAVE_VOIP_CONFIG", entityType = "VOIP_CONFIG")
    public TenantVoipConfig saveVoipConfig(TenantVoipConfig config) {
        log.info("💾 Admin saving VoIP config for tenant: {}, provider: {}", 
                 config.getTenantId(), config.getProvider());
        
        // Check if config already exists (unique constraint: tenant_id + provider)
        Optional<TenantVoipConfig> existing = voipConfigRepository
            .findByTenantIdAndProvider(config.getTenantId(), config.getProvider());
        
        if (existing.isPresent()) {
            // Update existing
            TenantVoipConfig existingConfig = existing.get();
            existingConfig.setAiAssistantId(config.getAiAssistantId());
            existingConfig.setAiType(config.getAiType());
            existingConfig.setMessagingProfileId(config.getMessagingProfileId());
            existingConfig.setStreamUrl(config.getStreamUrl());
            existingConfig.setIsActive(config.getIsActive());
            existingConfig.setMetadata(config.getMetadata());
            
            log.info("✅ Updated existing VoIP config ID: {}", existingConfig.getId());
            return voipConfigRepository.save(existingConfig);
        }
        
        // Create new
        TenantVoipConfig saved = voipConfigRepository.save(config);
        log.info("✅ Created new VoIP config ID: {}", saved.getId());
        return saved;
    }
    
    /**
     * Get all VoIP configs for a tenant
     */
    @Transactional(readOnly = true)
    public List<TenantVoipConfig> getAllConfigsForTenant(String tenantId) {
        log.debug("Fetching all VoIP configs for tenant: {}", tenantId);
        return voipConfigRepository.findByTenantId(tenantId);
    }
    
    /**
     * Delete VoIP configuration
     * Always evicts cache, even if config doesn't exist
     */
    @CacheEvict(value = "voipConfigs", key = "#tenantId + '_' + #provider")
    @Transactional
    @Auditable(action = "DELETE_VOIP_CONFIG", entityType = "VOIP_CONFIG")
    public void deleteVoipConfig(String tenantId, Provider provider) {
        log.info("🗑️ Admin deleting VoIP config for tenant: {}, provider: {}", tenantId, provider);
        
        Optional<TenantVoipConfig> config = voipConfigRepository
            .findByTenantIdAndProvider(tenantId, provider);
        
        if (config.isPresent()) {
            voipConfigRepository.delete(config.get());
            log.info("✅ Deleted VoIP config ID: {}", config.get().getId());
        } else {
            log.warn("⚠️ No config found to delete for tenant: {}, provider: {}", tenantId, provider);
        }
        
        // Cache is evicted regardless via @CacheEvict annotation
    }
    
    /**
     * Activate/Deactivate VoIP configuration
     * Always evicts cache, even if config doesn't exist
     */
    @CacheEvict(value = "voipConfigs", key = "#tenantId + '_' + #provider")
    @Transactional
    public void toggleVoipConfig(String tenantId, Provider provider, boolean isActive) {
        log.info("🔄 Admin toggling VoIP config to {} for tenant: {}, provider: {}", 
                 isActive, tenantId, provider);
        
        Optional<TenantVoipConfig> config = voipConfigRepository
            .findByTenantIdAndProvider(tenantId, provider);
        
        if (config.isPresent()) {
            config.get().setIsActive(isActive);
            voipConfigRepository.save(config.get());
            log.info("✅ Toggled VoIP config ID: {} to active={}", config.get().getId(), isActive);
        } else {
            log.warn("⚠️ No config found to toggle for tenant: {}, provider: {}", tenantId, provider);
        }
        
        // Cache is evicted regardless via @CacheEvict annotation
    }
}
