package com.xinelu.manage.service.scriptInfo.impl;

import com.xinelu.common.annotation.DataScope;
import com.xinelu.common.config.SystemBusinessConfig;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.enums.ScriptStatusEnum;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.SecurityUtils;
import com.xinelu.common.utils.file.FileUploadUtils;
import com.xinelu.common.utils.file.MimeTypeUtils;
import com.xinelu.manage.domain.scriptInfo.ScriptInfo;
import com.xinelu.manage.domain.scriptinfoedge.ScriptInfoEdge;
import com.xinelu.manage.dto.script.ScriptInfoDto;
import com.xinelu.manage.mapper.scriptInfo.ScriptInfoMapper;
import com.xinelu.manage.mapper.scriptinfoedge.ScriptInfoEdgeMapper;
import com.xinelu.manage.mapper.scriptinfonode.ScriptInfoNodeMapper;
import com.xinelu.manage.service.scriptInfo.IScriptInfoService;
import com.xinelu.manage.vo.scriptInfo.Edge;
import com.xinelu.manage.vo.scriptInfo.Node;
import com.xinelu.manage.vo.scriptInfo.ScriptVO;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 话术信息Service业务层处理
 *
 * @author xinelu
 * @date 2024-02-26
 */
@Service
public class ScriptInfoServiceImpl implements IScriptInfoService {
    @Resource
    private ScriptInfoMapper scriptInfoMapper;

    @Resource
    private SystemBusinessConfig systemBusinessConfig;

    @Resource
    private ScriptInfoEdgeMapper scriptInfoEdgeMapper;

    @Resource
    private ScriptInfoNodeMapper scriptInfoNodeMapper;


    /**
     * 查询话术信息
     *
     * @param id 话术信息主键
     * @return 话术信息
     */
    @Override
    public ScriptInfo selectScriptInfoById(Long id) {
        return scriptInfoMapper.selectScriptInfoById(id);
    }

    /**
     * 查询话术信息列表
     *
     * @param scriptInfo 话术信息
     * @return 话术信息
     */
    @DataScope(agencyAlias = "d", deptAlias = "si")
    @Override
    public List<ScriptInfo> selectScriptInfoList(ScriptInfoDto scriptInfo) {
        return scriptInfoMapper.selectScriptInfoList(scriptInfo);
    }

    /**
     * 新增话术信息
     *
     * @param scriptInfo 话术信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertScriptInfo(ScriptInfo scriptInfo) {
        // 判断通用话术名称是否存在
        if (scriptInfoMapper.countByScriptInfo(scriptInfo) > 0) {
            throw new ServiceException("通用话术名称已存在");
        }
        // 设置创建人与创建时间
        scriptInfo.setCreateBy(SecurityUtils.getUsername());
        scriptInfo.setCreateTime(LocalDateTime.now());
        scriptInfo.setScriptStatus(ScriptStatusEnum.OFF_SHELF.getInfo());
        return scriptInfoMapper.insertScriptInfo(scriptInfo);
    }

    /**
     * 修改话术信息
     *
     * @param scriptInfo 话术信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateScriptInfo(ScriptInfo scriptInfo) {
        ScriptInfo scriptInfo1 = scriptInfoMapper.selectScriptInfoById(scriptInfo.getId());
        if (Objects.isNull(scriptInfo1)) {
            throw new ServiceException("该话术名称已删除！");
        }
        // 检查除当前记录之外是否存在同名的话术名称
        if (scriptInfoMapper.countByScriptNameExcludingId(scriptInfo.getScriptName(), scriptInfo.getDepartmentId(), scriptInfo.getId(), scriptInfo.getCommonScriptName()) > 0) {
            // 存在同名的通用话术名称，不能进行更新
            throw new ServiceException("通用话术名称已存在，请使用其他名称。");
        }
        // 不存在同名的话术名称或者名称未改变，设置修改人和修改时间
        scriptInfo.setUpdateBy(SecurityUtils.getUsername());
        scriptInfo.setUpdateTime(LocalDateTime.now());
        // 进行更新操作
        return scriptInfoMapper.updateScriptInfo(scriptInfo);
    }

    /**
     * 批量删除话术信息
     *
     * @param ids 需要删除的话术信息主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteScriptInfoByIds(Long[] ids) {
        scriptInfoEdgeMapper.deleteScriptInfoEdgeByScriptInfoIds(ids);
        scriptInfoNodeMapper.deleteScriptInfoNodeByScriptInfoIds(ids);
        return scriptInfoMapper.deleteScriptInfoByIds(ids);
    }

    /**
     * 删除话术信息信息
     *
     * @param id 话术信息主键
     * @return 结果
     */
    @Override
    public int deleteScriptInfoById(Long id) {
        return scriptInfoMapper.deleteScriptInfoById(id);
    }

