package com.saas.voip.controller;

import com.saas.admin.entity.Tenant;
import com.saas.admin.repository.TenantRepository;
import com.saas.admin.service.PhoneNumberService;
import com.saas.shared.core.TenantContext;
import com.saas.shared.enums.VoiceAiProviderType;
import com.saas.shared.service.DualSaveCallDataService;
import com.saas.tenant.entity.InboundCallData;
import com.saas.tenant.service.InboundCallService;
import com.saas.voip.config.VoiceAiConfig;
import com.saas.voip.extractor.CallDataExtractor;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
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.Optional;

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

    @Value("${server.port:8000}")
    private String serverPort;
    
    private final CallDataExtractor callDataExtractor;
    private final DualSaveCallDataService dualSaveCallDataService;
    private final PhoneNumberService phoneNumberService;
    private final TenantRepository tenantRepository;
    private final VoiceAiConfig voiceAiConfig;

    @GetMapping(value = "/incoming-call", produces = MediaType.APPLICATION_XML_VALUE)
    public String handleIncomingCallGet(HttpServletRequest request) {
        return handleIncomingCall(request);
    }

    @PostMapping(value = "/incoming-call", produces = MediaType.APPLICATION_XML_VALUE)
    public String handleIncomingCallPost(HttpServletRequest request) {
        return handleIncomingCall(request);
    }

    private String handleIncomingCall(HttpServletRequest request) {
        String host = request.getHeader("Host");
        String scheme = request.getScheme();
        String forwardedProto = request.getHeader("X-Forwarded-Proto");
        
        log.info("=== INCOMING CALL FROM TWILIO ===");
        log.info("Host: {}", host);
        log.info("Scheme: {}", scheme);
        log.info("X-Forwarded-Proto: {}", forwardedProto);

        // Extract form data and identify tenant
        MultiValueMap<String, String> formData = extractFormData(request);
        String toNumber = formData.getFirst("To");
        String schemaName = null;
        
        if (toNumber != null) {
            try {
                // Set admin context for phone number and tenant lookup
                TenantContext.setTenantId("saas_db");
                
                Optional<String> foundTenantId = phoneNumberService.getTenantIdByPhoneNumber(toNumber);
                if (foundTenantId.isPresent()) {
                    String tenantId = foundTenantId.get();
                    log.info("📞 Identified Tenant ID: {} for phone number: {}", tenantId, toNumber);
                    
                    // Get tenant schema name
                    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 tenant found for phone number: {}", toNumber);
                }
            } finally {
                TenantContext.clear();
            }
        }

        // Extract and save call data to BOTH admin + tenant databases
        if (schemaName != null) {
            try {
                InboundCallData callData = callDataExtractor.extractFromTwilioRequest(formData);
                // Save to BOTH admin (saas_db) and tenant schema for complete data tracking
                dualSaveCallDataService.saveToBothDatabases(callData, schemaName);
                log.info("✅ Twilio call data saved to BOTH admin + tenant databases");
            } catch (Exception e) {
                log.error("Error saving Twilio call data", e);
            }
        } else {
            log.warn("⚠️ Skipping call data persistence - no tenant schema identified");
        }

        // Use WSS for HTTPS or when behind a proxy like ngrok
        String wsProtocol = ("https".equals(forwardedProto) || "https".equals(scheme)) ? "wss" : "ws";
        String wsUrl = wsProtocol + "://" + host + "/media-stream";
        
        log.info("Generated WebSocket URL: {}", wsUrl);

        // Build TwiML based on AI provider
        VoiceAiProviderType provider = voiceAiConfig.getProvider();
        String twiml;
        
        // Get call parameters from formData
        String fromNumber = formData.getFirst("From");
        String toNumberParam = formData.getFirst("To");
        
        if (provider == VoiceAiProviderType.ELEVENLABS) {
            // ElevenLabs: Skip <Say> - let the agent's "first message" speak
            log.info("🎙️ ElevenLabs mode: Agent will deliver welcome message from dashboard");
            twiml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                   "<Response>" +
                   "  <Connect>" +
                   "    <Stream url=\"" + wsUrl + "\">" +
                   "      <Parameter name=\"From\" value=\"" + fromNumber + "\" />" +
                   "      <Parameter name=\"To\" value=\"" + toNumberParam + "\" />" +
                   "    </Stream>" +
                   "  </Connect>" +
                   "</Response>";
        } else {
            // OpenAI: Use TwiML <Say> for legal disclaimer
            log.info("🎙️ OpenAI mode: TwiML will deliver welcome message");
            twiml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                   "<Response>" +
                   "  <Say voice=\"alice\" language=\"fr-FR\">" +
                   "    Bonjour, vous êtes en contact avec la Clinique La Rive Bleue. Cet appel est enregistré afin d'améliorer la qualité de nos services." +
                   "  </Say>" +
                   "  <Connect>" +
                   "    <Stream url=\"" + wsUrl + "\">" +
                   "      <Parameter name=\"From\" value=\"" + fromNumber + "\" />" +
                   "      <Parameter name=\"To\" value=\"" + toNumberParam + "\" />" +
                   "    </Stream>" +
                   "  </Connect>" +
                   "</Response>";
        }
        
        log.info("Returning TwiML for provider {}: {}", provider, twiml);
        return twiml;
    }

    @GetMapping("/health")
    public String health() {
        return "Twilio VoIP Service is running!";
    }
    
    private MultiValueMap<String, String> extractFormData(HttpServletRequest request) {
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        Enumeration<String> parameterNames = request.getParameterNames();
        
        while (parameterNames.hasMoreElements()) {
            String paramName = parameterNames.nextElement();
            String[] paramValues = request.getParameterValues(paramName);
            for (String paramValue : paramValues) {
                formData.add(paramName, paramValue);
            }
        }
        
        return formData;
    }
}
