package com.ruoyi.project.business.service.impl;

import static com.ruoyi.common.constant.CacheConstants.AGENT_KEY;
import static com.ruoyi.common.enums.SerialNumberPrefix.AGT;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.google.common.collect.Lists;
import com.ruoyi.common.enums.ValueType;
import com.ruoyi.project.business.enums.JEPFuncEnum;
import com.ruoyi.project.business.enums.JEPLogicEnum;
import com.ruoyi.project.business.service.*;
import org.springframework.beans.BeanUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.enums.FileBuzType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.redis.RedisCache;
import com.ruoyi.project.business.domain.*;
import com.ruoyi.project.business.mapper.TbAgentMapper;
import com.ruoyi.project.business.mapper.TbAreaMapper;
import com.ruoyi.project.common.service.ICommonService;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.service.ISysUserService;

import java.util.*;
import java.util.concurrent.CompletableFuture;

import io.netty.util.internal.ObjectUtil;
import lombok.RequiredArgsConstructor;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

import static com.ruoyi.common.constant.CacheConstants.AGENT_KEY;
import static com.ruoyi.common.enums.SerialNumberPrefix.AGT;

/**
 * 【请填写功能名称】Service业务层处理
 *
 * @author ruoyi
 * @date 2024-04-16
 */
@Service
public class TbAgentServiceImpl extends ServiceImpl<TbAgentMapper, TbAgent> implements ITbAgentService {

    @Resource
    private TbAgentMapper tbAgentMapper;

    @Resource
    private ICommonService commonService;

    @Resource
    private TbAreaMapper tbAreaMapper;

    @Resource
    private ISysUserService sysUserService;

    @Resource
    private RedisCache redisCache;

    @Resource
    private ITcAccountService tcAccountService;

    @Resource
    private ITcProjectService tcProjectService;

    @Resource
    private ITcLeadService tcLeadService;

    @Resource
    private ITbFileService tbFileService;

    @Resource
    private ITbCountryService tbCountryService;

    @Resource
    private ITbAgentHistoryService tbAgentHistoryService;

    @Resource
    private ITpParaLibraryService tpParaLibraryService;


    /**
     * 查询【请填写功能名称】列表
     *
     * @param tbAgent 【请填写功能名称】
     * @return 【请填写功能名称】
     */
    @Override
    public List<TbAgent> selectTbAgentList(TbAgent tbAgent) {
        tbAgent.setPermissionChar(SecurityUtils.getPermissionCharIns());
        return tbAgentMapper.selectTbAgentList(tbAgent);
    }

    /**
     * 新增【请填写功能名称】
     *
     * @param tbAgent 【请填写功能名称】
     * @return 结果
     */
    @Override
    @CacheEvict(value = AGENT_KEY, allEntries = true)
    public boolean insertTbAgent(TbAgent tbAgent) {
        String agentNo = redisCache.generateSerialNumber(AGT.getPrefix());
        tbAgent.setAgentNo(agentNo);

        repeatCheck(tbAgent);

        // tbAgent.setCreateTime(DateUtils.getNowDate());
        // tbAgent.setCreateBy(SecurityUtils.getUserId().toString());
        // 获取id
        if (tbAgent.getParentAgentId() == null) {
            tbAgent.setParentAgentId(0L);
        }
        // 非一级代理商时，也保存上级销售。如二级代理商的上级销售为一级代理商的上级销售   ： 20240513 from Tang by fangk
        if (tbAgent.getAgentLevel() != null && !tbAgent.getAgentType().equals("1")) {
            // TODO 注意这里只考虑两级代理商，多级代理商另需递归处理
            TbAgent parentAgent = getById(tbAgent.getParentAgentId());
            if (parentAgent != null) {
                tbAgent.setParentSalerId(parentAgent.getParentSalerId());
            }
        }
        // id
        tbAgent.setAgentId(commonService.getCommonID("seq_area_agent"));
        // 数据权限
        tbAgent.setPermissionChar(handlePermissionChar(tbAgent));
        TbAgentHistory tbAgentHistory = new TbAgentHistory();
        BeanUtils.copyProperties(tbAgent,tbAgentHistory);
        tbAgentHistory.setCreateTime(new Date());
        // return tbAgentMapper.insertTbAgent(tbAgent);
        getFormula(Lists.newArrayList(tbAgent));
        boolean r1 = save(tbAgent);
        // 保存附件
        boolean r2 = tbFileService.saveOrUpdateFile(tbAgent.getAnnex(), tbAgent.getAgentId(),
            FileBuzType.AGENT.getType());
        //保存到代理商履历表
        boolean r3 = tbAgentHistoryService.save(tbAgentHistory);

        return r1 && r2 && r3;

    }

