package com.ruoyi.cc.controller;

import java.io.File;
import java.util.*;

import com.alibaba.fastjson.JSONObject;
import com.ruoyi.aicall.tts.aliyun.AliyunTTSWebApi;
import com.ruoyi.aicall.tts.doubao.DoubaoTTSWebApi;
import com.ruoyi.cc.service.ICcParamsService;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ExceptionUtil;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.UuidGenerator;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.cc.utils.RecordingPathUtils;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.cc.domain.CcIvr;
import com.ruoyi.cc.service.ICcIvrService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import org.apache.shiro.authz.annotation.Logical;
import org.springframework.web.multipart.MultipartFile;

import java.nio.file.Path;

/**
 * IVR配置Controller
 * 
 * @author ruoyi
 * @date 2025-12-19
 */
@Controller
@RequestMapping("/cc/ivr")
public class CcIvrController extends BaseController
{
    private String prefix = "cc/ivr";

    @Autowired
    private ICcIvrService ccIvrService;
    @Autowired
    private ICcParamsService ccParamsService;

    @RequiresPermissions("cc:ivr:view")
    @GetMapping()
    public String ivr()
    {
        return prefix + "/ivr";
    }

    /**
     * 查询IVR配置列表
     */
    @RequiresPermissions("cc:ivr:list")
    @PostMapping("/list")
    @ResponseBody
    public List<CcIvr> list(CcIvr ccIvr)
    {
        List<CcIvr> list = ccIvrService.selectCcIvrList(ccIvr);
        return list;
    }

    /**
     * 新增IVR配置
     */
    @RequiresPermissions("cc:ivr:add")
    @GetMapping("/add/{parentId}")
    public String add(@PathVariable("parentId") String parentId, ModelMap mmap)
    {
        CcIvr ccIvr = new CcIvr();
        ccIvr.setParentNodeId(parentId);
        ccIvr.setId(UuidGenerator.GetOneUuid());
        if ("0".equals(parentId)) {
            ccIvr.setRootId(ccIvr.getId());
        } else {
            ccIvr.setRootId(ccIvrService.selectCcIvrById(parentId).getRootId());
        }
        mmap.put("ccIvr", ccIvr);
        return prefix + "/add";
    }

