package com.dayou.service.impl;

import com.dayou.utils.LoginContext;
import com.dayou.vo.AssetsRepertoryVo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import cn.hutool.core.util.ObjectUtil;
import com.dayou.common.BaseEntity;
import com.dayou.dto.*;
import com.dayou.entity.Assets;
import com.dayou.entity.BusinessNumber;
import com.dayou.exception.ErrorCode;
import com.dayou.mapper.AssetsEvaluationTargetMapper;
import com.dayou.mapper.AssetsMapper;
import com.dayou.mapper.AssetsProductionMapper;
import com.dayou.service.IAssetsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dayou.service.IBusinessNumberService;
import com.dayou.service.workflow.IWorkFlowService;
import com.dayou.vo.AssetsBusinessMember;
import com.dayou.vo.AssetsOrderFundInvoiceVO;
import com.dayou.vo.AssetsVO;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.dayou.enums.MainBusinessEnum.ASSET_BUSINESS;
import static com.dayou.enums.ProductionEnum.*;

/**
 * <p>
 * 资产业务订单表 服务实现类
 * </p>
 *
 * @author GouGengquan
 * @since 2024-03-28
 */
@Service
public class AssetsServiceImpl extends ServiceImpl<AssetsMapper, Assets> implements IAssetsService {

    @Autowired
    private IBusinessNumberService businessNumberService;

    @Autowired
    private IWorkFlowService workFlowService;

    @Autowired
    private AssetsMapper assetsMapper;

    @Autowired
    private AssetsProductionMapper assetsProductionMapper;

    @Autowired
    private AssetsEvaluationTargetMapper assetsEvaluationTargetMapper;

    /**
     * 条件查询资产任务列表
     *
     * @param page            分页条件
     * @param assetsSelectDTO 查询条件
     * @return Page<AssetsVO>
     */
    @Override
    public Page<AssetsVO> selectPage(Page page, AssetsSelectDTO assetsSelectDTO) {
        return assetsMapper.selectPage(page, assetsSelectDTO);
    }

    /**
     * 条件查询我的资产任务订单列表
     *
     * @param page            分页条件
     * @param assetsSelectDTO 查询条件
     * @return Page<AssetsVO>
     */
    @Override
    public Page<AssetsVO> selectMyOrderPage(Page page, AssetsSelectDTO assetsSelectDTO) {
        return assetsMapper.selectMyOrderPage(page, assetsSelectDTO);
    }

    /**
     * 条件查询资产已归档列表
     * @param page 分页条件
     * @param assetsSelectDTO 查询条件
     * @return Page<AssetsVO>
     */
    @Override
    public Page<AssetsVO> selectArchivedPage(Page page, AssetsSelectDTO assetsSelectDTO) {
        return assetsMapper.selectArchivedPage(page, assetsSelectDTO);
    }

    /**
     * 条件查询资产已终止列表
     * @param page 分页条件
     * @param assetsSelectDTO 查询条件
     * @return Page<AssetsVO>
     */
    @Override
    public Page<AssetsVO> selectTerminatedPage(Page page, AssetsSelectDTO assetsSelectDTO) {
        assetsSelectDTO.setHandlerId(LoginContext.getCurrentUserId());
        return assetsMapper.selectTerminatedPage(page, assetsSelectDTO);
    }


    /**
     * 条件查询资产已终止列表
     * @param page 分页条件
     * @param assetsSelectDTO 查询条件
     * @return Page<AssetsVO>
     */
    @Override
    public Page<AssetsRepertoryVo> selectRepertoryPage(Page page, AssetsSelectDTO assetsSelectDTO) {
        return assetsMapper.selectRepertoryPage(page, assetsSelectDTO);
    }

    /**
     * 条件查询资产入库统计集合(用于导出)
     * @param assetsSelectDTO 查询条件
     * @return Page<AssetsVO>
     */
    @Override
    public List<AssetsRepertoryVo> selectRepertoryList(AssetsSelectDTO assetsSelectDTO) {
        return assetsMapper.selectRepertoryList(assetsSelectDTO);
    }

    /**
     * 根据业务id获取资产业务详情
     *
     * @param id 业务id
     * @return AssetsVO
     */
    @Override
    public AssetsVO getAssetsDetailById(Long id) {
        AssetsVO assetsVO = assetsMapper.getAssetsDetailById(id);
        return assetsVO;
    }


