package com.saas.voip.service;

import com.twilio.Twilio;
import com.twilio.rest.api.v2010.account.Message;
import com.twilio.type.PhoneNumber;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import jakarta.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

@Service
@Slf4j
public class SmsService {

    public enum Provider {
        TWILIO, TELNYX, ZIWO
    }

    private final RestTemplate restTemplate = new RestTemplate();
    private final ZiwoApiService ziwoApiService;

    @Value("${twilio.account.sid:}")
    private String twilioAccountSid;

    @Value("${twilio.auth.token:}")
    private String twilioAuthToken;

    @Value("${twilio.phone.number:}")
    private String twilioPhoneNumber;

    @Value("${telnyx.api.key:}")
    private String telnyxApiKey;

    @Value("${telnyx.messaging.profile.id:}")
    private String telnyxMessagingProfileId;

    private static final String TELNYX_SMS_API = "https://api.telnyx.com/v2/messages";
    private static final DateTimeFormatter FRENCH_DATE_FORMATTER = 
        DateTimeFormatter.ofPattern("EEEE dd MMMM yyyy 'à' HH'h'mm", Locale.FRENCH);

    public SmsService(ZiwoApiService ziwoApiService) {
        this.ziwoApiService = ziwoApiService;
    }

    @PostConstruct
    public void init() {
        if (twilioAccountSid != null && !twilioAccountSid.isEmpty() 
            && twilioAuthToken != null && !twilioAuthToken.isEmpty()) {
            try {
                Twilio.init(twilioAccountSid, twilioAuthToken);
                log.info("Twilio SMS initialized with number: {}", twilioPhoneNumber);
            } catch (Exception e) {
                log.warn("Failed to initialize Twilio: {}", e.getMessage());
            }
        }
    }

    public String sendAppointmentConfirmation(
            Provider provider,
            String fromPhoneNumber,
            String toPhoneNumber,
            String patientName,
            String doctorName,
            LocalDateTime appointmentDateTime,
            String statusCallbackUrl) {
        
        if (appointmentDateTime == null) {
            log.warn("Appointment date/time is null, cannot send SMS to {}", toPhoneNumber);
            return null;
        }

        String formattedDateTime = appointmentDateTime.format(FRENCH_DATE_FORMATTER);
        String messageBody = buildAppointmentMessage(patientName, doctorName, formattedDateTime);

        return switch (provider) {
            case TWILIO -> sendViaTwilio(toPhoneNumber, messageBody, statusCallbackUrl);
            case TELNYX -> sendViaTelnyx(fromPhoneNumber, toPhoneNumber, messageBody, statusCallbackUrl);
            case ZIWO -> sendViaZiwo(fromPhoneNumber, toPhoneNumber, messageBody);
        };
    }

    public boolean sendCustomSms(Provider provider, String fromPhoneNumber, String toPhoneNumber, String messageBody) {
        String result = switch (provider) {
            case TWILIO -> sendViaTwilio(toPhoneNumber, messageBody, null);
            case TELNYX -> sendViaTelnyx(fromPhoneNumber, toPhoneNumber, messageBody, null);
            case ZIWO -> sendViaZiwo(fromPhoneNumber, toPhoneNumber, messageBody);
        };
        return result != null;
    }

    public String sendSms(Provider provider, String fromPhoneNumber, String toPhoneNumber, String messageBody, String webhookUrl) {
        return switch (provider) {
            case TWILIO -> sendViaTwilio(toPhoneNumber, messageBody, webhookUrl);
            case TELNYX -> sendViaTelnyx(fromPhoneNumber, toPhoneNumber, messageBody, webhookUrl);
            case ZIWO -> sendViaZiwo(fromPhoneNumber, toPhoneNumber, messageBody);
        };
    }

