package com.saas.voip.extractor;

import com.saas.tenant.entity.InboundCallData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

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

@Component
@Slf4j
public class ZiwoCallDataExtractor {

    private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_DATE_TIME;

    public InboundCallData extractFromZiwoRequest(Map<String, Object> payload) {
        InboundCallData callData = new InboundCallData();

        try {
            callData.setCallSid(getString(payload, "call_id"));
            callData.setFromNumber(getString(payload, "from"));
            callData.setToNumber(getString(payload, "to"));
            callData.setDirection(getString(payload, "direction", "inbound"));
            callData.setCallStatus(getString(payload, "status", "initiated"));

            Map<String, Object> callerLocation = getMap(payload, "caller_location");
            if (callerLocation != null) {
                callData.setFromCity(getString(callerLocation, "city"));
                callData.setFromState(getString(callerLocation, "state"));
                callData.setFromCountry(getString(callerLocation, "country"));
            }

            callData.setCaller(getString(payload, "caller_name"));

            String startTimeStr = getString(payload, "start_time");
            if (startTimeStr != null && !startTimeStr.isEmpty()) {
                callData.setStartTime(parseDateTime(startTimeStr));
            }

            String endTimeStr = getString(payload, "end_time");
            if (endTimeStr != null && !endTimeStr.isEmpty()) {
                callData.setEndTime(parseDateTime(endTimeStr));
            }

            Integer duration = getInteger(payload, "duration");
            if (duration != null) {
                callData.setDuration(duration);
            }

            callData.setRecordingUrl(getString(payload, "recording_url"));
            callData.setRecordingSid(getString(payload, "recording_sid"));

            log.debug("Extracted Ziwo call data: CallSid={}, From={}, To={}", 
                     callData.getCallSid(), callData.getFromNumber(), callData.getToNumber());

            return callData;

        } catch (Exception e) {
            log.error("Error extracting Ziwo call data", e);
            return callData;
        }
    }

    public void updateCallDataWithEvent(InboundCallData callData, Map<String, Object> eventPayload) {
        try {
            String event = getString(eventPayload, "event");
            
            if (event == null) {
                return;
            }

            switch (event) {
                case "call.initiated":
                    callData.setCallStatus("initiated");
                    String startTimeStr = getString(eventPayload, "start_time");
                    if (startTimeStr != null && !startTimeStr.isEmpty()) {
                        callData.setStartTime(parseDateTime(startTimeStr));
                    }
                    break;

                case "call.answered":
                    callData.setCallStatus("in-progress");
                    break;

                case "call.completed":
                    callData.setCallStatus("completed");
                    String endTimeStr = getString(eventPayload, "end_time");
                    if (endTimeStr != null && !endTimeStr.isEmpty()) {
                        callData.setEndTime(parseDateTime(endTimeStr));
                    }
                    Integer duration = getInteger(eventPayload, "duration");
                    if (duration != null) {
                        callData.setDuration(duration);
                    }
                    String recordingUrl = getString(eventPayload, "recording_url");
                    if (recordingUrl != null && !recordingUrl.isEmpty()) {
                        callData.setRecordingUrl(recordingUrl);
                    }
                    break;

                case "call.failed":
                case "call.no-answer":
                case "call.busy":
                    callData.setCallStatus(event.replace("call.", ""));
                    break;

                default:
                    log.debug("Unhandled Ziwo event type: {}", event);
            }

            log.debug("Updated Ziwo call data with event: {}", event);

        } catch (Exception e) {
            log.error("Error updating Ziwo call data with event", e);
        }
    }

    private String getString(Map<String, Object> map, String key) {
        return getString(map, key, null);
    }

    private String getString(Map<String, Object> map, String key, String defaultValue) {
        Object value = map.get(key);
        if (value == null) {
            return defaultValue;
        }
        return value.toString();
    }

    private Integer getInteger(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return null;
        }
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        try {
            return Integer.parseInt(value.toString());
        } catch (NumberFormatException e) {
            log.warn("Could not parse integer value for key {}: {}", key, value);
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> getMap(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value instanceof Map) {
            return (Map<String, Object>) value;
        }
        return null;
    }

    private LocalDateTime parseDateTime(String dateTimeStr) {
        if (dateTimeStr == null || dateTimeStr.isEmpty()) {
            return null;
        }

        try {
            return LocalDateTime.parse(dateTimeStr, ISO_FORMATTER);
        } catch (DateTimeParseException e) {
            log.warn("Could not parse datetime: {}", dateTimeStr);
            return null;
        }
    }
}