    private void repeatCheck(TbAgent tbAgent) {
        // 重复检查
        if (tbAgent.getAgentId() == null && StringUtils.isNotEmpty(tbAgent.getAgentNo())) {
            Integer exist = tbAgentMapper.existAgent(new TbAgent().setAgentNo(tbAgent.getAgentNo()));
            if (exist != null) {
                // 发番，不会发生
                throw new RuntimeException("代理商编号已存在");
            }
        }
        if (StringUtils.isNotEmpty(tbAgent.getAgentName())) {
            //Integer existName = tbAgentMapper.existAgent(new TbAgent().setAgentName(tbAgent.getAgentName()));
            Integer existName = tbAgentMapper.existAgent(tbAgent);
            if (existName != null) {
                throw new RuntimeException(MessageUtils.message("agent.name.repeat"));
            }
        }
    }


    /**
     * 拼接数据权限字符: 所属区域的数据权限字符+代理商的数据权限字符
     *
     * @param tbAgent 代理商
     */
    private String handlePermissionChar(TbAgent tbAgent) {
        TbArea tbArea = tbAreaMapper.selectTbAreaByAreaId(tbAgent.getAreaId());

        String permissionChar = "," + tbAgent.getAgentId();
        if (tbAgent.getParentAgentId() == 0L) {
            permissionChar += tbArea.getPermissionChar();
        } else {
            TbAgent parentAgent = getById(tbAgent.getParentAgentId());
            permissionChar += parentAgent.getPermissionChar();
        }
        return permissionChar;
    }


    /**
     * 修改【请填写功能名称】
     *
     * @param tbAgent 【请填写功能名称】
     * @return 结果
     */
    @Override
    @CacheEvict(value = AGENT_KEY, allEntries = true)
    public boolean updateTbAgent(TbAgent tbAgent) {
        // tbAgent.setUpdateTime(DateUtils.getNowDate());
        // 获取id
        if (tbAgent.getParentAgentId() == null) {
            tbAgent.setParentAgentId(0L);
        }
        this.repeatCheck(tbAgent);
        tbAgent.setPermissionChar(handlePermissionChar(tbAgent));
        TbAgentHistory tbAgentHistory = new TbAgentHistory();
        //往履历表中添加记录
        BeanUtils.copyProperties(tbAgent,tbAgentHistory);
        tbAgentHistory.setCreateTime(new Date());
        tbAgentHistory.setCreateBy(tbAgent.getUpdateBy());
        getFormula(Lists.newArrayList(tbAgent));
        tbAgentHistoryService.save(tbAgentHistory);
        // return tbAgentMapper.updateTbAgent(tbAgent);
        tbFileService.saveOrUpdateFile(tbAgent.getAnnex(), tbAgent.getAgentId(), FileBuzType.AGENT.getType());
        return updateById(tbAgent);
    }

    public void getFormula(List<TbAgent> list) {
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(list)) {
            return;
        }

        TpParaLibrary library = new TpParaLibrary();
        List<TpParaLibrary> libraryList = tpParaLibraryService.selectTpParaLibraryList(library).stream()
                .sorted(Comparator.comparing(item -> -item.getParaName().length())).collect(Collectors.toList());

        Function<String, String> replaceNames = formula -> {
            if (StringUtils.isBlank(formula)){
                return "";
            }

            // 1. 替换逻辑操作符
            for (JEPLogicEnum item : JEPLogicEnum.values()) {
                formula = formula.replaceAll(StringUtils.initLogicRegpx(item.getLogicKey()), item.getLogicValue());
            }

            // 2. 替换函数操作符
            for (JEPFuncEnum item : JEPFuncEnum.values()) {
                formula = formula.replaceAll(StringUtils.initFuncRegpx(item.getFuncValue()), Matcher.quoteReplacement("$@$" + item.getFuncKey() + "$@$"));
            }

            // 3. 替换变量名
            for (TpParaLibrary item: libraryList){
                formula = formula.replaceAll(StringUtils.initRegpx(item.getParaName()), Matcher.quoteReplacement("$_$" + item.getParaCode() + "$_$"));
            }

            return formula;
        };

