package cn.iocoder.yudao.module.mes.service.producereport;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.mes.controller.admin.changerecord.vo.ChangeTypeEnum;
import cn.iocoder.yudao.module.mes.controller.admin.plan.vo.PlanStatusEnum;
import cn.iocoder.yudao.module.mes.controller.admin.producereport.vo.*;
import cn.iocoder.yudao.module.mes.controller.admin.producereportplan.vo.WorkReportPlanSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.organization.OrganizationDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.plan.PlanDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.producereport.ProduceReportDetailDO;
import cn.iocoder.yudao.module.mes.dal.mysql.producereport.ProduceReportDetailMapper;
import cn.iocoder.yudao.module.mes.service.changerecord.ProduceReportChangeRecordService;
import cn.iocoder.yudao.module.mes.service.organization.OrganizationService;
import cn.iocoder.yudao.module.mes.service.plan.PlanService;
import cn.iocoder.yudao.module.mes.service.workreportplan.WorkReportPlanService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.*;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PLAN_NOT_EXISTS;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRODUCE_REPORT_DETAIL_NOT_EXISTS;

/**
 * 生产报工明细 Service 实现类
 *
 * @author 内蒙必硕
 */
@Service
@Validated
public class ProduceReportDetailServiceImpl implements ProduceReportDetailService {

    @Resource
    private ProduceReportDetailMapper produceReportDetailMapper;
    @Resource
    private ProduceReportChangeRecordService produceReportChangeRecordService;

    @Override
    @Transactional
    public Long createProduceReportDetail(ProduceReportDetailSaveReqVO createReqVO) {
        createReqVO.setReportStatus(ReportStatusEnum.草稿.getValue());
        // 插入
        ProduceReportDetailDO produceReportDetail = BeanUtils.toBean(createReqVO, ProduceReportDetailDO.class);
        produceReportDetailMapper.insert(produceReportDetail);
        produceReportChangeRecordService.saveChange(produceReportDetail.getId(),"", produceReportDetail.toString()
        , ChangeTypeEnum.创建.getValue());
        // 返回
        return produceReportDetail.getId();
    }

    @Override
    public void updateProduceReportDetail(ProduceReportDetailSaveReqVO updateReqVO) {
        // 校验存在
        validateProduceReportDetailExists(updateReqVO.getId());
        // 更新
        //ProduceReportDetailDO updateObj = BeanUtils.toBean(updateReqVO, ProduceReportDetailDO.class);
        ProduceReportDetailDO updateObj = produceReportDetailMapper.selectById(updateReqVO.getId());
        String before = updateObj.toString();
        updateObj.setProductId(updateReqVO.getProductId());
        updateObj.setQualityNumber(updateReqVO.getQualityNumber());
        updateObj.setQualityRate(updateReqVO.getQualityRate());
        updateObj.setWasteNumber(updateReqVO.getWasteNumber());
        updateObj.setWasteReason(updateReqVO.getWasteReason());
        updateObj.setTotalNumber(updateReqVO.getTotalNumber());
        updateObj.setRemark(updateReqVO.getRemark());
        updateObj.setReportTime(updateReqVO.getReportTime());
        updateObj.setTotalTime(updateReqVO.getTotalTime());
        produceReportChangeRecordService.saveChange(updateObj.getId(),before, updateObj.toString()
                , ChangeTypeEnum.编辑.getValue());
        produceReportDetailMapper.updateById(updateObj);
    }

    @Override
    public void deleteProduceReportDetail(Long id) {
        // 校验存在
        //validateProduceReportDetailExists(id);
        ProduceReportDetailDO detailDO = produceReportDetailMapper.selectById(id);
        if ( detailDO== null) {
            throw exception(PRODUCE_REPORT_DETAIL_NOT_EXISTS);
        }
        produceReportChangeRecordService.saveChange(id,detailDO.toString(), ""
                , ChangeTypeEnum.删除.getValue());
        // 删除
        produceReportDetailMapper.deleteById(id);
    }

    private void validateProduceReportDetailExists(Long id) {
        if (produceReportDetailMapper.selectById(id) == null) {
            throw exception(PRODUCE_REPORT_DETAIL_NOT_EXISTS);
        }
    }

    @Override
    public ProduceReportDetailDO getProduceReportDetail(Long id) {
        return produceReportDetailMapper.selectById(id);
    }

