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.mes.controller.admin.changerecord.vo.ChangeTypeEnum;
import cn.iocoder.yudao.module.mes.controller.admin.producereport.vo.*;
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.ProduceReportDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.producereport.ProduceReportDetailDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.producereport.ViewReportUserDateSummary;
import cn.iocoder.yudao.module.mes.dal.mysql.producereport.ProduceReportDetailMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.producereport.ProduceReportMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.producereport.ViewReportUserDateMapper;
import cn.iocoder.yudao.module.mes.dal.redis.no.MesNoRedisDAO;
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.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.apache.commons.lang3.StringUtils;
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.util.Collections;
import java.util.List;
import java.util.Map;

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.PRODUCE_REPORT_NOT_EXISTS;

/**
 * 生产报工单 Service 实现类
 *
 * @author 内蒙必硕
 */
@Service
@Validated
public class ProduceReportServiceImpl implements ProduceReportService {

    @Resource
    private ProduceReportMapper produceReportMapper;
    @Resource
    private ProduceReportDetailMapper produceReportDetailMapper;
    @Resource
    private OrganizationService organizationService;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private ProduceReportChangeRecordService produceReportChangeRecordService;
    @Resource
    private ProduceReportDetailService produceReportDetailService;
    @Resource
    private PlanService planService;
    @Resource
    private MesNoRedisDAO noRedisDAO;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createProduceReport(ProduceReportSaveReqVO createReqVO) {
        createReqVO.setReportStatus(ReportStatusEnum.草稿.getValue());
        // 插入
        ProduceReportDO produceReport = BeanUtils.toBean(createReqVO, ProduceReportDO.class);
        if (StringUtils.isEmpty(createReqVO.getReportCode())) {
            // 1.4 生成订单号，并校验唯一性
            String no = noRedisDAO.generate3(MesNoRedisDAO.REPORT_NO_PREFIX);
            produceReport.setReportCode(no);
        }
        produceReportMapper.insert(produceReport);

        // 插入子表
        if( createReqVO.getProduceReportDetails()!=null&& createReqVO.getProduceReportDetails().size()>0){
            createProduceReportDetailList( produceReport, createReqVO.getProduceReportDetails());
        }
        // 返回
        return produceReport.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProduceReport(ProduceReportSaveReqVO updateReqVO) {
        // 校验存在
        validateProduceReportExists(updateReqVO.getId());
        // 更新
        ProduceReportDO updateObj = BeanUtils.toBean(updateReqVO, ProduceReportDO.class);
        ProduceReportDO oldObj = produceReportMapper.selectById(updateObj.getId());
        oldObj.setTotalTime(updateReqVO.getTotalTime());
        oldObj.setReportTime(updateReqVO.getReportTime());
        oldObj.setRemark(updateReqVO.getRemark());
        //如果当前是驳回状态，再编辑的话就改为草稿状态重新提交
        if(updateObj.getReportStatus().equals(ReportStatusEnum.驳回.getValue())){
            oldObj.setReportStatus(ReportStatusEnum.草稿.getValue());
        }
        produceReportMapper.updateById(oldObj);

        // 更新子表
        updateProduceReportDetailList(updateObj, updateReqVO.getProduceReportDetails());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteProduceReport(Long id) {
        // 校验存在
        validateProduceReportExists(id);
        // 删除
        produceReportMapper.deleteById(id);

        // 删除子表
        deleteProduceReportDetailByReportId(id);
    }

    private void validateProduceReportExists(Long id) {
        if (produceReportMapper.selectById(id) == null) {
            throw exception(PRODUCE_REPORT_NOT_EXISTS);
        }
    }

    @Override
    public ProduceReportDO getProduceReport(Long id) {
        return produceReportMapper.selectById(id);
    }

    @Override
    public PageResult<ProduceReportDO> getProduceReportPage(ProduceReportPageReqVO pageReqVO) {
        return produceReportMapper.selectPage(pageReqVO);
    }

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

        return BeanUtils.toBean(list, ProduceReportRespVO.class, item -> {
            MapUtils.findAndThen(map, item.getOrgId(),
                    org -> item.setOrgName(org.getName())
            );
            MapUtils.findAndThen(userMap, item.getUserId(),
                    user -> item.setUserName(user.getNickname()));
        });
    }
    // ==================== 子表（生产报工明细） ====================

    @Override
    public List<ProduceReportDetailDO> getProduceReportDetailListByReportId(Long reportId) {
        return produceReportDetailMapper.selectListByReportId(reportId);
    }
    @Override
    public List<ProduceReportDetailRespVO> getDetailListByReportId(Long reportId) {
        List<ProduceReportDetailDO> list =  produceReportDetailMapper.selectListByReportId(reportId);
        return produceReportDetailService.buildVOList(list);
    }
    private void createProduceReportDetailList(ProduceReportDO reportDO, List<ProduceReportDetailDO> list) {
        Map<Long, PlanDO> map = planService.getPlanMap(convertSet(list, ProduceReportDetailDO::getPlanId));

        list.forEach(o -> o.setId(null).setReportId(reportDO.getId()).setReportStatus(reportDO.getReportStatus())
                .setReportDate(reportDO.getReportDate()).setGroupType(reportDO.getGroupType())
                .setOrgId(reportDO.getOrgId()).setOrgType(reportDO.getOrgType())
                .setUserId(reportDO.getUserId()).setReportType(reportDO.getReportType())
                .setProductId(map.get(o.getPlanId()).getProductId())
                .setQualityNumber(o.getQualityNumber()==null?BigDecimal.ZERO: o.getQualityNumber())
                .setPackageNumber(o.getPackageNumber()==null?BigDecimal.ZERO: o.getPackageNumber())
                .setWasteNumber(o.getWasteNumber()==null?BigDecimal.ZERO: o.getWasteNumber())
                .setTotalNumber(o.getQualityNumber().add(o.getWasteNumber()))
        );
        produceReportDetailMapper.insertBatch(list);
    }

    private void updateProduceReportDetailList(ProduceReportDO reportDO, List<ProduceReportDetailDO> list) {
        deleteProduceReportDetailByReportId(reportDO.getId());
        if(list==null ||list.size()==0)return;
//		list.forEach(o -> o.setId(null)
//                .setUpdater(null).setUpdateTime(null)
//        ); // 解决更新情况下：1）id 冲突；2）updateTime 不更新
        createProduceReportDetailList(reportDO, list);
    }

    private void deleteProduceReportDetailByReportId(Long reportId) {
        produceReportDetailMapper.deleteByReportId(reportId);
    }

    @Override
    @Transactional
    public void updateStatus(Long id, Integer status) {
        ProduceReportDO reportDO = getProduceReport(id);
        reportDO.setReportStatus(status);
        produceReportMapper.updateById(reportDO);
        if(status.equals(ReportStatusEnum.送审.getValue())){
            produceReportChangeRecordService.saveChange(id,"", "", ChangeTypeEnum.提交.getValue());
        }
        else if(status.equals(ReportStatusEnum.通过.getValue())) {
            produceReportChangeRecordService.saveChange(id, "", "", ChangeTypeEnum.审核.getValue());
            List<ProduceReportDetailDO> list = getProduceReportDetailListByReportId(id);
            for (ProduceReportDetailDO detail: list) {
                //明细固定分配单个计划
                produceReportDetailService.updateStatus3(detail,status);
            }
        }
    }

    @Override
    public List<ProduceReportDO> getList(ProduceReportPageReqVO pageReqVO){
        return produceReportMapper.selectBy(pageReqVO);
    }

    @Resource
    private ViewReportUserDateMapper viewReportUserDateMapper;
    @Override
    public ViewReportUserDateSummary selectSumBy(Long userId, String[] reportDays) {
        List<ViewReportUserDateSummary> list = viewReportUserDateMapper.selectBy(userId,null,reportDays);

        BigDecimal sumNumber = list.stream()
                .map(ViewReportUserDateSummary::getSumNumber).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal quality = list.stream()
                .map(ViewReportUserDateSummary::getTotalQualityNumber).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal waste = list.stream()
                .map(ViewReportUserDateSummary::getTotalWasteNumber).reduce(BigDecimal.ZERO, BigDecimal::add);
        ViewReportUserDateSummary summary = new ViewReportUserDateSummary().setUserId(userId)
                .setSumNumber(sumNumber).setTotalQualityNumber(quality).setTotalWasteNumber(waste);

        return  summary;
    }

    @Override
    public List<ViewReportUserDateSummary> selectBy(Long userId, String reportDay, String[] reportDays) {
        return viewReportUserDateMapper.selectBy(userId,reportDay,reportDays);
    }
}