package com.saas.voip.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.saas.tenant.entity.InboundCallRequest;
import com.saas.tenant.service.InboundCallService;
import com.saas.voip.handler.ElevenLabsSessionHandler;
import com.saas.voip.service.SmsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;

@RestController
@RequestMapping("/api/voip/elevenlabs")
@RequiredArgsConstructor
@Slf4j
public class ElevenLabsCallbackController {
    
    private final InboundCallService inboundCallService;
    private final ElevenLabsSessionHandler elevenLabsSessionHandler;
    private final SmsService smsService;
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    @Value("${server.base-url:http://localhost:8000}")
    private String serverBaseUrl;
    
    @PostMapping("/call-summary")
    public ResponseEntity<Map<String, Object>> handleCallSummary(
            @RequestBody Map<String, Object> payload,
            @RequestParam(required = false) String sessionId) {
        
        log.info("Received ElevenLabs call summary: {}", payload);
        
        try {
            // Extract conversation_id from payload
            String conversationId = null;
            if (payload.containsKey("data") && payload.get("data") instanceof Map) {
                Map<String, Object> data = (Map<String, Object>) payload.get("data");
                if (data.containsKey("conversation_id")) {
                    conversationId = data.get("conversation_id").toString();
                }
            }
            
            // Try to get callSid from conversation_id first, then from sessionId
            String callSid = null;
            if (conversationId != null) {
                callSid = elevenLabsSessionHandler.getCallSidByConversationId(conversationId);
                log.info("📞 Found callSid {} for conversation_id {}", callSid, conversationId);
            }
            if (callSid == null && sessionId != null) {
                callSid = elevenLabsSessionHandler.getCallSid(sessionId);
            }
            if (callSid == null && payload.containsKey("call_sid")) {
                callSid = payload.get("call_sid").toString();
            }
            
            if (callSid != null) {
                String nom = getStringValue(payload, "nom", "patient_name");
                String dateNaissance = getStringValue(payload, "date_naissance", "birthdate");
                String telephone = getStringValue(payload, "telephone", "phone");
                String maladie = getStringValue(payload, "maladie", "illness");
                String motifVisite = getStringValue(payload, "motif_visite", "visit_reason");
                String doctorName = getStringValue(payload, "doctor_name");
                String appointmentDateTimeStr = getStringValue(payload, "appointment_date_time", "appointment_datetime");
                Boolean confirmed = getBooleanValue(payload, "appointment_confirmed", "confirmed");
                
                LocalDateTime appointmentDateTime = null;
                if (appointmentDateTimeStr != null) {
                    try {
                        appointmentDateTime = LocalDateTime.parse(appointmentDateTimeStr);
                    } catch (Exception e) {
                        log.warn("Failed to parse appointment date/time: {}", appointmentDateTimeStr);
                    }
                }
                
                InboundCallRequest request = InboundCallRequest.builder()
                        .callSid(callSid)
                        .nom(nom)
                        .dateNaissance(dateNaissance)
                        .telephone(telephone)
                        .maladie(maladie)
                        .motifVisite(motifVisite)
                        .appointmentDateTime(appointmentDateTime)
                        .doctorName(doctorName)
                        .appointmentConfirmed(confirmed != null && confirmed)
                        .smsSent(false)
                        .build();
                
                // Try to get transcript from ElevenLabs payload first
                String transcript = null;
                if (conversationId != null && payload.containsKey("data") && payload.get("data") instanceof Map) {
                    Map<String, Object> data = (Map<String, Object>) payload.get("data");
                    if (data.containsKey("transcript")) {
                        transcript = objectMapper.writeValueAsString(data.get("transcript"));
                        log.info("📝 Extracted transcript from ElevenLabs payload");
                    }
                }
                // Fallback to stored transcript
                if (transcript == null && conversationId != null) {
                    transcript = elevenLabsSessionHandler.getTranscriptByConversationId(conversationId);
                }
                if (transcript == null && sessionId != null) {
                    transcript = elevenLabsSessionHandler.getTranscript(sessionId);
                }
                if (transcript != null) {
                    request.setConversationTranscript(transcript);
                }
                
                InboundCallRequest savedRequest = inboundCallService.savePatientRequest(request);
                log.info("Saved ElevenLabs patient data for callSid: {}", callSid);
                
                if (Boolean.TRUE.equals(savedRequest.getAppointmentConfirmed()) && 
                    savedRequest.getAppointmentDateTime() != null &&
                    savedRequest.getTelephone() != null &&
                    savedRequest.getDoctorName() != null) {
                    
                    log.info("📱 Envoi du SMS de confirmation de RDV...");
                    
                    String statusCallbackUrl = serverBaseUrl + "/api/voip/sms/status-callback";
                    
                    String smsSid = smsService.sendAppointmentConfirmation(
                        SmsService.Provider.TWILIO,
                        null,
                        savedRequest.getTelephone(),
                        savedRequest.getNom(),
                        savedRequest.getDoctorName(),
                        savedRequest.getAppointmentDateTime(),
                        statusCallbackUrl
                    );
                    
                    if (smsSid != null) {
                        savedRequest.setSmsSent(true);
                        savedRequest.setSmsSid(smsSid);
                        savedRequest.setSmsStatus("queued");
                        inboundCallService.savePatientRequest(savedRequest);
                        log.info("✅ SMS de confirmation envoyé (SID: {})", smsSid);
                    }
                }
                
                return ResponseEntity.ok(Map.of("status", "success", "saved", true));
            } else {
                log.warn("No callSid found in ElevenLabs callback");
                return ResponseEntity.badRequest().body(Map.of("error", "Missing callSid"));
            }
            
        } catch (Exception e) {
            log.error("Error processing ElevenLabs callback", e);
            return ResponseEntity.internalServerError().body(Map.of("error", e.getMessage()));
        }
    }
    
    private String getStringValue(Map<String, Object> payload, String... keys) {
        for (String key : keys) {
            if (payload.containsKey(key) && payload.get(key) != null) {
                return payload.get(key).toString();
            }
        }
        return null;
    }
    
    private Boolean getBooleanValue(Map<String, Object> payload, String... keys) {
        for (String key : keys) {
            if (payload.containsKey(key) && payload.get(key) != null) {
                Object value = payload.get(key);
                if (value instanceof Boolean) {
                    return (Boolean) value;
                }
                return Boolean.valueOf(value.toString());
            }
        }
        return null;
    }
}