    @Override
    public PageResult<ProduceReportDetailRespVO> getProduceReportDetailPage(ProduceReportDetailPageReqVO pageReqVO) {
        PageResult<ProduceReportDetailDO> pageResult =  produceReportDetailMapper.selectPage(pageReqVO);
        return new PageResult<>(buildVOList(pageResult.getList()), pageResult.getTotal());
    }
    @Override
    public PageResult<ProduceReportDetailRespVO> getCenterPage(ProduceReportDetailPageReqVO pageReqVO) {

        PageResult<ProduceReportDetailDO> pageResult =  produceReportDetailMapper.selectPage(pageReqVO);
        return new PageResult<>(buildVOList(pageResult.getList()), pageResult.getTotal());
    }
    @Resource
    private OrganizationService organizationService;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private ErpProductService productService;
    @Resource
    private PlanService planService;
    @Resource
    private WorkReportPlanService workReportPlanService;

    @Override
    public  List<ProduceReportDetailRespVO> buildVOList(List<ProduceReportDetailDO> list){
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        Map<Long, OrganizationDO> map = organizationService.getMap(
                convertSet(list, ProduceReportDetailDO::getOrgId));
        // 1.4 管理员信息
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                convertSet(list, ProduceReportDetailDO::getUserId));
        Map<Long, ErpProductDO> productMap = productService.getProductMap(
                convertSet(list, ProduceReportDetailDO::getProductId));

