package com.multictrl.modules.business.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.multictrl.common.config.MinioConfig;
import com.multictrl.common.constant.BusinessConstant;
import com.multictrl.common.exception.ErrorCode;
import com.multictrl.common.exception.RenException;
import com.multictrl.common.page.PageData;
import com.multictrl.common.service.impl.CrudServiceImpl;
import com.multictrl.common.utils.CacheUtils;
import com.multictrl.common.utils.ConvertUtils;
import com.multictrl.common.utils.FfmpegUtils;
import com.multictrl.common.utils.Utils;
import com.multictrl.modules.business.dao.SpeakerDao;
import com.multictrl.modules.business.dto.SpeakerDTO;
import com.multictrl.modules.business.dto.speaker.SpeakerSet;
import com.multictrl.modules.business.dto.speaker.TtsText;
import com.multictrl.modules.business.entity.SpeakerEntity;
import com.multictrl.modules.business.service.DJIBaseService;
import com.multictrl.modules.business.service.SpeakerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Map;

/**
 * 喊话器控制
 *
 * @author Sdy
 * @since 1.0.0 2026/5/6
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SpeakerServiceImpl extends CrudServiceImpl<SpeakerDao, SpeakerEntity, SpeakerDTO> implements SpeakerService {
    private final DJIBaseService djiBaseService;
    private final MinioConfig minioConfig;

    @Override
    public QueryWrapper<SpeakerEntity> getWrapper(Map<String, Object> params) {
        String id = (String) params.get("id");
        String type = (String) params.get("type");
        String dockSn = (String) params.get("dockSn");

        QueryWrapper<SpeakerEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StrUtil.isNotBlank(id), "id", id);
        if (StrUtil.isNotBlank(type)) {
            wrapper.eq("type", Integer.parseInt(type));
        }
        wrapper.eq(StrUtil.isNotBlank(dockSn), "dock_sn", dockSn);
        wrapper.orderByDesc("create_date");

        return wrapper;
    }

    @Override
    public void addTemplate(SpeakerDTO speaker) {
        Long count = baseDao.selectCount(new QueryWrapper<SpeakerEntity>().eq("dock_sn", speaker.getDockSn())
                .eq("name", speaker.getName()));
        if (count > 0) {
            throw new RenException(ErrorCode.SPEAKER_NAME_EXIST);
        }
        SpeakerEntity speakerEntity = ConvertUtils.sourceToTarget(speaker, SpeakerEntity.class);
        Integer type = speaker.getType();
        if (type == 1) {
            speakerEntity.setMd5(Utils.md5Txt(speaker.getTextContent()));
        } else {
            String mediaPath = speaker.getMediaPath();
            String path = minioConfig.getOther().getDataPath() + "/" + mediaPath;
            if (!FileUtil.exist(path)) {
                throw new RenException(ErrorCode.FILE_NOT_EXIST, "音频");
            }
            //调用ffmpeg将mp3或wav 转成pcm
            String pcmPath = path.split("\\.")[0] + ".pcm";
            String command = "ffmpeg -i " + path
                    + " -ss 00 -t 179 -f s16le -ar 16000 -ac 1  -acodec pcm_s16le " + pcmPath;
            FfmpegUtils.runCommand(command);
            //轮询文件是否生成，因为ffmpeg和当前java进程不同步
            int retry = 20;
            while (!FileUtil.exist(pcmPath) && retry-- > 0) {
                Utils.sleep(1);
                log.info("ffmpeg mp3 or wav 2 pcm, await {} s", 20 - retry);
            }
            if (!FileUtil.exist(pcmPath)) {
                throw new RenException(ErrorCode.FILE_NOT_EXIST, "pcm音频");
            }
            speakerEntity.setMd5(Utils.md5File(pcmPath));
            speakerEntity.setPcmPath(pcmPath.replaceAll(minioConfig.getOther().getDataPath() + "/", ""));
        }
        baseDao.insert(speakerEntity);
    }

    @Override
    public void deleteTemplate(Long id) {
        SpeakerEntity speakerEntity = selectById(id);
        if (speakerEntity == null) {
            return;
        }
        Integer type = speakerEntity.getType();
        if (type == 2) {
            String mediaPath = speakerEntity.getMediaPath();
            String pcmPath = speakerEntity.getPcmPath();
            FileUtil.del(minioConfig.getOther().getDataPath() + "/" + mediaPath);
            FileUtil.del(minioConfig.getOther().getDataPath() + "/" + pcmPath);
        }
        deleteById(id);
    }

    @Override
    public String drcSetVolume(String dockSn, Integer volume) {
        if (volume == null || volume < 0 || volume > 100) {
            throw new RenException(ErrorCode.PARAMS_ERROR);
        }
        JSONObject data = getDataIncludePsdkIndex(dockSn);
        data.set("play_volume", volume);
        return djiBaseService.executeDrcAndReturnResult(dockSn, "drc_speaker_play_volume_set", data);
    }

    @Override
    public String drcSetMode(String dockSn, Integer mode) {
        if (mode == null || (mode != 0 && mode != 1)) {
            throw new RenException(ErrorCode.PARAMS_ERROR);
        }
        JSONObject data = getDataIncludePsdkIndex(dockSn);
        data.set("play_mode", mode);
        return djiBaseService.executeDrcAndReturnResult(dockSn, "drc_speaker_play_mode_set", data);
    }

    @Override
    public String drcSetTts(String dockSn, SpeakerSet ttsSpeaker) {
        JSONObject data = getDataIncludePsdkIndex(dockSn);
        data.set("volume", ttsSpeaker.getVolume());
        data.set("type", ttsSpeaker.getType());
        data.set("language", ttsSpeaker.getLanguage());
        data.set("speed", ttsSpeaker.getSpeed());
        return djiBaseService.executeDrcAndReturnResult(dockSn, "drc_speaker_tts_set", data);
    }

    @Override
    public String drcStopSpeaker(String dockSn) {
        JSONObject data = getDataIncludePsdkIndex(dockSn);
        return djiBaseService.executeDrcAndReturnResult(dockSn, "drc_speaker_play_stop", data);
    }

    @Override
    public String drcReplaySpeaker(String dockSn) {
        JSONObject data = getDataIncludePsdkIndex(dockSn);
        return djiBaseService.executeDrcAndReturnResult(dockSn, "drc_speaker_replay", data);
    }

    @Override
    public String drcStartSpeakerTts(String dockSn, TtsText ttsText) {
        JSONObject data = getDataIncludePsdkIndex(dockSn);
        JSONObject tts = new JSONObject();
        tts.set("text", ttsText.getText());
        tts.set("name", ttsText.getName());
        tts.set("md5", Utils.md5Txt(ttsText.getText()));
        data.set("tts", tts);
        return djiBaseService.executeDrcAndReturnResult(dockSn, "drc_speaker_tts_play_start", data);
    }

    @Override
    public String drcStartSpeakerTemplate(String dockSn, Long id) {
        SpeakerEntity speakerEntity = selectById(id);
        if (speakerEntity == null || speakerEntity.getType() != 1) {
            throw new RenException(ErrorCode.PARAMS_ERROR);
        }
        TtsText ttsText = new TtsText();
        ttsText.setName(speakerEntity.getName());
        ttsText.setText(speakerEntity.getTextContent());
        return drcStartSpeakerTts(dockSn, ttsText);
    }

    @Override
    public SpeakerDao getDao() {
        return baseDao;
    }

    //获取包含psdk_index的data
    private JSONObject getDataIncludePsdkIndex(String dockSn) {
        JSONObject data = new JSONObject();
        Object speakerIndex = CacheUtils.get(BusinessConstant.UAV_SPEAKER_INDEX + dockSn);
        if (speakerIndex != null) {
            data.set("psdk_index", speakerIndex);
        } else {
            throw new RenException(ErrorCode.UAV_SPEAKER_INDEX_NOT_EXIST);
        }
        return data;
    }
}
