package com.dji.sample.psdk.service.impl;

import com.dji.sample.component.websocket.model.BizCodeEnum;
import com.dji.sample.component.websocket.service.IWebSocketMessageService;
import com.dji.sample.manage.model.dto.DeviceDTO;
import com.dji.sample.manage.service.IDeviceRedisService;
import com.dji.sample.psdk.model.dto.SpeakerPlayDTO;
import com.dji.sample.psdk.service.IPsdkService;
import com.dji.sdk.cloudapi.interconnection.CustomDataTransmissionFromPsdk;
import com.dji.sdk.cloudapi.interconnection.CustomDataTransmissionToPsdkRequest;
import com.dji.sdk.cloudapi.interconnection.InterconnectionMethodEnum;
import com.dji.sdk.cloudapi.psdk.*;
import com.dji.sdk.cloudapi.psdk.api.AbstractPsdkService;
import com.dji.sdk.mqtt.MqttReply;
import com.dji.sdk.mqtt.events.EventsDataRequest;
import com.dji.sdk.mqtt.events.TopicEventsRequest;
import com.dji.sdk.mqtt.events.TopicEventsResponse;
import com.dji.sdk.mqtt.services.ServicesPublish;
import com.dji.sdk.mqtt.services.ServicesReplyData;
import com.dji.sdk.mqtt.services.TopicServicesResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Service;

import java.util.Optional;

/**
 * PSDK service implementation
 * 
 * @author GeoFly Team
 * @version 1.0
 * @date 2026-02-03
 */
@Slf4j
@Service
public class PsdkServiceImpl extends AbstractPsdkService implements IPsdkService {

    @Autowired
    private IDeviceRedisService deviceRedisService;

    @Autowired
    private IWebSocketMessageService webSocketMessageService;

    // ==================== Event Handlers (Device to Cloud) ====================

    @Override
    public TopicEventsResponse<MqttReply> customDataTransmissionFromPsdk(
            TopicEventsRequest<CustomDataTransmissionFromPsdk> request, MessageHeaders headers) {
        
        String deviceSn = request.getGateway();
        CustomDataTransmissionFromPsdk data = request.getData();
        
        log.info("Received PSDK custom data - Device: {}, Data: {}", deviceSn, data.getValue());
        
        try {
            String workspaceId = getWorkspaceId(deviceSn);
            
            // 直接通过 WebSocket 推送给订阅者
            webSocketMessageService.sendBatch(workspaceId, BizCodeEnum.PSDK_CUSTOM_DATA.getCode(), data);
            
        } catch (Exception e) {
            log.error("Failed to handle PSDK custom data", e);
        }
        
        return new TopicEventsResponse<MqttReply>()
                .setData(MqttReply.success());
    }

    @Override
    public TopicEventsResponse<MqttReply> psdkUiResourceUploadResult(
            TopicEventsRequest<PsdkUiResourceUploadResult> request, MessageHeaders headers) {
        
        String deviceSn = request.getGateway();
        PsdkUiResourceUploadResult result = request.getData();
        
        log.info("Received PSDK UI resource upload result - Device: {}, PSDK Index: {}, Result: {}", 
                deviceSn, result.getPsdkIndex(), result.getResult());
        
        try {
            String workspaceId = getWorkspaceId(deviceSn);
            
            // 直接通过 WebSocket 推送给订阅者
            webSocketMessageService.sendBatch(workspaceId, BizCodeEnum.PSDK_UI_RESOURCE.getCode(), result);
            
        } catch (Exception e) {
            log.error("Failed to handle PSDK UI resource upload result", e);
        }
        
        return new TopicEventsResponse<MqttReply>()
                .setData(MqttReply.success());
    }

    @Override
    public TopicEventsResponse<MqttReply> psdkFloatingWindowText(
            TopicEventsRequest<PsdkFloatingWindowText> request, MessageHeaders headers) {
        
        String deviceSn = request.getGateway();
        PsdkFloatingWindowText floatingWindow = request.getData();
        
        log.info("Received PSDK floating window text - Device: {}, PSDK Index: {}, Text: {}", 
                deviceSn, floatingWindow.getPsdkIndex(), floatingWindow.getValue());
        
        try {
            String workspaceId = getWorkspaceId(deviceSn);
            
            // 直接通过 WebSocket 推送给订阅者
            webSocketMessageService.sendBatch(workspaceId, BizCodeEnum.PSDK_FLOATING_WINDOW.getCode(), floatingWindow);
            
        } catch (Exception e) {
            log.error("Failed to handle PSDK floating window text", e);
        }
        
        return new TopicEventsResponse<MqttReply>()
                .setData(MqttReply.success());
    }

