package com.casic.missiles.service.Impl.meter;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.casic.missiles.core.application.service.AbstractDictService;
import com.casic.missiles.core.model.auth.AuthUser;
import com.casic.missiles.core.shiro.ShiroKit;
import com.casic.missiles.dto.BaseApprovalSubmitRequest;
import com.casic.missiles.dto.ReturnDTO;
import com.casic.missiles.dto.ReturnUtil;
import com.casic.missiles.dto.flowable.AllApproveDTO;
import com.casic.missiles.dto.flowable.ApprovalDeleteRequest;
import com.casic.missiles.dto.flowable.ToBeApprovedDTO;
import com.casic.missiles.dto.meter.*;
import com.casic.missiles.enums.BusinessExceptionEnum;
import com.casic.missiles.enums.PrefixCodeEnum;
import com.casic.missiles.enums.meter.MeterDictEnum;
import com.casic.missiles.enums.system.ApprovalStatusEnum;
import com.casic.missiles.exception.BusinessException;
import com.casic.missiles.mapper.meter.MeterTraceSupplierMapper;
import com.casic.missiles.model.meter.MeterTraceSupplier;
import com.casic.missiles.model.meter.MeterTraceSupplierPerson;
import com.casic.missiles.model.meter.MeterTraceSupplierStandardEquipment;
import com.casic.missiles.model.response.ResponseData;
import com.casic.missiles.service.IBaseApprovalService;
import com.casic.missiles.service.flowable.ApprovalOperateService;
import com.casic.missiles.service.meter.IMeterTraceSupplierPersonService;
import com.casic.missiles.service.meter.IMeterTraceSupplierService;
import com.casic.missiles.service.meter.IMeterTraceSupplierStandardEquipmentService;
import com.casic.missiles.utils.ConvertUtils;
import com.casic.missiles.utils.DictCodeUtils;
import com.casic.missiles.utils.NumberGeneratorUtil;
import com.casic.missiles.utils.PageUtil;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 计量管理-溯源供方-溯源供方表(计量计量单位的设备的单位) 服务实现类
 * </p>
 *
 * @author wangpeng
 * @since 2022-11-28
 */
@Service
public class MeterTraceSupplierServiceImpl extends ServiceImpl<MeterTraceSupplierMapper, MeterTraceSupplier> implements IMeterTraceSupplierService {
    @Autowired
    private MeterTraceSupplierMapper traceSupplierMapper;
    @Autowired
    private IMeterTraceSupplierPersonService traceSupplierPersonService;
    @Resource
    private AbstractDictService dictService;
    @Autowired
    private IBaseApprovalService baseApprovalService;
    @Autowired
    private ApprovalOperateService approvalOperateService;
    @Resource
    private TaskService taskService;
    @Resource
    private RuntimeService runtimeService;
    @Autowired
    private IMeterTraceSupplierStandardEquipmentService meterTraceSupplierStandardEquipmentService;

    @Override
    public Page<MeterTraceSupplier> listPage(Page<MeterTraceSupplier> page, TraceSupplierListRequest request) {
        QueryWrapper<MeterTraceSupplier> wrapper = getWrapper(request);
        Page<MeterTraceSupplier> traceSupplierPage = traceSupplierMapper.selectPage(page, wrapper);
        traceSupplierPage.getRecords().stream().forEach(result -> {
            result.setApprovalStatusName(dictService.getDictNameByCode(MeterDictEnum.APPROVAL_STATUS, result.getApprovalStatus()));
        });
        return traceSupplierPage;
    }

    @Override
    public List<MeterTraceSupplier> list(TraceSupplierListRequest request) {
        QueryWrapper<MeterTraceSupplier> wrapper = getWrapper(request);
        return traceSupplierMapper.selectList(wrapper);
    }

