package com.saas.voip.controller;

import com.saas.admin.entity.PhoneNumber;
import com.saas.admin.entity.Tenant;
import com.saas.admin.repository.PhoneNumberRepository;
import com.saas.admin.repository.TenantRepository;
import com.saas.shared.core.TenantContext;
import com.saas.shared.enums.Provider;
import com.saas.tenant.entity.InboundCallData;
import com.saas.tenant.service.InboundCallService;
import com.saas.voip.extractor.TelnyxCallDataExtractor;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;

import java.util.Enumeration;
import java.util.Map;
import java.util.Optional;

@RestController
@RequestMapping("/api/voip/telnyx")
@Slf4j
@RequiredArgsConstructor
public class TelnyxVoiceController {

    private final TelnyxCallDataExtractor callDataExtractor;
    private final InboundCallService inboundCallService;
    private final PhoneNumberRepository phoneNumberRepository;
    private final TenantRepository tenantRepository;

    @PostMapping(value = "/incoming-call", produces = MediaType.APPLICATION_JSON_VALUE)
    public Map<String, Object> handleIncomingCall(HttpServletRequest request, @RequestBody Map<String, Object> payload) {
        
        log.info("=== TELNYX WEBHOOK RECEIVED ===");
        
        // Extract event type from Telnyx webhook
        Map<String, Object> eventData = (Map<String, Object>) payload.get("data");
        String eventType = (String) eventData.get("event_type");
        
        log.info("📞 Event Type: {}", eventType);
        
        // Only handle call.initiated events for incoming calls
        if (!"call.initiated".equals(eventType)) {
            log.info("⏭️ Ignoring event type: {}", eventType);
            return Map.of("status", "ignored", "event_type", eventType);
        }
        
        Map<String, Object> callPayload = (Map<String, Object>) eventData.get("payload");
        
        String fromNumber = (String) callPayload.get("from");
        String toNumber = (String) callPayload.get("to");
        String callControlId = (String) callPayload.get("call_control_id");
        String callSessionId = (String) callPayload.get("call_session_id");
        String direction = (String) callPayload.get("direction");
        
        log.info("📞 Direction: {}, From: {}, To: {}", direction, fromNumber, toNumber);
        log.info("🆔 Call Control ID: {}, Session ID: {}", callControlId, callSessionId);
        
        // Only handle incoming calls
        if (!"incoming".equals(direction)) {
            log.info("⏭️ Ignoring non-incoming call");
            return Map.of("status", "ignored", "direction", direction);
        }
        
        String schemaName = null;
        String tenantId = null;
        
        // Identify tenant via phone number
        if (toNumber != null) {
            try {
                Optional<PhoneNumber> phoneOpt = phoneNumberRepository.findByPhoneNumber(toNumber);
                
                if (phoneOpt.isPresent() && phoneOpt.get().getProvider() == Provider.TELNYX) {
                    tenantId = phoneOpt.get().getTenantId();
                    log.info("📞 Identified Tenant ID: {} for Telnyx number: {}", tenantId, toNumber);
                    
                    // Get tenant schema
                    Optional<Tenant> tenant = tenantRepository.findByTenantId(tenantId);
                    if (tenant.isPresent()) {
                        schemaName = tenant.get().getSchemaName();
                        log.info("📊 Using schema: {} for tenant: {}", schemaName, tenantId);
                    }
                } else {
                    log.warn("⚠️ No Telnyx tenant found for phone number: {}", toNumber);
                }
            } catch (Exception e) {
                log.error("Error looking up tenant", e);
            }
        }
        
        // Save call data to tenant schema
        if (schemaName != null && callSessionId != null) {
            TenantContext.setTenantId(schemaName);
            
            try {
                // Extract and save call data
                InboundCallData callData = callDataExtractor.extractFromTelnyxRequest(payload);
                inboundCallService.saveCallData(callData);
                
                log.info("✅ Telnyx call data saved to tenant schema: {}", schemaName);
            } catch (Exception e) {
                log.error("Error saving Telnyx call data", e);
            } finally {
                TenantContext.clear();
            }
        }
        
        // IMPORTANT: For Telnyx, you must use the Call Control API to:
        // 1. Answer the call: POST /v2/calls/{call_control_id}/actions/answer
        // 2. Start AI assistant: POST /v2/calls/{call_control_id}/actions/start_ai_assistant
        //
        // Unlike Twilio TwiML, Telnyx webhooks just return 200 OK.
        // Call control happens via separate REST API calls.
        
        log.warn("⚠️ TELNYX CONFIGURATION REQUIRED:");
        log.warn("   To answer calls and start AI, you need to:");
        log.warn("   1. Use Telnyx Call Control API (not webhook responses)");
        log.warn("   2. Configure TeXML Application in Telnyx Portal");
        log.warn("   3. OR use Telnyx SDK to answer call programmatically");
        log.warn("   Call Control ID: {}", callControlId);
        
        // Return 200 OK - Telnyx doesn't expect commands in webhook response
        return Map.of(
            "status", "received",
            "call_control_id", callControlId,
            "message", "Use Telnyx Call Control API or TeXML to handle this call"
        );
    }
    
    @PostMapping(value = "/call-initiated", produces = MediaType.APPLICATION_JSON_VALUE)
    public void handleCallInitiated(@RequestBody Map<String, Object> payload) {
        log.info("📞 Telnyx call initiated event received");
        // Log the event, no action needed
    }
    
    @PostMapping(value = "/call-answered", produces = MediaType.APPLICATION_JSON_VALUE)
    public void handleCallAnswered(@RequestBody Map<String, Object> payload) {
        log.info("✅ Telnyx call answered event received");
    }
    
    @PostMapping(value = "/call-hangup", produces = MediaType.APPLICATION_JSON_VALUE)
    public void handleCallHangup(@RequestBody Map<String, Object> payload) {
        log.info("📴 Telnyx call hangup event received");
        
        Map<String, Object> eventData = (Map<String, Object>) payload.get("data");
        Map<String, Object> callPayload = (Map<String, Object>) eventData.get("payload");
        
        String callSessionId = (String) callPayload.get("call_session_id");
        
        // Update call status in database
        // TODO: Extract duration and update
    }
    
    @GetMapping("/health")
    public String health() {
        return "Telnyx VoIP Service is running!";
    }
    
    /**
     * Get Telnyx AI Assistant ID for a tenant
     * Can be configured per tenant or use a global default
     */
    private String getTelnyxAIAssistantId(String tenantId) {
        // TODO: Implement tenant-specific AI assistant lookup
        // For now, return default or from env variable
        String defaultAssistantId = System.getenv("TELNYX_AI_ASSISTANT_ID");
        return defaultAssistantId != null ? defaultAssistantId : "default-assistant";
    }
}