    @Override
    public TopicEventsResponse<MqttReply> speakerAudioPlayStartProgress(
            TopicEventsRequest<EventsDataRequest<SpeakerAudioPlayStartProgress>> request, MessageHeaders headers) {
        
        String deviceSn = request.getGateway();
        SpeakerAudioPlayStartProgress progress = request.getData().getOutput();
        
        if (progress.getOutput() != null && progress.getOutput().getProgress() != null) {
            log.info("Received speaker audio play progress - Device: {}, PSDK Index: {}, Step: {}, Percent: {}%", 
                    deviceSn, 
                    progress.getOutput().getPsdkIndex(),
                    progress.getOutput().getProgress().getStepKey(),
                    progress.getOutput().getProgress().getPercent());
        }
        
        try {
            String workspaceId = getWorkspaceId(deviceSn);
            
            // 直接通过 WebSocket 推送给订阅者
            webSocketMessageService.sendBatch(workspaceId, BizCodeEnum.PSDK_SPEAKER_PROGRESS.getCode(), progress);
            
        } catch (Exception e) {
            log.error("Failed to handle speaker audio play progress", e);
        }
        
        return new TopicEventsResponse<MqttReply>()
                .setData(MqttReply.success());
    }

    @Override
    public TopicEventsResponse<MqttReply> speakerTtsPlayStartProgress(
            TopicEventsRequest<EventsDataRequest<SpeakerTtsPlayStartProgress>> request, MessageHeaders headers) {
        
        String deviceSn = request.getGateway();
        SpeakerTtsPlayStartProgress progress = request.getData().getOutput();
        
        if (progress.getOutput() != null && progress.getOutput().getProgress() != null) {
            log.info("Received speaker TTS play progress - Device: {}, PSDK Index: {}, Step: {}, Percent: {}%", 
                    deviceSn,
                    progress.getOutput().getPsdkIndex(),
                    progress.getOutput().getProgress().getStepKey(),
                    progress.getOutput().getProgress().getPercent());
        }
        
        try {
            String workspaceId = getWorkspaceId(deviceSn);
            
            // 直接通过 WebSocket 推送给订阅者
            webSocketMessageService.sendBatch(workspaceId, BizCodeEnum.PSDK_SPEAKER_PROGRESS.getCode(), progress);
            
        } catch (Exception e) {
            log.error("Failed to handle speaker TTS play progress", e);
        }
        
        return new TopicEventsResponse<MqttReply>()
                .setData(MqttReply.success());
    }

    // ==================== Service Methods (Cloud to Device) ====================

    @Autowired
    private ServicesPublish servicesPublish;

    @Override
    public TopicServicesResponse<ServicesReplyData> sendCustomDataToPsdk(String deviceSn, Integer psdkIndex, String data) {
        CustomDataTransmissionToPsdkRequest request = new CustomDataTransmissionToPsdkRequest()
                .setValue(data);
        
        log.info("Sending custom data to PSDK - Device: {}, Data: {}", deviceSn, data);
        
        return servicesPublish.publish(deviceSn, 
                InterconnectionMethodEnum.CUSTOM_DATA_TRANSMISSION_TO_PSDK.getMethod(), 
                request);
    }

    @Override
    public TopicServicesResponse<ServicesReplyData> setWidgetValue(String deviceSn, Integer psdkIndex, Integer widgetIndex, Integer value) {
        PsdkWidgetValueSetRequest request = new PsdkWidgetValueSetRequest()
                .setPsdkIndex(psdkIndex)
                .setIndex(widgetIndex)
                .setValue(value);
        
        log.info("Setting PSDK widget value - Device: {}, PSDK Index: {}, Widget: {}, Value: {}", 
                deviceSn, psdkIndex, widgetIndex, value);
        
        return servicesPublish.publish(deviceSn, 
                PsdkMethodEnum.WIDGET_VALUE_SET.getMethod(), 
                request);
    }

    @Override
    public TopicServicesResponse<ServicesReplyData> setInputBoxText(String deviceSn, Integer psdkIndex, String text) {
        PsdkInputBoxTextSetRequest request = new PsdkInputBoxTextSetRequest()
                .setPsdkIndex(psdkIndex)
                .setValue(text);
        
        log.info("Setting PSDK input box text - Device: {}, PSDK Index: {}, Text: {}", 
                deviceSn, psdkIndex, text);
        
        return servicesPublish.publish(deviceSn, 
                PsdkMethodEnum.INPUT_BOX_TEXT_SET.getMethod(), 
                request);
    }