        return BeanUtils.toBean(list, ProduceReportDetailRespVO.class, item -> {
            MapUtils.findAndThen(map, item.getOrgId(),
                    org -> item.setOrgName(org.getName())
            );
            MapUtils.findAndThen(userMap, item.getUserId(),
                    user -> item.setUserName(user.getNickname()));

            MapUtils.findAndThen(productMap, item.getProductId(),
                    pro -> item.setProductName(pro.getName()));
        });
    }

    /**更改报工单状态***/

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(Long id, Integer status) {
        ProduceReportDetailDO reportDetailDO = produceReportDetailMapper.selectById(id);
        reportDetailDO.setReportStatus(status);
        String before = reportDetailDO.toString();
        produceReportDetailMapper.updateById(reportDetailDO);
        if(status.equals(ReportStatusEnum.送审.getValue())){
            produceReportChangeRecordService.saveChange(reportDetailDO.getId(),before, reportDetailDO.toString()
                    , ChangeTypeEnum.提交.getValue());
        }

        if(status.equals(ReportStatusEnum.通过.getValue())){
            produceReportChangeRecordService.saveChange(reportDetailDO.getId(),before, reportDetailDO.toString()
                    , ChangeTypeEnum.审核.getValue());
            //分配给开工中的计划
            List<Integer> statusList = new ArrayList<>();
            statusList.add(PlanStatusEnum.量产.getValue());
            List<PlanDO> planList = planService.getPlanByStatusAndProduct(statusList,reportDetailDO.getProductId());
            if(planList!=null && planList.size()>0){
                //该种产品只有一个计划在开工
                if(planList.size()==1){
                    WorkReportPlanSaveReqVO saveReqVO = new WorkReportPlanSaveReqVO()
                            .setReportId(id).setPlanId(planList.get(0).getId())
                            .setTaskDetailId(planList.get(0).getTaskDetailId())
                            .setProductId(reportDetailDO.getProductId())
                            .setQualityNumberPlan(reportDetailDO.getQualityNumber())
                            .setWasteNumberPlan(reportDetailDO.getWasteNumber());
                    workReportPlanService.createWorkReportPlan(saveReqVO);
                }
                else{
                    MathContext mc = new MathContext(0, RoundingMode.HALF_UP);
                    long totalNeed = 0;
                    Map<Long, Long> planNeedMap = new HashMap<>();
                    Map<Long, PlanDO> planMap = new HashMap<>();
                    for (PlanDO plan : planList) {
                        BigDecimal finishNumber = workReportPlanService.selectSumBy(plan.getId(),reportDetailDO.getOrgType());
                        long planNeed = plan.getPlanNumber() > finishNumber.longValue() ? plan.getPlanNumber() - finishNumber.longValue(): 0;
                        totalNeed += planNeed;
                        planNeedMap.put(plan.getId(), planNeed);
                        planMap.put(plan.getId(),plan);
                    }
                    //根据计划各自的需求比例分配给计划
                    for (Long planId : planNeedMap.keySet()) {
                        Long planNeed = planNeedMap.get(planId);
                        if(planNeed>0){
                            BigDecimal planNumber = reportDetailDO.getQualityNumber().multiply(BigDecimal.valueOf(planNeed/totalNeed),mc);
                            BigDecimal wasteNumber = reportDetailDO.getWasteNumber().multiply(BigDecimal.valueOf(planNeed/totalNeed),mc);

                            WorkReportPlanSaveReqVO saveReqVO = new WorkReportPlanSaveReqVO()
                                    .setReportId(id).setPlanId(planId)
                                    .setTaskDetailId(planMap.get(planId).getTaskDetailId())
                                    .setProductId(reportDetailDO.getProductId())
                                    .setQualityNumberPlan(planNumber)
                                    .setWasteNumberPlan(wasteNumber);
                            workReportPlanService.createWorkReportPlan(saveReqVO);
                        }
                    }
                }
            }
            else throw exception(PLAN_NOT_EXISTS);
        }
    }

    //通过报工单
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus2( ProduceReportDetailDO reportDetailDO, Integer status) {
        reportDetailDO.setReportStatus(status);
        produceReportDetailMapper.updateById(reportDetailDO);
        //分配给开工中的计划
        List<Integer> statusList = new ArrayList<>();
        statusList.add(PlanStatusEnum.量产.getValue());
        List<PlanDO> planList = planService.getPlanByStatusAndProduct(statusList,reportDetailDO.getProductId());
        if(planList!=null && planList.size()>0){
            //该种产品只有一个计划在开工
            if(planList.size()==1){
                WorkReportPlanSaveReqVO saveReqVO = new WorkReportPlanSaveReqVO()
                        .setReportId(reportDetailDO.getId()).setPlanId(planList.get(0).getId())
                        .setTaskDetailId(planList.get(0).getTaskDetailId())
                        .setProductId(reportDetailDO.getProductId())
                        .setQualityNumberPlan(reportDetailDO.getQualityNumber())
                        .setWasteNumberPlan(reportDetailDO.getWasteNumber());
                workReportPlanService.createWorkReportPlan(saveReqVO);
            }
            else{
                MathContext mc = new MathContext(0, RoundingMode.HALF_UP);
                long totalNeed = 0;
                Map<Long, Long> planNeedMap = new HashMap<>();
                Map<Long, PlanDO> planMap = new HashMap<>();
                for (PlanDO plan : planList) {
                    BigDecimal finishNumber = workReportPlanService.selectSumBy(plan.getId(),reportDetailDO.getOrgType());
                    long planNeed = plan.getPlanNumber() > finishNumber.longValue() ? plan.getPlanNumber() - finishNumber.longValue(): 0;
                    totalNeed += planNeed;
                    planNeedMap.put(plan.getId(), planNeed);
                    planMap.put(plan.getId(),plan);
                }
                //根据计划各自的需求比例分配给计划
                for (Long planId : planNeedMap.keySet()) {
                    Long planNeed = planNeedMap.get(planId);
                    if(planNeed>0){
                        BigDecimal planNumber = reportDetailDO.getQualityNumber().multiply(BigDecimal.valueOf(planNeed/totalNeed),mc);
                        BigDecimal wasteNumber = reportDetailDO.getWasteNumber().multiply(BigDecimal.valueOf(planNeed/totalNeed),mc);

                        WorkReportPlanSaveReqVO saveReqVO = new WorkReportPlanSaveReqVO()
                                .setReportId(reportDetailDO.getId()).setPlanId(planId)
                                .setTaskDetailId(planMap.get(planId).getTaskDetailId())
                                .setProductId(reportDetailDO.getProductId())
                                .setQualityNumberPlan(planNumber)
                                .setWasteNumberPlan(wasteNumber);
                        workReportPlanService.createWorkReportPlan(saveReqVO);
                    }
                }
            }
        }
        else throw exception(PLAN_NOT_EXISTS);
    }

    @Override
    public Long sumByPlanAndOrgType(Long planId,String orgType){
        return produceReportDetailMapper.sumByPlanAndOrgType(planId, orgType);
    }


    //报工明细固定对应分配计划
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus3( ProduceReportDetailDO reportDetailDO, Integer status) {
        reportDetailDO.setReportStatus(status);
        produceReportDetailMapper.updateById(reportDetailDO);
        PlanDO planDO = planService.getPlan(reportDetailDO.getPlanId());
        //分配给开工中的计划
        WorkReportPlanSaveReqVO saveReqVO = new WorkReportPlanSaveReqVO()
                .setReportId(reportDetailDO.getId()).setPlanId(reportDetailDO.getPlanId())
                .setTaskDetailId(planDO.getTaskDetailId())
                .setProductId(reportDetailDO.getProductId())
                .setQualityNumberPlan(reportDetailDO.getQualityNumber())
                .setWasteNumberPlan(reportDetailDO.getWasteNumber());
        workReportPlanService.createWorkReportPlan(saveReqVO);
    }
}