    private String sendViaTwilio(String toPhoneNumber, String messageBody, String statusCallbackUrl) {
        try {
            var messageCreator = Message.creator(
                    new PhoneNumber(toPhoneNumber),
                    new PhoneNumber(twilioPhoneNumber),
                    messageBody
            );
            
            if (statusCallbackUrl != null && !statusCallbackUrl.isEmpty()) {
                try {
                    messageCreator.setStatusCallback(java.net.URI.create(statusCallbackUrl));
                } catch (Exception e) {
                    log.warn("Failed to set status callback URL: {}", statusCallbackUrl);
                }
            }
            
            Message message = messageCreator.create();
            log.info("Twilio SMS sent - SID: {} Status: {} To: {}", 
                    message.getSid(), message.getStatus(), toPhoneNumber);
            
            return message.getSid();

        } catch (Exception e) {
            log.error("Twilio SMS error to {}: {}", toPhoneNumber, e.getMessage());
            return null;
        }
    }

    private String sendViaTelnyx(String fromPhoneNumber, String toPhoneNumber, String text, String webhookUrl) {
        if (fromPhoneNumber == null || fromPhoneNumber.isEmpty()) {
            log.error("Telnyx SMS requires fromPhoneNumber, but it was null or empty");
            return null;
        }
        
        try {
            Map<String, Object> payload = new HashMap<>();
            payload.put("from", fromPhoneNumber);
            payload.put("to", toPhoneNumber);
            payload.put("text", text);
            
            if (telnyxMessagingProfileId != null && !telnyxMessagingProfileId.isEmpty()) {
                payload.put("messaging_profile_id", telnyxMessagingProfileId);
            }
            
            if (webhookUrl != null && !webhookUrl.isEmpty()) {
                payload.put("webhook_url", webhookUrl);
            }

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.setBearerAuth(telnyxApiKey);

            HttpEntity<Map<String, Object>> request = new HttpEntity<>(payload, headers);

            ResponseEntity<Map> response = restTemplate.exchange(TELNYX_SMS_API, HttpMethod.POST, request, Map.class);

            if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
                @SuppressWarnings("unchecked")
                Map<String, Object> data = (Map<String, Object>) response.getBody().get("data");
                String messageId = data != null ? (String) data.get("id") : null;
                
                log.info("Telnyx SMS sent - ID: {} To: {}", messageId, toPhoneNumber);
                return messageId;
            } else {
                log.error("Telnyx SMS failed - Status: {}", response.getStatusCode());
                return null;
            }

        } catch (Exception e) {
            log.error("Telnyx SMS error: {}", e.getMessage());
            return null;
        }
    }

    private String sendViaZiwo(String fromPhoneNumber, String toPhoneNumber, String message) {
        if (fromPhoneNumber == null || fromPhoneNumber.isEmpty()) {
            log.error("Ziwo SMS requires fromPhoneNumber, but it was null or empty");
            return null;
        }
        
        try {
            Map<String, Object> result = ziwoApiService.sendSms(fromPhoneNumber, toPhoneNumber, message);

            if (result != null) {
                String messageId = result.get("message_id") != null ? result.get("message_id").toString() : null;
                log.info("Ziwo SMS sent - ID: {} To: {}", messageId, toPhoneNumber);
                return messageId;
            } else {
                log.error("Ziwo SMS failed");
                return null;
            }

        } catch (Exception e) {
            log.error("Ziwo SMS error: {}", e.getMessage());
            return null;
        }
    }

    private String buildAppointmentMessage(String patientName, String doctorName, String formattedDateTime) {
        return String.format(
            "Confirmation de rendez-vous - Clinique La Rive Bleue\n\n" +
            "Bonjour %s,\n\n" +
            "Votre rendez-vous avec %s est confirmé pour le %s.\n\n" +
            "Merci de votre confiance.\n\n" +
            "Clinique La Rive Bleue",
            patientName != null ? patientName : "cher(e) patient(e)",
            doctorName != null ? doctorName : "le médecin",
            formattedDateTime
        );
    }

    public boolean isTwilioConfigured() {
        return twilioAccountSid != null && !twilioAccountSid.isEmpty() 
            && twilioAuthToken != null && !twilioAuthToken.isEmpty();
    }

    public boolean isTelnyxConfigured() {
        return telnyxApiKey != null && !telnyxApiKey.isEmpty();
    }
}