    /**
     * 新增保存IVR配置
     */
    @RequiresPermissions("cc:ivr:add")
    @Log(title = "IVR配置", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @ResponseBody
    public AjaxResult addSave(CcIvr ccIvr)
    {
        if ("acd".equals(ccIvr.getAction())) {
            ccIvr.setAiTransferData(ccIvr.getAiTransferGroupId());
        } else if ("extension".equals(ccIvr.getAction())) {
            ccIvr.setAiTransferData(ccIvr.getAiTransferExtNumber());
        } else if ("gateway".equals(ccIvr.getAction())) {
            JSONObject aiTransferData = new JSONObject();
            aiTransferData.put("gatewayId", ccIvr.getAiTransferGatewayId());
            aiTransferData.put("destNumber", ccIvr.getAiTransferGatewayDestNumber());
            ccIvr.setAiTransferData(JSONObject.toJSONString(aiTransferData));
        } else if ("ai".equals(ccIvr.getAction())) {
            ccIvr.setAiTransferData(ccIvr.getAiInboundId());
        }
        if ("0".equals(ccIvr.getParentNodeId()) || StringUtils.isBlank(ccIvr.getDigit())) {
            ccIvr.setDigit("-1");
        }
        if (StringUtils.isBlank(ccIvr.getTtsProvider())) {
            ccIvr.setTtsProvider("");
        }
        if (StringUtils.isBlank(ccIvr.getVoiceCode())) {
            ccIvr.setVoiceCode("");
        }
        if (StringUtils.isBlank(ccIvr.getTtsLanguageCode())) {
            ccIvr.setTtsLanguageCode("zh-CN");
        }
        if (StringUtils.isBlank(ccIvr.getTtsModels())) {
            ccIvr.setTtsModels("");
        }
        return toAjax(ccIvrService.insertCcIvr(ccIvr));
    }

    /**
     * 修改IVR配置
     */
    @RequiresPermissions("cc:ivr:edit")
    @GetMapping("/edit/{id}")
    public String edit(@PathVariable("id") String id, ModelMap mmap)
    {
        CcIvr ccIvr = ccIvrService.selectCcIvrById(id);

        if ("acd".equals(ccIvr.getAction())) {
            ccIvr.setAiTransferGroupId(ccIvr.getAiTransferData());
        } else if ("extension".equals(ccIvr.getAction())) {
            ccIvr.setAiTransferExtNumber(ccIvr.getAiTransferData());
        } else if ("gateway".equals(ccIvr.getAction())) {
            if (StringUtils.isNotEmpty(ccIvr.getAiTransferData())) {
                JSONObject aiTransferData = JSONObject.parseObject(ccIvr.getAiTransferData());
                ccIvr.setAiTransferGatewayId(aiTransferData.getString("gatewayId"));
                ccIvr.setAiTransferGatewayDestNumber(aiTransferData.getString("destNumber"));
            }
        } else if ("ai".equals(ccIvr.getAction())) {
            ccIvr.setAiInboundId(ccIvr.getAiTransferData());
        }
        String recordingPath = ccParamsService.getParamValueByCode("recording_path", "/home/Records/");
        if (StringUtils.isNotEmpty(ccIvr.getTtsTextWav()) && ccIvr.getTtsTextWav().endsWith(".wav")) {
            ccIvr.setTtsTextfileUrl("recordings/files?filename=" + ccIvr.getTtsTextWav().replace(recordingPath, ""));
        }
        if (StringUtils.isNotEmpty(ccIvr.getPressKeyInvalidTipsWav()) && ccIvr.getPressKeyInvalidTipsWav().endsWith(".wav")) {
            ccIvr.setInvalidTipsfileUrl("recordings/files?filename=" + ccIvr.getPressKeyInvalidTipsWav().replace(recordingPath, ""));
        }
        if (StringUtils.isNotEmpty(ccIvr.getHangupTipsWav()) && ccIvr.getHangupTipsWav().endsWith(".wav")) {
            ccIvr.setHangupTipsfileUrl("recordings/files?filename=" + ccIvr.getHangupTipsWav().replace(recordingPath, ""));
        }
        mmap.put("ccIvr", ccIvr);
        return prefix + "/edit";
    }

    /**
     * 修改保存IVR配置
     */
    @RequiresPermissions("cc:ivr:edit")
    @Log(title = "IVR配置", businessType = BusinessType.UPDATE)
    @PostMapping("/edit")
    @ResponseBody
    public AjaxResult editSave(CcIvr ccIvr)
    {

        if ("acd".equals(ccIvr.getAction())) {
            ccIvr.setAiTransferData(ccIvr.getAiTransferGroupId());
        } else if ("extension".equals(ccIvr.getAction())) {
            ccIvr.setAiTransferData(ccIvr.getAiTransferExtNumber());
        } else if ("gateway".equals(ccIvr.getAction())) {
            JSONObject aiTransferData = new JSONObject();
            aiTransferData.put("gatewayId", ccIvr.getAiTransferGatewayId());
            aiTransferData.put("destNumber", ccIvr.getAiTransferGatewayDestNumber());
            ccIvr.setAiTransferData(JSONObject.toJSONString(aiTransferData));
        } else if ("ai".equals(ccIvr.getAction())) {
            ccIvr.setAiTransferData(ccIvr.getAiInboundId());
        }
        if ("0".equals(ccIvr.getParentNodeId())) {
            ccIvr.setDigit("-1");
        }
        if (StringUtils.isBlank(ccIvr.getTtsProvider())) {
            ccIvr.setTtsProvider("");
        }
        if (StringUtils.isBlank(ccIvr.getVoiceCode())) {
            ccIvr.setVoiceCode("");
        }
        if (StringUtils.isBlank(ccIvr.getTtsLanguageCode())) {
            ccIvr.setTtsLanguageCode("zh-CN");
        }
        if (StringUtils.isBlank(ccIvr.getTtsModels())) {
            ccIvr.setTtsModels("");
        }
        return toAjax(ccIvrService.updateCcIvr(ccIvr));
    }


    /**
     * 删除
     */
    @RequiresPermissions("cc:ivr:remove")
    @Log(title = "IVR配置", businessType = BusinessType.DELETE)
    @GetMapping("/remove/{id}")
    @ResponseBody
    public AjaxResult remove(@PathVariable("id") String id)
    {
        List<CcIvr> list = ccIvrService.selectCcIvrList(new CcIvr().setParentNodeId(id));
        if (list.size() > 0) {
            return AjaxResult.error("请先删除下层节点");
        }
        return toAjax(ccIvrService.deleteCcIvrById(id));
    }

    /**
     * 上传 IVR 语音（目录限制在 recording_path/{rootId}/ 下）
     */
    @RequiresPermissions(value = {"cc:ivr:add", "cc:ivr:edit", "aicall:account:add", "aicall:account:edit"}, logical = Logical.OR)
    @PostMapping("/uploadVoice")
    @ResponseBody
    public AjaxResult uploadVoice(@RequestParam("file") MultipartFile file,
                                  @RequestParam("rootId") String rootId) {
        try {
            if (file.isEmpty()) {
                return AjaxResult.error("文件不能为空");
            }

            String suffix = FilenameUtils.getExtension(file.getOriginalFilename()).toLowerCase();
            if (!"wav".equals(suffix)) {
                return AjaxResult.error("仅支持WAV格式文件");
            }

            long maxSize = 50 * 1024 * 1024;
            if (file.getSize() > maxSize) {
                return AjaxResult.error("文件大小不能超过50MB");
            }

            String recordingPath = ccParamsService.getParamValueByCode("recording_path", "/home/Records/");
            String fileName = DateUtils.format(new Date(), "yyyyMMddHHmmssSSS") + RandomStringUtils.random(3, false, true) + ".wav";
            Path destFilePath = RecordingPathUtils.resolveRootFile(recordingPath, rootId, fileName);
            if (destFilePath == null) {
                return AjaxResult.error("rootId参数不合法");
            }

            File destFile = destFilePath.toFile();
            File destPath = destFile.getParentFile();
            if (destPath != null) {
                destPath.mkdirs();
            }
            file.transferTo(destFile);

            Map<String, String> result = new HashMap<>();
            result.put("fileUrl", "recordings/files?filename=" + rootId + "/" + fileName);
            result.put("filePath", destFile.getAbsolutePath());
            result.put("originalName", file.getOriginalFilename());
            result.put("fileSize", String.valueOf(file.getSize()));

            return AjaxResult.success(result);

        } catch (Exception e) {
            logger.error("文件上传失败", e);
            return AjaxResult.error("文件上传失败：" + e.getMessage());
        }
    }

    /**
     * 校验同一层级下digit是否重复
     * @param digit 按键值
     * @param parentNodeId 父节点ID
     * @param id 当前记录ID（编辑时用于排除自身）
     * @return
     */
    @PostMapping("/checkDigit")
    @ResponseBody
    public AjaxResult checkDigit(@RequestParam String digit,
                                 @RequestParam String parentNodeId,
                                 @RequestParam(required = false) Long id) {
        // 根节点不校验
        if ("0".equals(parentNodeId)) {
            return AjaxResult.success();
        }

        boolean exists = ccIvrService.checkDigitExists(digit, parentNodeId, id);
        return exists ? AjaxResult.error("该按键值已存在") : AjaxResult.success();
    }


    /**
     * IVR 根节点列表（外呼任务/呼入 AI 等页面也会调用，仅需登录，不加 ivr 菜单权限以免打断现有流程）
     */
    @GetMapping("/all")
    @ResponseBody
    public AjaxResult all()
    {
        List<CcIvr> list = ccIvrService.selectCcIvrList(new CcIvr().setParentNodeId("0"));
        return AjaxResult.success(list);
    }


    @RequiresPermissions("cc:ivr:edit")
    @GetMapping("/reload")
    @ResponseBody
    public AjaxResult reload()
    {
        try {

            JSONObject reloadRsp = ccIvrService.reloadIvr();;
            if (null != reloadRsp) {
                if (reloadRsp.getBoolean("success")) {
                    return AjaxResult.success(MessageUtils.message("ivr.reload.success"));
                } else {
                    return AjaxResult.error(MessageUtils.message("ivr.reload.fail"));
                }
            }
        } catch (Exception e) {
            logger.error("IVR configuration reloaded failed." + ExceptionUtil.getExceptionMessage(e));
        }
        return AjaxResult.error(MessageUtils.message("ivr.reload.fail"));
    }


    /**
     * TTS 合成并写入 recording_path/{rootId}/（仅 wav，目录做 containment）
     */
    @RequiresPermissions(value = {"cc:ivr:add", "cc:ivr:edit"}, logical = Logical.OR)
    @GetMapping("/tts")
    @ResponseBody
    public AjaxResult tts(@RequestParam("rootId") String rootId,
                          @RequestParam(value = "voiceSource", required = false) String voiceSource,
                          @RequestParam(value = "voiceCode", required = false) String voiceCode,
                          @RequestParam(value = "ttsText", required = false) String ttsText)
    {
        if (StringUtils.isBlank(ttsText)) {
            return AjaxResult.error("请输入要合成的内容！");
        }
        CcIvr ccIvr = ccIvrService.selectCcIvrByRootId(rootId);
        if (null != ccIvr) {
            if (StringUtils.isBlank(voiceSource)) {
                voiceSource = ccIvr.getTtsProvider();
            }
            if (StringUtils.isBlank(voiceCode)) {
                voiceCode = ccIvr.getVoiceCode();
            }
        }
        if (null == ccIvr
                && StringUtils.isBlank(voiceSource)
                && StringUtils.isBlank(voiceCode)) {
            return AjaxResult.error("请选择音色！");
        }
        String recordingPath = ccParamsService.getParamValueByCode("recording_path", "/home/Records/");
        String fileName = DateUtils.format(new Date(), "yyyyMMddHHmmssSSS") + RandomStringUtils.random(3, false, true) + ".wav";
        Path ttsFilePath = RecordingPathUtils.resolveRootFile(recordingPath, rootId, fileName);
        if (ttsFilePath == null) {
            return AjaxResult.error("rootId参数不合法");
        }
        File fileDir = ttsFilePath.getParent().toFile();
        if (!fileDir.exists()) {
            fileDir.mkdirs();
        }
        String ttsPath = ttsFilePath.toAbsolutePath().toString();

        if ("aliyun_tts".equals(voiceSource)) {
            String aliyunTtsAccountJson = ccParamsService.getParamValueByCode("aliyun-tts-account-json", "{}");
            String appKey = JSONObject.parseObject(aliyunTtsAccountJson).getString("app_key");
            if (StringUtils.isBlank(appKey) || appKey.contains("******")) {
                return AjaxResult.error("请先配置阿里云TTS配置！");
            }
            if (AliyunTTSWebApi.shortTextTTSWebAPI(voiceCode, ttsText, ttsPath, aliyunTtsAccountJson)) {
                Map<String, String> result = new HashMap<>();
                result.put("fileUrl", "recordings/files?filename=" + rootId + "/" + fileName);
                result.put("filePath", ttsPath);
                result.put("originalName", fileName);
                return AjaxResult.success(result);
            } else {
                return AjaxResult.error("合成失败，请检查tts配置！");
            }
        } else if ("doubao_vcl_tts".equals(voiceSource)) {
            String doubaoTtsAccountJson = ccParamsService.getParamValueByCode("doubao-tts-account-json", "{}");
            String accessToken = JSONObject.parseObject(doubaoTtsAccountJson).getString("access_token");
            if (StringUtils.isBlank(accessToken) || accessToken.contains("******")) {
                return AjaxResult.error("请先配置豆包TTS配置！");
            }
            if (DoubaoTTSWebApi.shortTextTTSWebAPI(voiceCode, ttsText, ttsPath, doubaoTtsAccountJson)) {
                Map<String, String> result = new HashMap<>();
                result.put("fileUrl", "recordings/files?filename=" + rootId + "/" + fileName);
                result.put("filePath", ttsPath);
                result.put("originalName", fileName);
                return AjaxResult.success(result);
            } else {
                return AjaxResult.error("合成失败，请检查tts配置！");
            }
        } else {
            return AjaxResult.error("暂不支持该tts厂商的IVR语音在线合成！");
        }
    }

}