    /**
     * 话术图片上传
     */
    @Override
    public AjaxResult uploadScriptInfo(MultipartFile multipartFile) throws Exception {
        // 获取文件路径
        String uploadPathUrl = SystemBusinessConfig.getProfile() + systemBusinessConfig.getScriptFileUrl();
        if (StringUtils.isBlank(uploadPathUrl)) {
            return AjaxResult.success();
        }
        // 上传
        String scriptFilePath = FileUploadUtils.upload(uploadPathUrl, multipartFile, MimeTypeUtils.IMAGE_EXTENSION);
        if (StringUtils.isBlank(scriptFilePath)) {
            throw new ServiceException("图片上传失败，请联系管理员！");
        }
        // 上传成功，返回话术图片url
        AjaxResult ajax = AjaxResult.success("上传成功！");
        ajax.put("imgUrl", scriptFilePath);
        return ajax;
    }

    @Override
    public AjaxResult selectScriptEdgeNode(Long id) {
        return AjaxResult.success(scriptInfoMapper.selectScriptEdgeNode(id));
    }

    /**
     * 新增话术节点
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult insertScriptEdgeNode(ScriptVO scriptVO) {
        ScriptInfo scriptInfo = new ScriptInfo();
        scriptInfo.setId(scriptVO.getScriptInfoId());
        scriptInfo.setFlowScheme(scriptVO.getFlowScheme());
        scriptInfo.setUpdateBy(SecurityUtils.getUsername());
        scriptInfo.setUpdateTime(LocalDateTime.now());
        int updateScriptInfo = scriptInfoMapper.updateScriptInfo(scriptInfo);
        if (updateScriptInfo <= 0) {
            return AjaxResult.error("新增话术图失败！");
        }
        if (CollectionUtils.isEmpty(scriptVO.getNodes()) || CollectionUtils.isEmpty(scriptVO.getEdges())) {
            return AjaxResult.success();
        }
        List<Node> scriptInfoNodes = scriptVO.getNodes();
        List<ScriptInfoEdge> scriptInfoEdges = new ArrayList<>();
        for (Node node : scriptVO.getNodes()) {
            node.setScriptInfoId(scriptVO.getScriptInfoId());
            node.setScriptNodeName(node.getLabel());
            node.setScriptContent(node.getLabel());
            node.setScriptNodeType(node.getType());
            node.setCreateBy(SecurityUtils.getUsername());
            node.setCreateTime(LocalDateTime.now());
        }
        int i1 = scriptInfoNodeMapper.insertScriptInfoNodeList(scriptInfoNodes);
        if (i1 <= 0) {
            return AjaxResult.error("新增话术图失败！");
        }
        for (Edge edge : scriptVO.getEdges()) {
            ScriptInfoEdge scriptInfoEdge = new ScriptInfoEdge();
            scriptInfoEdge.setKeywords(edge.getKeyword());
            Node node = scriptInfoNodes.stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getCode()) && edge.getSource().equals(item.getCode())).findFirst().orElse(new Node());
            scriptInfoEdge.setStartNodeId(node.getId());
            scriptInfoEdge.setStartNodeName(node.getLabel());
            Node node2 = scriptInfoNodes.stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getCode()) && edge.getTarget().equals(item.getCode())).findFirst().orElse(new Node());
            scriptInfoEdge.setEndNodeId(node2.getId());
            scriptInfoEdge.setEndNodeName(node2.getLabel());
            scriptInfoEdge.setScriptInfoId(scriptVO.getScriptInfoId());
            scriptInfoEdge.setScriptEdgeName(edge.getLabel());
            scriptInfoEdges.add(scriptInfoEdge);
        }
        int i2 = scriptInfoEdgeMapper.insertScriptInfoEdgeList(scriptInfoEdges);
        if (i2 <= 0) {
            return AjaxResult.error("新增话术图失败！");
        }
        return AjaxResult.success();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult updateScriptEdgeNode(ScriptVO scriptVO) {
        List<Long> scriptInfoEdgeIds = scriptInfoMapper.selectScriptInfoEdgeIds(scriptVO.getScriptInfoId());
        List<Long> scriptInfoNodeIds = scriptInfoMapper.selectScriptInfoNodeIds(scriptVO.getScriptInfoId());
        scriptInfoMapper.deleteScriptInfoNode(scriptVO.getScriptInfoId());
        scriptInfoMapper.deleteScriptInfoEdge(scriptVO.getScriptInfoId());
        ScriptInfo scriptInfo = new ScriptInfo();
        scriptInfo.setId(scriptVO.getScriptInfoId());
        scriptInfo.setFlowScheme(scriptVO.getFlowScheme());
        scriptInfo.setUpdateBy(SecurityUtils.getUsername());
        scriptInfo.setUpdateTime(LocalDateTime.now());
        int updateScriptInfo = scriptInfoMapper.updateScriptInfo(scriptInfo);
        if (updateScriptInfo <= 0) {
            return AjaxResult.error("修改话术图失败！");
        }
        List<Node> scriptInfoNodes = scriptVO.getNodes();
        List<ScriptInfoEdge> scriptInfoEdges = new ArrayList<>();
        int i = 0;
        for (Node node : scriptVO.getNodes()) {
            node.setScriptInfoId(scriptVO.getScriptInfoId());
            if (Objects.nonNull(node.getLabel())){
                String[] split = node.getLabel().split("\\n");
                int i1 = node.getLabel().indexOf("\n");
                if (split.length > 0) {
                    node.setScriptNodeName(split[0]);
                }
                if (split.length > 1) {
                    node.setScriptContent(node.getLabel().substring(i1 + 1));
                }
            }
            node.setScriptNodeType(node.getType());
            node.setCreateBy(SecurityUtils.getUsername());
            node.setCreateTime(LocalDateTime.now());
            if (CollectionUtils.isNotEmpty(scriptInfoNodeIds) && (i < scriptInfoNodeIds.size()) && Objects.nonNull(scriptInfoNodeIds.get(i))) {
                node.setId(scriptInfoNodeIds.get(i));
                i++;
            }
        }
        int i1 = scriptInfoNodeMapper.insertScriptInfoNodeList(scriptInfoNodes);
        if (i1 <= 0) {
            return AjaxResult.error("修改话术图失败！");
        }
        if (CollectionUtils.isEmpty(scriptVO.getNodes()) || CollectionUtils.isEmpty(scriptVO.getEdges())) {
            return AjaxResult.success();
        }
        int num = 0;
        for (Edge edge : scriptVO.getEdges()) {
            ScriptInfoEdge scriptInfoEdge = new ScriptInfoEdge();
            scriptInfoEdge.setKeywords(edge.getKeyword());
            Node startNode = scriptInfoNodes.stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getCode()) && edge.getSource().equals(item.getCode())).findFirst().orElse(new Node());
            scriptInfoEdge.setStartNodeId(startNode.getId());
            scriptInfoEdge.setStartNodeName(startNode.getLabel());
            Node endNode = scriptInfoNodes.stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getCode()) && edge.getTarget().equals(item.getCode())).findFirst().orElse(new Node());
            scriptInfoEdge.setEndNodeId(endNode.getId());
            scriptInfoEdge.setEndNodeName(endNode.getLabel());
            scriptInfoEdge.setScriptInfoId(scriptVO.getScriptInfoId());
            scriptInfoEdge.setScriptEdgeName(edge.getLabel());
            scriptInfoEdges.add(scriptInfoEdge);
            if (CollectionUtils.isNotEmpty(scriptInfoEdgeIds) && (num < scriptInfoEdgeIds.size()) && Objects.nonNull(scriptInfoEdgeIds.get(num))) {
                scriptInfoEdge.setId(scriptInfoEdgeIds.get(num));
                num++;
            }
        }
        int i2 = scriptInfoEdgeMapper.insertScriptInfoEdgeList(scriptInfoEdges);
        if (i2 <= 0) {
            return AjaxResult.error("修改话术图失败！");
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult selectScriptVariable(Long id) {
        ScriptInfo scriptInfo = scriptInfoMapper.selectScriptInfoById(id);
        if (Objects.isNull(scriptInfo) || StringUtils.isBlank(scriptInfo.getVariables())) {
            return AjaxResult.success();
        }
        List<String> variables = Arrays.asList(scriptInfo.getVariables().split("\\|"));
        Map<String, String> variablehMap = new HashMap<>();
        for (String variable : variables) {
            variablehMap.put(variable, null);
        }
        return AjaxResult.success(variablehMap);
    }
}