    /**
     * 新增资产业务订单
     *
     * @param assets 资产订单信息
     * @return Boolean
     */
    @Override
    public WorkNodeCommit add(Assets assets) {
        //获取项目编号
        assets.setOrderId(businessNumberService.takeOrderNumber());
        //新增订单信息
        this.save(assets);
        //发起流程
        return workFlowService.openingOrder(ASSET_BUSINESS, assets.getId(), null, assets.getRemark());
    }

    /**
     * 修改资产业务订单项目负责人与项目成员
     *
     * @param taskRecordDTO 修改dto
     * @return Boolean
     */
    @Override
    public Boolean updatePrincipalAndMembers(TaskRecordDTO<AssetsPrincipalMembersDTO> taskRecordDTO) {
        AssetsPrincipalMembersDTO assetsPrincipalMembersDTO = taskRecordDTO.getTaskData();
        if (ObjectUtil.isNull(assetsPrincipalMembersDTO.getPrincipalId()) && ObjectUtil.isNull(assetsPrincipalMembersDTO.getMembers())) {
            ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR, "项目负责人和项目参与人员不能为空。");
        }
        return this.update(new LambdaUpdateWrapper<Assets>().set(Assets::getMembers, assetsPrincipalMembersDTO.getMembers()).set(Assets::getPrincipalId, assetsPrincipalMembersDTO.getPrincipalId())
                .eq(BaseEntity::getId, assetsPrincipalMembersDTO.getId()));
    }

    /**
     * 根据业务id获取资产业务款项信息
     *
     * @param id 业务id
     * @return AssetsOrderFundInvoiceVO
     */
    @Override
    public AssetsOrderFundInvoiceVO getOrderFundInvoiceById(Long id) {
        return assetsMapper.getOrderFundInvoiceById(id);
    }

    @Override
    public Boolean update(Assets assets) {
        return this.updateById(assets);
    }

    @Override
    public Boolean delete(Long id) {
        //逻辑删除
        return this.removeById(id);
    }

    /**
     * 资产业务产品取号
     * 格式示例:川友预报字2024第0101-2号
     *
     * @param dto 取号dto
     * @return String
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean takeAssetsProductionNo(TakeAssetsProductionNoDTO dto) {
        String productionNo = genProductionNo(dto);
        //产品添加产品号
        assetsProductionMapper.updateProductionNo(dto.getBusinessId(), dto.getProductionType(), productionNo);
        //如果还有未取号评估对象,再添加一份同类型产品
        if (dto.getHasNotTakeNumTargetSelect()) {
            assetsProductionMapper.copyProductionInfo(dto.getBusinessId(), dto.getProductionType(), dto.getPrintCount());
        }
        //评估对象添加产品号
        for (Long id : dto.getTargetIdList()) {
            //判断取号的产品类型
            if (dto.getProductionType().equals(STATEMENT.getCode())){ //意见书
                assetsEvaluationTargetMapper.updateTargetStatementNo(id, productionNo);
            }else { //报告
                assetsEvaluationTargetMapper.updateTargetReportNo(id, productionNo);
            }

        }
        if (ObjectUtil.isNotNull(productionNo) && ObjectUtil.isNotEmpty(productionNo)){
            return Boolean.TRUE;
        }else {
            return Boolean.FALSE;
        }

    }

    /**
     * 生成资产产品号
     *
     * @param takeAssetsProductionNoDTO 取号dto
     * @return String
     */
    public String genProductionNo(TakeAssetsProductionNoDTO takeAssetsProductionNoDTO) {
        //获取年份
        Calendar calendar = Calendar.getInstance();
        int nowYear = calendar.get(Calendar.YEAR);
        String productionNo = "（" + nowYear + "）" + "第";

        //获取资产产品取号信息
        BusinessNumber businessNumber = assetsMapper.getBusinessNum(takeAssetsProductionNoDTO.getProductionType() + "_NUMBER", ASSET_BUSINESS.getCode(), nowYear);

        //获取当前资产业务评估对象已经生成的产品号集合
        List<String> productionNoList = null;
        //判断取号的产品类型
        if (takeAssetsProductionNoDTO.getProductionType().equals(STATEMENT.getCode())){ //意见书
            productionNoList = assetsEvaluationTargetMapper.getStatementNoList(takeAssetsProductionNoDTO.getBusinessId());
        }else { //报告
            productionNoList = assetsEvaluationTargetMapper.getReportNoList(takeAssetsProductionNoDTO.getBusinessId());
        }
        //判断该资产业务订单是否有取过号
        if (ObjectUtil.isNull(productionNoList) || productionNoList.isEmpty()) {
            //判断是否有取号信息
            if (ObjectUtil.isNotNull(businessNumber)) { //取号信息不为空组合产品号
                //判断两个进位是否都>9,具有两位数
                if (businessNumber.getMonth() > 9 && businessNumber.getNextNo() > 9) {
                    productionNo = productionNo + businessNumber.getMonth() + businessNumber.getNextNo();
                } else {
                    //第一进位小于10,前面多加一个0组成两位
                    if (businessNumber.getMonth() < 10) {
                        productionNo = productionNo + "0" + businessNumber.getMonth();
                    } else {
                        productionNo = productionNo + businessNumber.getMonth();
                    }
                    //第二进位小于10,前面多加一个0组成两位
                    if (businessNumber.getNextNo() < 10) {
                        productionNo = productionNo + "0" + businessNumber.getNextNo();
                    } else {
                        productionNo = productionNo + businessNumber.getNextNo();
                    }
                }
                //设置下一个产品号取号信息
                if (businessNumber.getNextNo() < 99) {
                    businessNumber.setNextNo(businessNumber.getNextNo() + 1);
                } else {
                    businessNumber.setMonth(businessNumber.getMonth() + 1);
                    businessNumber.setNextNo(1);
                }
                //更新取号信息
                assetsMapper.updateBusinessNum(businessNumber);
            } else { //为空插入取号规则信息,并重新获取
                businessNumber = addBusinessNumber(takeAssetsProductionNoDTO.getProductionType() + "_NUMBER", ASSET_BUSINESS.getCode(), nowYear);
                //判断两个进位是否都>9,具有两位数
                if (businessNumber.getMonth() > 9 && businessNumber.getNextNo() > 9) {
                    productionNo = productionNo + businessNumber.getMonth() + businessNumber.getNextNo();
                } else {
                    //第一进位小于10,前面多加一个0组成两位
                    if (businessNumber.getMonth() < 10) {
                        productionNo = productionNo + "0" + businessNumber.getMonth();
                    } else {
                        productionNo = productionNo + businessNumber.getMonth();
                    }
                    //第二进位小于10,前面多加一个0组成两位
                    if (businessNumber.getNextNo() < 10) {
                        productionNo = productionNo + "0" + businessNumber.getNextNo();
                    } else {
                        productionNo = productionNo + businessNumber.getNextNo();
                    }
                }
                //设置下一个产品号取号信息
                if (businessNumber.getNextNo() < 99) {
                    businessNumber.setNextNo(businessNumber.getNextNo() + 1);
                } else {
                    businessNumber.setMonth(businessNumber.getMonth() + 1);
                    businessNumber.setNextNo(1);
                }
                //更新取号信息
                assetsMapper.updateBusinessNum(businessNumber);
            }

            //判断取号产品类型

            if (takeAssetsProductionNoDTO.getProductionType().equals(STATEMENT.getCode())) { //取号产品为意见书
                productionNo = "川友预报字" + productionNo;
            } else if (takeAssetsProductionNoDTO.getProductionType().equals(REPORT.getCode())) { //取号产品为评估报告
                productionNo = "川友评报字" + productionNo;
            } else if (takeAssetsProductionNoDTO.getProductionType().equals(CONSULT.getCode())) { //取号产品为咨询报告
                productionNo = "川友咨报字" + productionNo;
            } else if (takeAssetsProductionNoDTO.getProductionType().equals(LETTER.getCode())) { //取号产品为意见函
                productionNo = "川友字" + productionNo;
            } else { //都不是返回null
                return null;
            }
        } else { //已经在该子号之前生成过子号则直接将上一个产品的主体拿过来赋值
            int dashIndex = productionNoList.get(0).indexOf('-');
            productionNo = productionNoList.get(0).substring(0, dashIndex);
        }


        // 判断有无子号
        if (takeAssetsProductionNoDTO.getSelectAll()) { //true 则选择了全部评估对象,仅主号无子号
            return productionNo + "号";
        } else { //false 选择了部分评估对象,有子号
            return getProductionSecNum(productionNo, productionNoList);
        }
    }

    /**
     * 获取资产产品子号
     *
     * @return String
     */
    public String getProductionSecNum(String productionNo, List<String> productionNoList) {
        // 判断同一资产业务的同一类型产品是否有生成过子号
        if (ObjectUtil.isNull(productionNoList) || productionNoList.isEmpty()) { //为null还没有生成过子号,生成第一个
            return productionNo + "-1号";
        } else { //不为null则说明已经生成过子号,找到目前最大的子号并生成下一个子号
            // 初始化最大子号为Integer.MIN_VALUE
            int maxNumber = Integer.MIN_VALUE;

            // 正则表达式，用于匹配短横线-后面的数字
            Pattern pattern = Pattern.compile("-(\\d+)");

            // 遍历字符串列表
            for (String str : productionNoList) {
                // 创建匹配器
                Matcher matcher = pattern.matcher(str);
                // 在字符串中查找短横线后面的数字
                while (matcher.find()) {
                    // 将找到的子号从字符串转换为整数
                    int secNum = Integer.parseInt(matcher.group(1));
                    // 更新最大的子号
                    if (secNum > maxNumber) {
                        maxNumber = secNum;
                    }
                }
            }
            // 将找到的最大子号 + 1, 得到下一个子号
            maxNumber = maxNumber + 1;
            return productionNo + "-" + maxNumber + "号";
        }
    }

    /**
     * 新增资产取号信息,并返回
     *
     * @param takeType     取号类型(同产品类型)
     * @param businessType 业务类型
     * @param year         年份
     * @return BusinessNumber
     */
    public BusinessNumber addBusinessNumber(String takeType, String businessType, Integer year) {
        BusinessNumber businessNumber = new BusinessNumber();
        businessNumber.setTakeType(takeType);
        businessNumber.setBusinessType(businessType);
        businessNumber.setYear(year);
        businessNumber.setMonth(1);
        businessNumber.setNextNo(1);
        //新增
        assetsMapper.addBusinessNum(businessNumber);
        //查询
        return assetsMapper.getBusinessNum(takeType, businessType, year);
    }

    /**
     * 获取资产项目所有参与人
     * @param assetsBusinessMembersDTO 查询dto
     * @return List<AssetsBusinessMembers>
     */
    @Override
    public List<AssetsBusinessMember> getAssetsBusinessMembers(AssetsBusinessMembersDTO assetsBusinessMembersDTO) throws JsonProcessingException {
        // 获取项目参与人id
        Assets businessMember = assetsMapper.getBusinessMembers(assetsBusinessMembersDTO);
        // 获取签字师id
        String signatorys = assetsMapper.getSignatorys(assetsBusinessMembersDTO);

        List<AssetsBusinessMember> assetsBusinessMemberList = new ArrayList<>();

        //获取项目负责人信息
        AssetsBusinessMember assetsBusinessMember;
        assetsBusinessMember = assetsMapper.getAssetsBusinessMember(businessMember.getPrincipalId());
        assetsBusinessMember.setBusinessId(assetsBusinessMembersDTO.getBusinessId());
        assetsBusinessMember.setMemberType("项目负责人");
        assetsBusinessMemberList.add(assetsBusinessMember);

        ObjectMapper objectMapper = new ObjectMapper();
        List<Long> memberIds = objectMapper.readValue(businessMember.getMembers(), new TypeReference<List<Long>>() {});
        List<Long> signatoryIds = objectMapper.readValue(signatorys, new TypeReference<List<Long>>() {});

        // 获取参与人信息
        for (Long userId : memberIds){
            assetsBusinessMember = assetsMapper.getAssetsBusinessMember(userId);
            assetsBusinessMember.setBusinessId(assetsBusinessMembersDTO.getBusinessId());
            assetsBusinessMember.setMemberType("项目参与人");
            assetsBusinessMemberList.add(assetsBusinessMember);
        }

        // 获取签字师信息
        for (Long userId : signatoryIds){
            assetsBusinessMember = assetsMapper.getAssetsBusinessMember(userId);
            assetsBusinessMember.setBusinessId(assetsBusinessMembersDTO.getBusinessId());
            assetsBusinessMember.setMemberType("签字师");
            assetsBusinessMemberList.add(assetsBusinessMember);
        }

        return assetsBusinessMemberList;
    }
}