    @Override
    @Transactional
    public ReturnDTO<TraceSupplierSaveResponse> saveTraceSupplier(MeterTraceSupplier traceSupplier) {
        //生成编号
        Long maxNo = traceSupplierMapper.selectMaxSupplierNo();
        String supplierNo = NumberGeneratorUtil.getContactNo(PrefixCodeEnum.TRACE_SUPPLIER_PREFIX, maxNo);
        traceSupplier.setSupplierNo(supplierNo);
        traceSupplier.setApprovalStatus(ApprovalStatusEnum.DRAFT); //草稿箱状态
        Assert.isFalse(Objects.isNull(ShiroKit.getUser()), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        traceSupplier.setCreateUserId(ShiroKit.getUser().getId()); //登录者用户id
        int insertFlag = traceSupplierMapper.insert(traceSupplier);
        Assert.isFalse(insertFlag <= 0, () -> {
            throw new BusinessException(BusinessExceptionEnum.TRACE_SUPPLIER_SAVE_FAILED);
        });
        //存储溯源供方人员信息
        boolean saveBatchFlag = true;
        List<MeterTraceSupplierPerson> traceSupplierPersonList = traceSupplier.getTraceSupplierPersonList();
        if (!CollectionUtils.isEmpty(traceSupplierPersonList)) {
            traceSupplierPersonList.forEach(person -> {
                person.setSupplierId(traceSupplier.getId());
            });
            saveBatchFlag = traceSupplierPersonService.saveBatch(traceSupplierPersonList);
        }
        Assert.isFalse(!saveBatchFlag, () -> {
            throw new BusinessException(BusinessExceptionEnum.TRACE_SUPPLIER_SAVE_FAILED);
        });

        //存储溯源供方标准装置信息
        boolean saveBatchFlag2 = true;
        List<Long> standardEquipmentIds = traceSupplier.getStandardEquipmentIds();
        if (!CollectionUtils.isEmpty(standardEquipmentIds)) {
            List<MeterTraceSupplierStandardEquipment> equipmentList = new ArrayList<>();
            standardEquipmentIds.forEach(id -> {
                MeterTraceSupplierStandardEquipment equipment = new MeterTraceSupplierStandardEquipment();
                equipment.setStandardEquipmentId(id);
                equipment.setSupplierId(traceSupplier.getId());
                equipmentList.add(equipment);
            });
            saveBatchFlag2 = meterTraceSupplierStandardEquipmentService.saveBatch(equipmentList);
        }
        Assert.isFalse(!saveBatchFlag2, () -> {
            throw new BusinessException(BusinessExceptionEnum.TRACE_SUPPLIER_SAVE_FAILED);
        });

        TraceSupplierSaveResponse traceSupplierSaveResponse = new TraceSupplierSaveResponse();
        traceSupplierSaveResponse.setId(traceSupplier.getId());
        traceSupplierSaveResponse.setSupplierNo(supplierNo);
        return ReturnUtil.success(traceSupplierSaveResponse);
    }

    @Override
    @Transactional
    public ReturnDTO addTraceSupplierList(List<MeterTraceSupplier> list) throws Exception {
        //用于存储验证后的错误信息
        Long maxNo = traceSupplierMapper.selectMaxSupplierNo();
        for (MeterTraceSupplier item : list) {
            Set<ConstraintViolation<MeterTraceSupplier>> validate = Validation.buildDefaultValidatorFactory().getValidator().validate(item);
            if (!CollectionUtils.isEmpty(validate)) {
                return ReturnUtil.failed(validate.iterator().next().getMessage());
            }
            DictCodeUtils.validDictCode(item);
            //生成编号
            String supplierNo = NumberGeneratorUtil.getContactNo(PrefixCodeEnum.TRACE_SUPPLIER_PREFIX, maxNo);
            item.setSupplierNo(supplierNo);
            maxNo++;
        }
        super.saveBatch(list);
        return ReturnUtil.success();
    }

    @Override
    @Transactional
    public ReturnDTO draftUpdate(MeterTraceSupplier traceSupplier) {
        int updateFlag = traceSupplierMapper.updateById(traceSupplier);
        //更新溯源供方人员信息
        List<MeterTraceSupplierPerson> traceSupplierPersonList = traceSupplier.getTraceSupplierPersonList();
        //先删除
        QueryWrapper<MeterTraceSupplierPerson> wrapper = new QueryWrapper<>();
        wrapper.eq("supplier_id", traceSupplier.getId());
        //存在无可删除溯源供方人员情况，无需校验删除成功
        traceSupplierPersonService.remove(wrapper);
        boolean saveFlag = true;
        //溯源供方人员可能为空
        if (!CollectionUtils.isEmpty(traceSupplierPersonList)) {
            //再增加
            traceSupplierPersonList.forEach(person -> {
                person.setSupplierId(traceSupplier.getId());
            });
            saveFlag = traceSupplierPersonService.saveBatch(traceSupplierPersonList);
        }

        //更新溯源供方标准装置信息
        //先删除再增加
        QueryWrapper<MeterTraceSupplierStandardEquipment> wrapper1 = new QueryWrapper<>();
        wrapper1.eq("supplier_id", traceSupplier.getId());
        meterTraceSupplierStandardEquipmentService.remove(wrapper1);
        boolean saveBatchFlag2 = true;
        List<Long> standardEquipmentIds = traceSupplier.getStandardEquipmentIds();
        if (!CollectionUtils.isEmpty(standardEquipmentIds)) {
            List<MeterTraceSupplierStandardEquipment> equipmentList = new ArrayList<>();
            standardEquipmentIds.forEach(id -> {
                MeterTraceSupplierStandardEquipment equipment = new MeterTraceSupplierStandardEquipment();
                equipment.setStandardEquipmentId(id);
                equipment.setSupplierId(traceSupplier.getId());
                equipmentList.add(equipment);
            });
            saveBatchFlag2 = meterTraceSupplierStandardEquipmentService.saveBatch(equipmentList);
        }

        if (updateFlag > 0 && saveFlag && saveBatchFlag2) {
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    @Transactional
    public ReturnDTO submitTraceSupplier(BaseApprovalSubmitRequest request) {
        //已取消后的提交需先删除原有实例
        if (StringUtils.isNotEmpty(request.getProcessId())){
            runtimeService.updateBusinessStatus(request.getProcessId(), ApprovalStatusEnum.DELETED);
            runtimeService.deleteProcessInstance(request.getProcessId(), "删除");
        }
        //1.根据表单id获取流程定义id
        //2.根据流程定义id启动流程实例
        String formId = request.getFormId();
        ReturnDTO returnDTO = baseApprovalService.processSubmit(formId, request.getId());
        if (ResponseData.DEFAULT_SUCCESS_CODE != returnDTO.getCode()) {
            return returnDTO;
        }
        ProcessInstance processInstance = (ProcessInstance) returnDTO.getData();

        MeterTraceSupplier traceSupplier = new MeterTraceSupplier();
        traceSupplier.setId(request.getId());
        traceSupplier.setApprovalStatus(ApprovalStatusEnum.UN_DRAFT); //非草稿状态
        traceSupplier.setProcessId(processInstance.getId());
        int row = traceSupplierMapper.updateById(traceSupplier);
        if (row <= 0) {
            throw new BusinessException(BusinessExceptionEnum.TRACE_SUPPLIER_SUBMIT_FAILED);
        }
        return ReturnUtil.success();
    }

    @Override
    public List<TraceSupplierApprovalListResponse> approvalListPage(Page<TraceSupplierApprovalListResponse> page, TraceSupplierApprovalListRequest request) {
        //登录用户
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        request.setCreateUserId(user.getId());
        return handleApprovalStatus(page, request);
    }

    @Override
    public ReturnDTO approvalDelete(ApprovalDeleteRequest request) {
        ReturnDTO returnDTO = approvalOperateService.delete(request);
        if (ResponseData.DEFAULT_SUCCESS_CODE == returnDTO.getCode()) {
            //本地删除
            if (traceSupplierMapper.deleteById(request.getId()) > 0) {
                return ReturnUtil.success();
            }
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    @Transactional
    public ReturnDTO failUpdate(MeterTraceSupplier traceSupplier) {
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        if (traceSupplierMapper.updateById(traceSupplier) > 0) {
            baseApprovalService.failUpdate(traceSupplier.getProcessId());
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    private List<TraceSupplierApprovalListResponse> handleApprovalStatus(Page<TraceSupplierApprovalListResponse> page, TraceSupplierApprovalListRequest request) {
        List<TraceSupplierApprovalListResponse> approvalList = new ArrayList<>();
        List<String> businessKeys = new ArrayList<>();
        List<MeterTraceSupplier> list;
        switch (request.getApprovalStatus()) {
            //草稿
            case ApprovalStatusEnum.DRAFT:
                list = traceSupplierMapper.selectDraftListForApproval(page, request);
                approvalList = handleApprovalListResponse(approvalList, list, ApprovalStatusEnum.DRAFT);
                break;
            //待审批，该状态维护在flowable中
            case ApprovalStatusEnum.TO_BE_APPROVED:
                List<ToBeApprovedDTO> toBeApprovedList = baseApprovalService.getToBeApprovedList(request.getFormId());
                if (!CollectionUtils.isEmpty(toBeApprovedList)) {
                    businessKeys = toBeApprovedList.stream().map(ToBeApprovedDTO::getBusinessKey).distinct().collect(Collectors.toList());
                }
                if (!CollectionUtils.isEmpty(businessKeys)) {
                    list = traceSupplierMapper.selectBatchForApproval(page, request, businessKeys);
                    approvalList = handleApprovalListResponse(approvalList, list, ApprovalStatusEnum.TO_BE_APPROVED);
                    //DTO根据业务主键补全taskId
                    approvalList.forEach(approval -> {
                        toBeApprovedList.forEach(toBeApprovedDTO -> {
                            if (String.valueOf(approval.getId()).equals(toBeApprovedDTO.getBusinessKey())) {
                                approval.setTaskId(toBeApprovedDTO.getTaskId());
                                //补全可选决策项
                                approval.setDecisionItem(toBeApprovedDTO.getDecisionItem());
                            }
                        });
                    });
                }
                break;
            //审批中，该状态维护在flowable中
            case ApprovalStatusEnum.IN_APPROVED:
                businessKeys = baseApprovalService.getInApprovedList(request.getFormId());
                if (!CollectionUtils.isEmpty(businessKeys)) {
                    list = traceSupplierMapper.selectBatchForApproval(page, request, businessKeys);
                    approvalList = handleApprovalListResponse(approvalList, list, ApprovalStatusEnum.IN_APPROVED);
                }
                break;
            //已通过，该状态维护在flowable
            case ApprovalStatusEnum.PASSED:
                businessKeys = baseApprovalService.getPassedList(request.getFormId());
                if (!CollectionUtils.isEmpty(businessKeys)) {
                    list = traceSupplierMapper.selectBatchForApproval(page, request, businessKeys);
                    approvalList = handleApprovalListResponse(approvalList, list, ApprovalStatusEnum.PASSED);
                }
                break;
            //未通过（包括拒绝、驳回，拒绝为直接删除实例，驳回为驳回到起点），该状态维护在flowable
            case ApprovalStatusEnum.FAILED:
                businessKeys = baseApprovalService.getFailedList(request.getFormId()); //未通过-拒绝
                List<String> rejectBusinessKey = baseApprovalService.getFailedRejectList(request.getFormId()); //未通过-驳回
                if (!CollectionUtils.isEmpty(businessKeys)) {
                    list = traceSupplierMapper.selectBatchForApproval(page, request, businessKeys);
                    approvalList = handleApprovalListResponse(approvalList, list, ApprovalStatusEnum.FAILED);
                }
                List<TraceSupplierApprovalListResponse> rejectApprovalList = new ArrayList<>();
                if (!CollectionUtils.isEmpty(rejectBusinessKey)) {
                    List<MeterTraceSupplier> rejectList = traceSupplierMapper.selectBatchForApproval(page, request, rejectBusinessKey);
                    rejectApprovalList = handleApprovalListResponse(approvalList, rejectList, ApprovalStatusEnum.FAILED_REJECT);
                }
                //合并未通过-拒绝和未通过-驳回
                approvalList.addAll(rejectApprovalList);
                //分页处理
                if(!CollectionUtils.isEmpty(approvalList)) {
                    Page pages = PageUtil.getPages((int) page.getCurrent(), (int) page.getSize(), approvalList);
                    page.setTotal(approvalList.size());
                    approvalList = pages.getRecords();
                }
                break;
            //已取消，该状态维护在flowable
            case ApprovalStatusEnum.CANCELED:
                businessKeys = baseApprovalService.getCanceledList(request.getFormId());
                if (!CollectionUtils.isEmpty(businessKeys)) {
                    list = traceSupplierMapper.selectBatchForApproval(page, request, businessKeys);
                    approvalList = handleApprovalListResponse(approvalList, list, ApprovalStatusEnum.CANCELED);
                }
                break;
            //全部
            //区分管理员和普通用户
            //普通用户获取自己发起的(审批中、已通过、未通过、已取消)，管理员获取全部(审批中、已通过、未通过、已取消)
            case ApprovalStatusEnum.ALL:
                List<AllApproveDTO> AllApproveList = baseApprovalService.getAllList(request.getFormId());
                if (!CollectionUtils.isEmpty(AllApproveList)) {
                    businessKeys = AllApproveList.stream().map(AllApproveDTO::getBusinessKey).collect(Collectors.toList());
                }
                if (!CollectionUtils.isEmpty(businessKeys)) {
                    list = traceSupplierMapper.selectBatchForApproval(page, request, businessKeys);
                    approvalList = handleAllApprovalListResponse(approvalList, list, AllApproveList);
                }
                break;
        }
        return approvalList;
    }

    private List<TraceSupplierApprovalListResponse> handleAllApprovalListResponse(List<TraceSupplierApprovalListResponse> approvalList, List<MeterTraceSupplier> list, List<AllApproveDTO> allApproveList) {
        Map<String, String> taskMap = new HashMap<>();
        approvalList = ConvertUtils.sourceToTarget(list, TraceSupplierApprovalListResponse.class);
        allApproveList.forEach(allApprove -> {
            taskMap.put(allApprove.getBusinessKey(), allApprove.getStatus());
        });
        //状态补全
        approvalList.forEach(approval -> {
            approval.setApprovalStatusName(dictService.getDictNameByCode(MeterDictEnum.APPROVAL_STATUS, taskMap.get(String.valueOf(approval.getId()))));
            approval.setApprovalStatus(taskMap.get(String.valueOf(approval.getId())));
        });
        //排序
        return approvalList.stream().sorted(Comparator.comparing(TraceSupplierApprovalListResponse::getCreateTime).reversed()).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public ReturnDTO updateTraceSupplier(MeterTraceSupplier traceSupplier) {
//        int updateFlag = traceSupplierMapper.updateById(traceSupplier);
//        boolean saveOrUpdateFlag = traceSupplierPersonService.saveOrUpdateBatch(traceSupplier.getTraceSupplierPersonList());
//        if (updateFlag > 0 && saveOrUpdateFlag) {
//            return ReturnUtil.success();
//        }
//        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
        return null;
    }

    @Override
    public ReturnDTO deleteTraceSupplier(Long id) {
        if (traceSupplierMapper.deleteById(id) > 0) {
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public ReturnDTO deleteBatchTraceSupplier(List<Long> ids) {
        if (traceSupplierMapper.deleteBatchIds(ids) > 0) {
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public ReturnDTO<TraceSupplierDetailResponse> traceSupplierDetail(Long id) {
        TraceSupplierDetailResponse detailResponse = traceSupplierMapper.selectTraceSupplierById(id);
        //todo:待合同模块支出合同完成后在支出合同中增加根据溯源供方id查合同列表接口
        return ReturnUtil.success(detailResponse);
    }


    private QueryWrapper<MeterTraceSupplier> getWrapper(TraceSupplierListRequest request) {
        //flowable中已通过状态的业务id列表
        List<String> passedList = baseApprovalService.getPassedList(request.getFormId());

        QueryWrapper<MeterTraceSupplier> wrapper = new QueryWrapper<>();
        //无审批通过则返回空数据
        if (CollectionUtils.isEmpty(passedList)) {
            //保证批量导入的可以查询到
            passedList.add("xxx");
        }
        wrapper.like(StringUtils.isNotBlank(request.getSupplierNo()), "supplier_no", request.getSupplierNo());
        wrapper.like(StringUtils.isNotBlank(request.getSupplierName()), "supplier_name", request.getSupplierName());
        wrapper.like(StringUtils.isNotBlank(request.getBusinessContent()), "business_content", request.getBusinessContent());
        wrapper.and(QueryWrapper -> QueryWrapper.in("id", passedList).or().isNull("approval_status"));
        wrapper.eq("is_del", 0);
        wrapper.orderByDesc("create_time");
        return wrapper;
    }

    private List<TraceSupplierApprovalListResponse> handleApprovalListResponse(List<TraceSupplierApprovalListResponse> approvalList, List<MeterTraceSupplier> list, String status) {
        approvalList = ConvertUtils.sourceToTarget(list, TraceSupplierApprovalListResponse.class);
        approvalList.stream().forEach(result -> {
            //审批状态两种获取方式：1、在此处设置，2、在flowable中设置业务状态，暂采取1
            result.setApprovalStatusName(dictService.getDictNameByCode(MeterDictEnum.APPROVAL_STATUS, status));
        });
        return approvalList;
    }
}
