package com.saas.tenant.controller;

import com.saas.admin.dto.request.UpdateVoipConfigRequest;
import com.saas.admin.dto.response.VoipConfigResponse;
import com.saas.admin.entity.TenantVoipConfig;
import com.saas.admin.service.TenantVoipConfigAdminService;
import com.saas.shared.core.TenantContext;
import com.saas.shared.dto.VoipConfigDTO;
import com.saas.shared.dto.mapper.VoipConfigMapper;
import com.saas.shared.enums.Provider;
import com.saas.shared.service.TenantVoipConfigRuntimeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;

/**
 * Tenant API for managing their own VoIP configurations.
 * Self-service endpoint - tenants can view and update their VoIP settings.
 * 
 * Protected with @PreAuthorize("hasRole('TENANT_USER')") to ensure only tenants access this.
 */
@RestController
@RequestMapping("/api/tenant/voip-configs")
@PreAuthorize("hasRole('TENANT_USER')")
@Tag(name = "Tenant VoIP Config", description = "Self-service VoIP configuration management for tenants")
@Slf4j
@RequiredArgsConstructor
public class TenantVoipConfigController {

    private final TenantVoipConfigRuntimeService voipRuntimeService;
    private final TenantVoipConfigAdminService voipAdminService;
    private final VoipConfigMapper voipConfigMapper;

    /**
     * Get current VoIP configuration for this tenant
     * Returns resolved config (DB first, then environment fallback)
     * 
     * GET /api/tenant/voip-configs/{provider}
     */
    @GetMapping("/{provider}")
    @Operation(summary = "Get VoIP configuration", 
               description = "Get current VoIP configuration for this tenant and provider. Returns database config if available, otherwise environment defaults.")
    public ResponseEntity<VoipConfigDTO> getVoipConfig(@PathVariable Provider provider) {
        String tenantId = TenantContext.getTenantId();
        
        log.info("📞 Tenant {} requesting VoIP config for provider: {}", tenantId, provider);
        
        // Use RuntimeService to get resolved config (DB or env)
        Optional<VoipConfigDTO> config = voipRuntimeService.resolveVoipConfig(tenantId, provider);
        
        if (config.isEmpty()) {
            log.warn("⚠️ No VoIP configuration available for tenant: {}, provider: {}", tenantId, provider);
            return ResponseEntity.notFound().build();
        }
        
        log.info("✅ Returning VoIP config (source: {})", 
                 config.get().isFromDatabase() ? "DATABASE" : "ENVIRONMENT");
        
        return ResponseEntity.ok(config.get());
    }
    
    /**
     * Update VoIP configuration for this tenant
     * Creates new config if doesn't exist, updates existing otherwise
     * 
     * PUT /api/tenant/voip-configs/{provider}
     */
    @PutMapping("/{provider}")
    @Operation(summary = "Update VoIP configuration", 
               description = "Update VoIP configuration for this tenant. Creates new if doesn't exist.")
    public ResponseEntity<VoipConfigResponse> updateVoipConfig(
            @PathVariable Provider provider,
            @Valid @RequestBody UpdateVoipConfigRequest request) {
        
        String tenantId = TenantContext.getTenantId();
        
        log.info("✏️ Tenant {} updating VoIP config for provider: {}", tenantId, provider);
        
        // Check if config exists in DB
        Optional<TenantVoipConfig> existingOpt = voipAdminService.getVoipConfig(tenantId, provider);
        
        TenantVoipConfig config;
        
        if (existingOpt.isPresent()) {
            // Update existing
            config = existingOpt.get();
            voipConfigMapper.updateEntity(request, config);
            log.info("📝 Updating existing VoIP config ID: {}", config.getId());
        } else {
            // Create new
            config = new TenantVoipConfig();
            config.setTenantId(tenantId);
            config.setProvider(provider);
            voipConfigMapper.updateEntity(request, config);
            
            // Default to active if not specified
            if (config.getIsActive() == null) {
                config.setIsActive(true);
            }
            
            log.info("➕ Creating new VoIP config for tenant");
        }
        
        // Save via AdminService (handles cache eviction)
        TenantVoipConfig saved = voipAdminService.saveVoipConfig(config);
        VoipConfigResponse response = voipConfigMapper.toResponse(saved);
        
        log.info("✅ VoIP config saved successfully with ID: {}", saved.getId());
        
        return ResponseEntity.ok(response);
    }
    
    /**
     * Check if tenant has a valid VoIP configuration
     * Useful for frontend to determine if VoIP features are available
     * 
     * GET /api/tenant/voip-configs/{provider}/status
     */
    @GetMapping("/{provider}/status")
    @Operation(summary = "Check VoIP configuration status", 
               description = "Returns whether this tenant has a valid VoIP configuration for the provider")
    public ResponseEntity<VoipConfigStatusResponse> checkVoipConfigStatus(@PathVariable Provider provider) {
        String tenantId = TenantContext.getTenantId();
        
        log.info("🔍 Tenant {} checking VoIP config status for provider: {}", tenantId, provider);
        
        boolean hasValidConfig = voipRuntimeService.hasValidConfig(tenantId, provider);
        
        Optional<VoipConfigDTO> config = voipRuntimeService.resolveVoipConfig(tenantId, provider);
        
        VoipConfigStatusResponse response = new VoipConfigStatusResponse(
            hasValidConfig,
            config.isPresent() && config.get().isFromDatabase() ? "DATABASE" : "ENVIRONMENT",
            config.map(VoipConfigDTO::isActive).orElse(false)
        );
        
        return ResponseEntity.ok(response);
    }
    
    /**
     * Response DTO for VoIP config status
     */
    public record VoipConfigStatusResponse(
        boolean hasValidConfig,
        String configSource,
        boolean isActive
    ) {}
}
