package com.testor.module.contractor.manage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.testor.common.constant.StatusEnum;
import com.testor.common.model.UpdateProcessStatusReq;
import com.testor.module.contractor.common.model.constant.ContractorProcessStatus;
import com.testor.module.contractor.enums.ContractorEvaluateIfVetoEnum;
import com.testor.module.contractor.enums.ContractorFlowTypeEnum;
import com.testor.module.contractor.enums.GeneralFlagEnum;
import com.testor.module.contractor.ledger.model.domain.TContractorInfo;
import com.testor.module.contractor.ledger.model.domain.TContractorLedger;
import com.testor.module.contractor.ledger.service.TContractorInfoService;
import com.testor.module.contractor.ledger.service.TContractorLedgerService;
import com.testor.module.contractor.manage.dao.TContractorEvaluateDao;
import com.testor.module.contractor.manage.model.domain.TContractorAcceptance;
import com.testor.module.contractor.manage.model.domain.TContractorBlacklist;
import com.testor.module.contractor.manage.model.domain.TContractorEvaluate;
import com.testor.module.contractor.manage.model.domain.TContractorEvaluateDetail;
import com.testor.module.contractor.manage.model.dto.ContractorEvaluateDto;
import com.testor.module.contractor.manage.model.dto.TContractorAcceptanceDTO;
import com.testor.module.contractor.manage.model.dto.TContractorEvaluateParam;
import com.testor.module.contractor.manage.service.TContractorAcceptanceService;
import com.testor.module.contractor.manage.service.TContractorBlacklistService;
import com.testor.module.contractor.manage.service.TContractorEvaluateDetailService;
import com.testor.module.contractor.manage.service.TContractorEvaluateService;
import com.tongtech.tfw.backend.common.biz.constants.BizConstants;
import com.tongtech.tfw.backend.common.context.ContextUtils;
import com.tongtech.tfw.backend.common.exception.BusinessException;
import com.tongtech.tfw.backend.common.models.supers.SuperServiceImpl;
import com.tongtech.tfw.backend.common.models.sys.UserInfo;
import com.tongtech.tfw.backend.core.helper.IdHelper;
import com.tongtech.tfw.backend.core.helper.ObjectHelper;
import com.tongtech.tfw.backend.core.helper.StringHelper;
import com.tongtech.tfw.backend.core.helper.bean.BeanHelper;
import com.tongtech.tfw.workflow.apis.definition.controller.ProcessDefinitionController;
import com.tongtech.tfw.workflow.apis.definition.model.dto.ProcessDefStartParam;
import com.tongtech.tfw.workflow.apis.task.controller.WfTaskController;
import com.tongtech.tfw.workflow.apis.task.model.dto.CompleteTask;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 承包商考核评价Service业务层处理
 *
 * @author testor-framework
 * @date 2024-11-30 15:42:18
 */
@Service
public class TContractorEvaluateServiceImpl extends SuperServiceImpl<TContractorEvaluateDao, TContractorEvaluate> implements TContractorEvaluateService {
    @Autowired(required = false)
    private TContractorEvaluateDao tContractorEvaluateDao;

    @Autowired
    private TContractorEvaluateDetailService tContractorEvaluateDetailService;

    @Autowired
    private ProcessDefinitionController processDefinitionController;

    @Autowired
    private WfTaskController wfTaskController;

    @Autowired
    private TContractorBlacklistService tContractorBlacklistService;

    @Autowired
    private TContractorAcceptanceService tContractorAcceptanceService;

    @Autowired
    private TContractorLedgerService tContractorLedgerService;

    @Autowired
    private TContractorInfoService tContractorInfoService;

    /**
     * 根据承包商id查询承包商考核评价记录，如果有则返回，如果没有则返回null
     *
     * @param contractorId 承包商台账id
     * @return
     */
    @Override
    public TContractorEvaluate getByContractorId(String contractorId) {
        QueryWrapper<TContractorEvaluate> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(TContractorEvaluate.CONTRACTOR_ID, contractorId);
        queryWrapper.ne(TContractorEvaluate.STATUS, StatusEnum.DELETE.getCode());
        return this.getOne(queryWrapper, false);
    }

