package com.ruoyi.aicall.controller;

import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSONObject;
import com.ruoyi.aicall.domain.CcCallTask;
import com.ruoyi.aicall.model.CallPhoneExportVo;
import com.ruoyi.aicall.service.ICcCallTaskService;
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 org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.aicall.domain.CcCallPhone;
import com.ruoyi.aicall.service.ICcCallPhoneService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.CommonUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;

/**
 * 外呼号码Controller
 * 
 * @author ruoyi
 * @date 2025-05-29
 */
@Controller
@RequestMapping("/aicall/callPhone")
public class CcCallPhoneController extends BaseController
{
    private String prefix = "aicall/callPhone";

    @Autowired
    private ICcCallPhoneService ccCallPhoneService;
    @Autowired
    private ICcCallTaskService ccCallTaskService;

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

    /**
     * 查询外呼号码列表
     * 两阶段查询：先分页查 id（避开大字段），再按 id 回表列表字段；dialogue/biz_json/tts_text 按需加载
     */
    @RequiresPermissions("aicall:callPhone:list")
    @PostMapping("/list")
    @Log(title = "查询通话记录", businessType = BusinessType.OTHER)
    @ResponseBody
    public TableDataInfo list(CcCallPhone ccCallPhone)
    {
        Long t0 = System.currentTimeMillis();
        // 任务名称已通过 batchId 选择；若仍传 batchName，先解析为 batchIds，避免大表 JOIN
        resolveBatchNameToIds(ccCallPhone);

        startPage();
        List<String> ids = ccCallPhoneService.selectCcCallPhoneIds(ccCallPhone);
        logger.info("通话记录查询id分页耗时:{}ms, size={}", (System.currentTimeMillis() - t0), ids == null ? 0 : ids.size());
        TableDataInfo tableDataInfo = getDataTable(ids);
        if (ids == null || ids.isEmpty()) {
            return tableDataInfo;
        }

        Long t1 = System.currentTimeMillis();
        List<CcCallPhone> records = ccCallPhoneService.selectCcCallPhoneLiteByIds(ids);
        fillBatchNames(records);
        for (CcCallPhone data: records) {
            String wavfile = data.getWavfile();
            if (StringUtils.isNotEmpty(wavfile) && wavfile.startsWith("/")) {
                wavfile = wavfile.substring(1);
            }
            data.setWavfile("/recordings/files?filename=" + (wavfile == null ? "" : wavfile));
            data.setTelephone(CommonUtils.maskPhoneNumber(data.getTelephone()));
            data.setCallerNumber(CommonUtils.maskPhoneNumber(data.getCallerNumber()));
            if (StringUtils.isBlank(data.getBatchName())) {
                data.setBatchName("-");
            }
            // 挂机原因处理
            if (StringUtils.isNotEmpty(data.getHangupCause())) {
                if (data.getHangupCause().startsWith("{") && data.getHangupCause().endsWith("}")) {
                    try {
                        JSONObject hangupCause = JSONObject.parseObject(data.getHangupCause());
                        String hangupCauseCode = hangupCause.getString("code");
                        String hangupCauseDetail = hangupCause.getString("details");
                        String hangupCauseCodeI18n = MessageUtils.message("_hangup_cause_code_" + hangupCauseCode);
                        if (StringUtils.isNotEmpty(hangupCauseCodeI18n)) {
                            hangupCauseCode = hangupCauseCodeI18n;
                        }
                        if (StringUtils.isNotEmpty(hangupCauseDetail)) {
                            data.setHangupCause(hangupCauseCode + ":" + hangupCauseDetail);
                        } else {
                            data.setHangupCause(hangupCauseCode);
                        }
                    } catch (Exception e) {
                        logger.error(ExceptionUtil.getExceptionMessage(e));
                    }

                }
            }
        }
        tableDataInfo.setRows(records);
        logger.info("通话记录回表组装耗时:{}ms, 后端累计:{}ms", (System.currentTimeMillis() - t1), (System.currentTimeMillis() - t0));
        return tableDataInfo;
    }

    /**
     * 按需加载通话详情大字段（播放录音时拉取 dialogue 等）
     */
    @RequiresPermissions("aicall:callPhone:list")
    @GetMapping("/detail/{id}")
    @ResponseBody
    public AjaxResult detail(@PathVariable("id") String id)
    {
        CcCallPhone phone = ccCallPhoneService.selectCcCallPhoneById(id);
        if (phone == null) {
            return AjaxResult.error("记录不存在");
        }
        Map<String, Object> data = new HashMap<>();
        data.put("id", phone.getId());
        data.put("uuid", phone.getUuid());
        data.put("dialogue", phone.getDialogue());
        data.put("bizJson", phone.getBizJson());
        data.put("ttsText", phone.getTtsText());
        data.put("wavfile", phone.getWavfile());
        data.put("recordServerUrl", phone.getRecordServerUrl());
        return AjaxResult.success(data);
    }

    private void resolveBatchNameToIds(CcCallPhone ccCallPhone) {
        if (ccCallPhone.getBatchId() != null || StringUtils.isEmpty(ccCallPhone.getBatchName())) {
            return;
        }
        List<CcCallTask> tasks = ccCallTaskService.selectCcCallTaskList(
                new CcCallTask().setBatchName(ccCallPhone.getBatchName()));
        List<Long> batchIds = new ArrayList<>();
        if (tasks != null) {
            for (CcCallTask task : tasks) {
                if (task.getBatchId() != null) {
                    batchIds.add(task.getBatchId());
                }
            }
        }
        Map<String, Object> params = ccCallPhone.getParams();
        if (params == null) {
            params = new HashMap<>();
            ccCallPhone.setParams(params);
        }
        // 无匹配任务时放入空列表，后续 SQL 用不可能命中的条件短路
        if (batchIds.isEmpty()) {
            batchIds.add(-1L);
        }
        params.put("batchIds", batchIds);
        ccCallPhone.setBatchName(null);
    }