    @Override
    public TopicServicesResponse<ServicesReplyData> playAudio(String deviceSn, SpeakerPlayDTO playDTO) {
        SpeakerAudioPlayStartRequest request = new SpeakerAudioPlayStartRequest()
                .setPsdkIndex(playDTO.getPsdkIndex())
                .setFile(new SpeakerAudioPlayStartRequest.AudioFile()
                        .setName(playDTO.getName())
                        .setUrl(playDTO.getUrl())
                        .setMd5(playDTO.getMd5())
                        .setFormat(playDTO.getFormat()));
        
        log.info("Playing audio on speaker - Device: {}, PSDK Index: {}, File: {}", 
                deviceSn, playDTO.getPsdkIndex(), playDTO.getName());
        
        return servicesPublish.publish(deviceSn, 
                PsdkMethodEnum.SPEAKER_AUDIO_PLAY_START.getMethod(), 
                request);
    }

    @Override
    public TopicServicesResponse<ServicesReplyData> playTts(String deviceSn, SpeakerPlayDTO playDTO) {
        SpeakerTtsPlayStartRequest request = new SpeakerTtsPlayStartRequest()
                .setPsdkIndex(playDTO.getPsdkIndex())
                .setTts(new SpeakerTtsPlayStartRequest.TtsContent()
                        .setName(playDTO.getName())
                        .setText(playDTO.getText())
                        .setMd5(playDTO.getMd5()));
        
        log.info("Playing TTS on speaker - Device: {}, PSDK Index: {}, Text: {}", 
                deviceSn, playDTO.getPsdkIndex(), playDTO.getText());
        
        return servicesPublish.publish(deviceSn, 
                PsdkMethodEnum.SPEAKER_TTS_PLAY_START.getMethod(), 
                request);
    }

    @Override
    public TopicServicesResponse<ServicesReplyData> replay(String deviceSn, Integer psdkIndex) {
        SpeakerReplayRequest request = new SpeakerReplayRequest()
                .setPsdkIndex(psdkIndex);
        
        log.info("Replaying on speaker - Device: {}, PSDK Index: {}", deviceSn, psdkIndex);
        
        return servicesPublish.publish(deviceSn, 
                PsdkMethodEnum.SPEAKER_REPLAY.getMethod(), 
                request);
    }

    @Override
    public TopicServicesResponse<ServicesReplyData> stopPlay(String deviceSn, Integer psdkIndex) {
        SpeakerPlayStopRequest request = new SpeakerPlayStopRequest()
                .setPsdkIndex(psdkIndex);
        
        log.info("Stopping play on speaker - Device: {}, PSDK Index: {}", deviceSn, psdkIndex);
        
        return servicesPublish.publish(deviceSn, 
                PsdkMethodEnum.SPEAKER_PLAY_STOP.getMethod(), 
                request);
    }

    @Override
    public TopicServicesResponse<ServicesReplyData> setPlayMode(String deviceSn, Integer psdkIndex, Integer playMode) {
        SpeakerPlayModeSetRequest request = new SpeakerPlayModeSetRequest()
                .setPsdkIndex(psdkIndex)
                .setPlayMode(playMode);
        
        log.info("Setting speaker play mode - Device: {}, PSDK Index: {}, Mode: {}", 
                deviceSn, psdkIndex, playMode);
        
        return servicesPublish.publish(deviceSn, 
                PsdkMethodEnum.SPEAKER_PLAY_MODE_SET.getMethod(), 
                request);
    }

    @Override
    public TopicServicesResponse<ServicesReplyData> setVolume(String deviceSn, Integer psdkIndex, Integer volume) {
        SpeakerPlayVolumeSetRequest request = new SpeakerPlayVolumeSetRequest()
                .setPsdkIndex(psdkIndex)
                .setPlayVolume(volume);
        
        log.info("Setting speaker volume - Device: {}, PSDK Index: {}, Volume: {}", 
                deviceSn, psdkIndex, volume);
        
        return servicesPublish.publish(deviceSn, 
                PsdkMethodEnum.SPEAKER_PLAY_VOLUME_SET.getMethod(), 
                request);
    }

    // ==================== Helper Methods ====================

    private String getWorkspaceId(String deviceSn) {
        Optional<DeviceDTO> deviceOnline = deviceRedisService.getDeviceOnline(deviceSn);
        return deviceOnline.map(DeviceDTO::getWorkspaceId).orElse(null);
    }
}