    @Override
    public Page<ContractorEvaluateDto> pageList(TContractorEvaluateParam param) {
        Long page =
                StringHelper.isEmpty(param.getPage()) ? BizConstants.PAGE : Long.valueOf(param.getPage());
        Long limit =
                StringHelper.isEmpty(param.getLimit()) ? BizConstants.LIMIT : Long.valueOf(param.getLimit());
        Page<TContractorEvaluate> resultPage = new Page<>(page, limit);
        UserInfo loginUser = ContextUtils.getLoginUser();
        param.setOrgId(loginUser.getOrgId());
        return tContractorEvaluateDao.pageList(resultPage, param);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TContractorEvaluate addEntity(TContractorEvaluateParam addRequest) {
        String id = IdHelper.getId32bit();
        TContractorEvaluate data = BeanHelper.beanToBean(addRequest, TContractorEvaluate.class);
        data.setId(id);
        data.setProcessStatus(ContractorProcessStatus.PENDING_SUBMISSION.getValue());
        data.setEvaluatePerson(ContextUtils.getLoginUser().getUserName());
        List<TContractorEvaluateDetail> evaluateDetails = addRequest.getEvaluateDetails();
        if(StringUtils.isEmpty(data.getOrgId())){
            data.setOrgId(ContextUtils.getLoginUser().getOrgId());
        }
        boolean result = save(data);
        for (TContractorEvaluateDetail detail : evaluateDetails) {
            detail.setEvaluateId(id);
        }
        if (result) {
            // 保存评价明细
            tContractorEvaluateDetailService.saveBatch(evaluateDetails);
        }
        // 计算总得分，并更新评价总分
        this.setTotalScore(data, evaluateDetails);
        BigDecimal score = data.getScore();
        String evaluteLevel = "";
        if(score.compareTo(new BigDecimal(90)) > 0){
            evaluteLevel = "优秀";
        } else if(score.compareTo(new BigDecimal(70)) > 0){
            evaluteLevel = "达标";
        } else if (score.compareTo(new BigDecimal(60)) >= 0){
            evaluteLevel = "一般";
        } else {
            evaluteLevel = "不达标";
        }
        data.setEvaluateLevel(evaluteLevel);
        this.updateById(data);
        return data;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateEntity(TContractorEvaluateParam updateRequest) {
        TContractorEvaluate data = BeanHelper.beanToBean(updateRequest, TContractorEvaluate.class);
        List<TContractorEvaluateDetail> evaluateDetails = updateRequest.getEvaluateDetails();
        // 计算总得分
        this.setTotalScore(data, evaluateDetails);
        BigDecimal score = data.getScore();
        String evaluteLevel = "";
        if(score.compareTo(new BigDecimal(90)) > 0){
            evaluteLevel = "优秀";
        } else if(score.compareTo(new BigDecimal(70)) > 0){
            evaluteLevel = "达标";
        } else if (score.compareTo(new BigDecimal(60)) >= 0){
            evaluteLevel = "一般";
        } else {
            evaluteLevel = "不达标";
        }
        data.setEvaluateLevel(evaluteLevel);
        // 更新评价总分
        boolean result = this.updateById(data);
        if (result && ObjectHelper.isNotEmpty(evaluateDetails)) {
            // 更新评价明细
            tContractorEvaluateDetailService.updateBatchById(evaluateDetails);
        }

        return result;

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProcessStatus(UpdateProcessStatusReq updateProcessStatusReq) throws Exception {
        if (StringHelper.isEmpty(updateProcessStatusReq.getId()) || StringHelper.isEmpty(updateProcessStatusReq.getProcessStatus())) {
            throw new BusinessException("请求参数有误，请联系管理员！");
        }
        this.lambdaUpdate().set(TContractorEvaluate::getProcessStatus, updateProcessStatusReq.getProcessStatus())
                .set(StringUtils.isNotEmpty(updateProcessStatusReq.getProcessId()), TContractorEvaluate::getProcessId
                        , updateProcessStatusReq.getProcessId())
                .set(StringUtils.isNotEmpty(updateProcessStatusReq.getRejectOpinion()),
                        TContractorEvaluate::getRejectOpinion, updateProcessStatusReq.getRejectOpinion())
                .eq(TContractorEvaluate::getId, updateProcessStatusReq.getId()).update();
    }

    @Override
    public void startProcess(TContractorEvaluateParam updateRequest) {
        // 创建一个ProcessDefStartParam对象，并设置流程定义的key为"contractor"
        ProcessDefStartParam processDefStartParam = new ProcessDefStartParam("contractor");
        // 如果是新增提交，则先保存数据，再执行后续逻辑
        if(StringUtils.isEmpty(updateRequest.getId())){
            TContractorEvaluate evaluate = this.addEntity(updateRequest);
            updateRequest.setId(evaluate.getId());
        }
        // 设置业务主键为updateRequest的id
        processDefStartParam.setBizKey(updateRequest.getId());
        // 创建一个Map对象，并设置type为"evaluate"
        Map<String, Object> map = new HashMap<>();
        map.put("type", ContractorFlowTypeEnum.EVALUATE.getCode());
        // 将Map对象设置到processDefStartParam的variables属性中
        processDefStartParam.setVariables(map);
        // 调用processDefinitionController的startProcessIns方法，并获取返回结果
        String result = processDefinitionController.startProcessIns(processDefStartParam).getData().getResult();

        // 创建一个TContractorEvaluate对象,更新流程状态
        TContractorEvaluate tContractorEvaluate = new TContractorEvaluate();
        tContractorEvaluate.setId(updateRequest.getId());
        // 设置processId为result
        tContractorEvaluate.setProcessId(result);
        // 设置processStatus为待审核
        tContractorEvaluate.setProcessStatus(ContractorProcessStatus.UNDER_REVIEW.getValue());
        // 评价时间取提交审批时间
        tContractorEvaluate.setEvaluateTime(new Date());
        // 更新实体
        this.updateById(tContractorEvaluate);
    }

    @Override
    public void completeProcess(TContractorEvaluateParam updateRequest) {
        String processStatus = updateRequest.getProcessStatus();
        CompleteTask completeTask = new CompleteTask();
        completeTask.setBizId(updateRequest.getId());
        completeTask.setTaskId(updateRequest.getTaskId());
        // 创建一个vars参数
        Map<String, Object> vars = StringHelper.isEmpty(updateRequest.getVars()) ? new HashMap<>() : updateRequest.getVars();
        if(!vars.containsKey("processStatus")) {
            vars.put("processStatus", processStatus);
        }
        completeTask.setVars(vars);
        wfTaskController.completeTask(completeTask).getData().getResult();
        // 创建一个TContractorEvaluate对象
        TContractorEvaluate tContractorEvaluate = new TContractorEvaluate();
        // 设置id为updateRequest的id
        tContractorEvaluate.setId(updateRequest.getId());
        // 设置processStatus
        tContractorEvaluate.setProcessStatus(processStatus);
        if(ContractorProcessStatus.REJECTED.getValue().equals(processStatus)){
            String rejectOpinion = vars.get("rejectOpinion") == null ? "" : vars.get("rejectOpinion").toString();
            tContractorEvaluate.setRejectOpinion(rejectOpinion);
        }
        // 调用tContractorEvaluateService的updateById方法，更新tContractorEvaluate对象
        boolean result = this.updateById(tContractorEvaluate);
        if(result && processStatus.equals(ContractorProcessStatus.APPROVED.getValue())){
            tContractorEvaluate  = this.getById(updateRequest.getId());
            this.setContractorBlacklist(tContractorEvaluate);
        }
    }

    /**
     * 下一步
     *
     * @param updateRequest
     */
    @Override
    public void nextStep(TContractorEvaluateParam updateRequest) {
        TContractorAcceptanceDTO acceptanceDTO = new TContractorAcceptanceDTO();
        acceptanceDTO.setContractorId(updateRequest.getContractorId());
        acceptanceDTO.setProjId(updateRequest.getProjId());
        acceptanceDTO.setBizId(updateRequest.getBizId());
        acceptanceDTO.setOrgId(updateRequest.getOrgId());
        TContractorAcceptance result = tContractorAcceptanceService.addEntity(acceptanceDTO);

        TContractorEvaluate  tContractorEvaluate = new TContractorEvaluate();
        tContractorEvaluate.setId(updateRequest.getId());
        tContractorEvaluate.setIfNext(GeneralFlagEnum.YES.getCode());
        this.updateById(tContractorEvaluate);
    }

    /**
     * 计算总得分
     *
     * @param data
     * @param evaluateDetails
     */
    private void setTotalScore(TContractorEvaluate data, List<TContractorEvaluateDetail> evaluateDetails){
        BigDecimal totalScore = new BigDecimal(0);
        if(ObjectHelper.isEmpty(evaluateDetails)){
            data.setScore(totalScore);
            return;
        }
        // 日常表现-应急管理-应急物资-未配置应急物资项适用性及得分
        String isUseT31 = GeneralFlagEnum.NO.getCode();
        BigDecimal scoreT31 = new BigDecimal(0);

        // 日常表现-应急管理-应急物资-已配置但应急物资不合项适用性及得分
        String isUseT32 = GeneralFlagEnum.NO.getCode();
        BigDecimal scoreT32 = new BigDecimal(0);

        for (TContractorEvaluateDetail detail : evaluateDetails) {
            if (GeneralFlagEnum.YES.getCode().equals(detail.getIsUse()) && detail.getScore() != null) {
                totalScore = totalScore.add(detail.getScore());
            }
            if ("T31".equals(detail.getIndexCode())) {
                isUseT31 = detail.getIsUse();
                scoreT31 = detail.getScore();
            }
            if ("T32".equals(detail.getIndexCode())) {
                isUseT32 = detail.getIsUse();
                scoreT32 = detail.getScore();
            }
        }
        // 不涉及否决项时，需要计算总得分
        if(ContractorEvaluateIfVetoEnum.NONE.getCode().equals(data.getIfVeto())) {
            // 日常表现-应急管理-应急物资,未配置和已配置但不全是属于互斥性评价，避免前端两项都填写导致多计算得分，后台计算时需要从部分中去除多计算的得分
            if (GeneralFlagEnum.YES.getCode().equals(isUseT31) && GeneralFlagEnum.YES.getCode().equals(isUseT32)
                    && scoreT31 != null && scoreT32 != null
                    && scoreT32.compareTo(new BigDecimal(0)) > 0) {
                // 如果两项都填写了得分，则未配置的情况优先，已配置但应急物资不全项得分需要扣除
                totalScore = totalScore.subtract(scoreT32);
            }
            data.setScore(totalScore);
        } else {
            data.setScore(new BigDecimal(0));
        }
    }

    /**
     * 设置承包商黑名单
     *
     * @param tContractorEvaluate
     */
    private void setContractorBlacklist(TContractorEvaluate tContractorEvaluate){
        // 如果承包商考核评价得分小于70分，则自动进入黑名单
        if(tContractorEvaluate.getScore().compareTo(new BigDecimal(70)) >= 0){
            return;
        }
        TContractorBlacklist blacklist = tContractorBlacklistService.getByContractorId(tContractorEvaluate.getContractorId());
        if(blacklist != null) {
            return;
        }
        blacklist = new TContractorBlacklist();
        blacklist.setId(IdHelper.getId32bit());
        blacklist.setContractorId(tContractorEvaluate.getContractorId());
        blacklist.setProjId(tContractorEvaluate.getProjId());
        blacklist.setBizId(tContractorEvaluate.getBizId());
        blacklist.setEvaluateId(tContractorEvaluate.getId());
        blacklist.setEvaluatePerson(tContractorEvaluate.getEvaluatePerson());
        blacklist.setViolationReason("承包商考核评价得分小于70分，自动进入黑名单");
        blacklist.setProcessStatus(ContractorProcessStatus.APPROVED.getValue());
        blacklist.setOrgId(tContractorEvaluate.getOrgId());
        boolean flag = tContractorBlacklistService.save(blacklist);
        if(!flag){
            return;
        }
        TContractorLedger contractorLedger =
                tContractorLedgerService.getById(tContractorEvaluate.getContractorId());
        // 更新承包商信息为黑名单
        if(contractorLedger != null){
            TContractorInfo tContractorInfo = new TContractorInfo();
            tContractorInfo.setId(contractorLedger.getInfoId());
            tContractorInfo.setIsBlacklist(GeneralFlagEnum.YES.getCode());
            tContractorInfoService.updateById(tContractorInfo);
        }
    }
}