    private void fillBatchNames(List<CcCallPhone> records) {
        Set<Long> batchIdSet = new HashSet<>();
        for (CcCallPhone data : records) {
            if (data.getBatchId() != null) {
                batchIdSet.add(data.getBatchId());
            }
        }
        if (batchIdSet.isEmpty()) {
            return;
        }
        Map<Long, String> batchNameMap = new HashMap<>();
        for (Long batchId : batchIdSet) {
            CcCallTask task = ccCallTaskService.selectCcCallTaskByBatchId(batchId);
            batchNameMap.put(batchId, task == null || StringUtils.isBlank(task.getBatchName()) ? "-" : task.getBatchName());
        }
        for (CcCallPhone data : records) {
            data.setBatchName(batchNameMap.getOrDefault(data.getBatchId(), "-"));
        }
    }

    /**
     * 导出外呼号码列表
     */
    @RequiresPermissions("aicall:callPhone:export")
    @Log(title = "外呼号码", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @ResponseBody
    public AjaxResult export(CcCallPhone ccCallPhone)
    {
        List<CcCallPhone> list = ccCallPhoneService.selectCcCallPhoneList(ccCallPhone);
        Date d0 = DateUtils.dateTime( "yyyy-MM-dd", "2025-01-01");
        Map<Long, String> batchNameMap = new HashMap<>();
        List<CallPhoneExportVo> dataList = new ArrayList<>();
        for (CcCallPhone data: list) {
            data.setTelephone(CommonUtils.maskPhoneNumber(data.getTelephone()));
            data.setCallerNumber(CommonUtils.maskPhoneNumber(data.getCallerNumber()));
            String batchName = batchNameMap.getOrDefault(data.getBatchId(), "");
            if (StringUtils.isBlank(batchName)) {
                CcCallTask ccCallTask = ccCallTaskService.selectCcCallTaskByBatchId(data.getBatchId());
                if (null != ccCallTask) {
                    batchName = ccCallTask.getBatchName();
                } else {
                    batchName = "-";
                }
                batchNameMap.put(data.getBatchId(), batchName);
            }
            data.setBatchName(batchName);
            CallPhoneExportVo vo = new CallPhoneExportVo();
            BeanUtils.copyProperties(data, vo);
            vo.setCallstatusName(MessageUtils.message("callPhone.table.callstatus" + data.getCallstatus()));
            if (data.getCalloutTime() <= d0.getTime()) {
                vo.setCalloutTimeStr("-");
            } else {
                vo.setCalloutTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(data.getCalloutTime())));
            }
            if (data.getAnsweredTime() <= d0.getTime()) {
                vo.setAnsweredTimeStr("-");
            } else {
                vo.setAnsweredTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(data.getAnsweredTime())));
            }
            if (data.getCallEndTime() <= d0.getTime()) {
                vo.setCallEndTimeStr("-");
            } else {
                vo.setCallEndTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(data.getCallEndTime())));
            }
            Long timeLen = data.getTimeLen()/1000;
            vo.setTimeLenSec(timeLen/60 + "分" + timeLen%60 + "秒" );
            dataList.add(vo);
        }
        ExcelUtil<CallPhoneExportVo> util = new ExcelUtil<>(CallPhoneExportVo.class);
        return util.exportExcel(dataList, "外呼结果数据");
    }

    /**
     * 新增外呼号码
     */
    @GetMapping("/add")
    public String add()
    {
        return prefix + "/add";
    }

    /**
     * 新增保存外呼号码
     */
    @RequiresPermissions("aicall:callPhone:add")
    @Log(title = "外呼号码", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @ResponseBody
    public AjaxResult addSave(CcCallPhone ccCallPhone)
    {
        return toAjax(ccCallPhoneService.insertCcCallPhone(ccCallPhone));
    }

    /**
     * 修改外呼号码
     */
    @RequiresPermissions("aicall:callPhone:edit")
    @GetMapping("/edit/{id}")
    public String edit(@PathVariable("id") String id, ModelMap mmap)
    {
        CcCallPhone ccCallPhone = ccCallPhoneService.selectCcCallPhoneById(id);
        mmap.put("ccCallPhone", ccCallPhone);
        return prefix + "/edit";
    }

    /**
     * 修改保存外呼号码
     */
    @RequiresPermissions("aicall:callPhone:edit")
    @Log(title = "外呼号码", businessType = BusinessType.UPDATE)
    @PostMapping("/edit")
    @ResponseBody
    public AjaxResult editSave(CcCallPhone ccCallPhone)
    {
        return toAjax(ccCallPhoneService.updateCcCallPhone(ccCallPhone));
    }

    /**
     * 删除外呼号码
     */
    @RequiresPermissions("aicall:callPhone:remove")
    @Log(title = "外呼号码", businessType = BusinessType.DELETE)
    @PostMapping( "/remove")
    @ResponseBody
    public AjaxResult remove(String ids)
    {
        return toAjax(ccCallPhoneService.deleteCcCallPhoneByIds(ids));
    }
}