        list.forEach(item -> {
            if (ValueType.FORMULA.getCode().equals(item.getDiscountType())) {
                item.setDiscount(null);
                item.setDiscountFormula(replaceNames.apply(item.getDiscountFormulaTxt()));
            } else {
                item.setDiscountFormula("");
                item.setDiscountFormulaTxt("");
            }
        });

    }

    /**
     * 批量删除【请填写功能名称】
     *
     * @param agentIds 需要删除的【请填写功能名称】主键
     * @return 结果
     */
    @Override
    @CacheEvict(value = AGENT_KEY, allEntries = true)
    public boolean deleteTbAgentByAgentIds(Long[] agentIds) {
        preCheckDelete(agentIds);

        // return tbAgentMapper.deleteTbAgentByAgentIds(agentIds);
        return removeByIds(Arrays.asList(agentIds));
    }

    /**
     * 代理商删除前的校验
     *
     * @param agentIds
     */
    private void preCheckDelete(Long[] agentIds) {

        // 检查是否存在下级代理商
        CompletableFuture<Integer> existNextAgentTask = CompletableFuture.supplyAsync(
            () -> tbAgentMapper.existNextAgent(agentIds));
        // 检查是否存在关联的用户
        CompletableFuture<Integer> existUserTask = CompletableFuture.supplyAsync(
            () -> sysUserService.existUserByAgentIds(agentIds));
        // 检查是否存在关联的客户
        CompletableFuture<Integer> existCustomerTask = CompletableFuture.supplyAsync(
            () -> tcAccountService.existCustomerByAgentIds(agentIds));
        // 检查是否存在关联的项目
        CompletableFuture<Integer> existProjectTask = CompletableFuture.supplyAsync(
            () -> tcProjectService.existProjectByAgentIds(agentIds));
        // 检查是否存在关联的线索
        CompletableFuture<Boolean> existLeadTask = CompletableFuture.supplyAsync(() -> tcLeadService.getBaseMapper()
            .exists(Wrappers.lambdaQuery(TcLead.class).in(TcLead::getOwnerAgent, Arrays.asList(agentIds))));

        CompletableFuture.allOf(existNextAgentTask, existCustomerTask, existUserTask, existProjectTask, existLeadTask)
            .join();

        if (existNextAgentTask.join() != null) {
            throw new RuntimeException(MessageUtils.message("agent.delFail.existSubAgent"));
        }
        if (existUserTask.join() != null) {
            throw new RuntimeException(MessageUtils.message("agent.delFail.existUser"));
        }
        if (existCustomerTask.join() != null) {
            throw new RuntimeException(MessageUtils.message("agent.delFail.existCustomer"));
        }
        if (existProjectTask.join() != null) {
            throw new RuntimeException(MessageUtils.message("agent.delFail.existProject"));
        }
        if (existLeadTask.join()) {
            throw new RuntimeException(MessageUtils.message("agent.delFail.existLead"));
        }


    }

    /**
     * 删除【请填写功能名称】信息
     *
     * @param agentId 【请填写功能名称】主键
     * @return 结果
     */
    @Override
    @CacheEvict(value = AGENT_KEY, allEntries = true)
    public int deleteTbAgentByAgentId(Long agentId) {
        preCheckDelete(new Long[]{agentId});
        return tbAgentMapper.deleteTbAgentByAgentId(agentId);
    }

    @Override
    public List<Tree<Long>> selectAgentTreeList(TbAgent agent) {
        agent.setPermissionChar(SecurityUtils.getPermissionCharIns());
        List<TbAgent> agents = tbAgentMapper.selectTbAgentList(agent);

        // 如果不存在总部根节点，手动添加
        boolean existRoot = agents.stream().anyMatch(item -> item.getAgentId() == 0L);
        if (!existRoot) {
            // 添加根节点：手动添加id：0；parent_id：-1作为总部（根节点）
            TbAgent root = new TbAgent();
            root.setAgentId(0L);
            root.setAgentName("总部");
            root.setParentAgentId(-1L);
            agents.add(root);
        }

        //配置 
        TreeNodeConfig config = new TreeNodeConfig();
        // 最大递归深度 不设置表示不限制深度
        config.setDeep(10);

        List<Tree<Long>> list = TreeUtil.build(agents, -1L, config, (node, tree) -> {
            tree.setId(node.getAgentId());
            tree.setName(node.getAgentName());
            tree.setParentId(node.getParentAgentId() == null ? -1L : node.getParentAgentId());

            // 额外的值/或者使用默认的name，在前端自定义label
            tree.put("label", node.getAgentName());
            tree.put("areaId", node.getAreaId());
        });

        return list;
    }

    @Override
    public List<TbAgent> selectAgentByAreaId(Long areaId, Long agentId) {
        // 查询区域下的一级代理商
        TbAgent agent = new TbAgent();
        agent.setAreaId(areaId);
        //agent.setParentAgentId(0L);
        agent.setAgentType("1");
        // 查看所属区域的一级代理商不需要权限
        agent.setPermissionChar("0");
        List<TbAgent> tbAgents = tbAgentMapper.selectTbAgentList(agent);
        // 排除自己
        tbAgents.removeIf(item -> item.getAgentId().equals(agentId));
        return tbAgents;
    }


    @Override
    public List<SysUser> selectSaleByAreaId(Long areaId) {
        // 所属区域的销售经理角色的user
        List<SysUser> users = sysUserService.selectUserByRoleKeyAndAreaId("sales_manager", areaId);
        return users;
    }

    @Override
    @CacheEvict(value = AGENT_KEY, allEntries = true)
    public int changeStatus(TbAgent agent) {
        return tbAgentMapper.updateTbAgent(agent);
    }

    /**
     * 获取客户全部代理商
     */
    @Override
    public List<TbAgent> selectForAccount() {
        return tbAgentMapper.selectForAccount(SecurityUtils.getPermissionCharIns());
    }

    @Override
    public List<TbAgent> selectForProject() {
        return tbAgentMapper.selectForProject(SecurityUtils.getPermissionCharIns());
    }

    @Override
    public List<TbAgent> selectForYear(String yearParam) {
        return tbAgentMapper.selectForYear(yearParam);
    }

    @Override
    @Cacheable(value = AGENT_KEY, key = "#agentId + '_' + #justSubs + '_' + #includeSelf", unless = "#result == null")
    public List<TbAgent> selectChildAreaList(Long agentId, boolean justSubs, boolean includeSelf) {
        TbAgent tbAgent = getById(agentId);
        if (tbAgent == null) {
            throw new RuntimeException(MessageUtils.message("agent.not.exist"));
        }

        List<TbAgent> tbAgents;
        if (justSubs) {
            tbAgents = tbAgentMapper.selectTbAgentList(new TbAgent().setParentAgentId(agentId));
            if (includeSelf) {
                tbAgents.add(tbAgent);
            }
        } else {
            // 反转字符串
            String permission = new StringBuilder(tbAgent.getPermissionChar()).reverse().toString();
            //permission += justSubs ? "_," : "%";
            tbAgents = tbAgentMapper.selectChildAgentList(permission);
            if (!includeSelf) {
                tbAgents.removeIf(area -> area.getAgentId().equals(agentId));
            }
        }

        return tbAgents;
    }

    @Override
    public List<TbAgent> selectAgentListByOwner(Long ownerId) {

        List<TbAgent> tbAgents = SpringUtils.getAopProxy(this).selectTbAgentList(new TbAgent());

        if (SecurityUtils.getDeptId() == 0L) {
            // 总部
            TbAgent headquarters = new TbAgent();
            headquarters.setAgentId(0L);
            headquarters.setAgentName(MessageUtils.message("agent.headquarters"));
            // 如果数据量比较大可以转链表使用头插法
            tbAgents.add(0, headquarters);
        }

        return tbAgents;
    }

    @Override
    public TbAgent getInfo(Long agentId) {
        TbAgent agent = getById(agentId);
        // 附件
        List<TbFile> annex = tbFileService.list(Wrappers.<TbFile>lambdaQuery().eq(TbFile::getBusinessId, agentId)
            .eq(TbFile::getBusinessType, FileBuzType.AGENT.getType()));
        if (Objects.nonNull(agent)) {
            agent.setAnnex(annex.stream().map(TbFile::getFilePath).collect(Collectors.joining(",")));
        } else {
            throw new ServiceException(MessageUtils.message("common.dataDeleted"));
        }

        // 可用国家列表
        if(!CollectionUtils.isEmpty(agent.getCountryIds())){
            List<TbCountry> tbCountries = tbCountryService.listByIds(agent.getCountryIds());
            agent.setCountryList(tbCountries);
        }
        return agent;
    }
}
