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

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
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.controller.admin.autocode.util.AutoCodeUtil;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService;
import cn.iocoder.yudao.module.mes.controller.admin.plan.vo.PlanStatusEnum;
import cn.iocoder.yudao.module.mes.controller.admin.task.vo.TaskDetailRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.task.vo.TaskPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.task.vo.TaskSaveReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.task.vo.TaskStatusEnum;
import cn.iocoder.yudao.module.mes.dal.dataobject.plan.PlanDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.task.TaskDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.task.TaskDetailDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.task.ViewTaskProductSummary;
import cn.iocoder.yudao.module.mes.dal.mysql.plan.PlanMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.task.TaskDetailMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.task.TaskMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.task.ViewTaskProductSummaryMapper;
import cn.iocoder.yudao.module.mes.dal.redis.no.MesNoRedisDAO;
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.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.*;

/**
 * 生产任务单 Service 实现类
 *
 * @author 内蒙必硕
 */
@Service
@Validated
public class TaskServiceImpl implements TaskService {

    @Resource
    private TaskMapper taskMapper;
    @Resource
    private TaskDetailMapper taskDetailMapper;
    @Resource
    private MesNoRedisDAO noRedisDAO;

    @Resource
    private AutoCodeUtil autoCodeUtil;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createTask(TaskSaveReqVO createReqVO) {
        // 插入
        TaskDO task = BeanUtils.toBean(createReqVO, TaskDO.class);
        if (StringUtils.isEmpty(task.getCode())) {
            // 1.4 生成订单号，并校验唯一性

//            String no = noRedisDAO.generate2(MesNoRedisDAO.TASK_NO_PREFIX);
//            if (taskMapper.selectByNo(no) != null) {
//                throw exception(PURCHASE_ORDER_NO_EXISTS);
//            }
//            task.setCode(no);
            task.setCode(autoCodeUtil.genSerialCode("TASK_CODE",null));
        } else {
            if (taskMapper.selectByNo(task.getCode()) != null) {
                throw exception(TASK_CODE_EXISTS);
            }
        }
        createReqVO.setStatus(TaskStatusEnum.草稿.getValue());
        taskMapper.insert(task);

        // 插入子表
        if(createReqVO.getTaskDetails()!=null && createReqVO.getTaskDetails().size()>0)
            createTaskDetailList(task.getId(), createReqVO.getTaskDetails());
        // 返回
        return task.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTask(TaskSaveReqVO updateReqVO) {
        // 校验存在
        validateTaskExists(updateReqVO.getId());
        // 更新
        TaskDO updateObj = BeanUtils.toBean(updateReqVO, TaskDO.class);
        taskMapper.updateById(updateObj);

        // 更新子表
        if(updateReqVO.getTaskDetails()!=null && updateReqVO.getTaskDetails().size()>0)
            updateTaskDetailList(updateReqVO.getId(), updateReqVO.getTaskDetails());
    }
    @Override
    public int updateTask(TaskDO taskDO){
       return  taskMapper.updateById(taskDO);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTask(Long id) {
        // 校验存在
        validateTaskExists(id);
        // 删除
        taskMapper.deleteById(id);

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

    private void validateTaskExists(Long id) {
        if (taskMapper.selectById(id) == null) {
            throw exception(TASK_NOT_EXISTS);
        }
    }

    @Override
    public List<TaskDO> getTaskList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return taskMapper.selectBatchIds(ids);
    }

    @Override
    public TaskDO getTask(Long id) {
        return taskMapper.selectById(id);
    }

    @Override
    public PageResult<TaskDO> getTaskPage(TaskPageReqVO pageReqVO) {
        return taskMapper.selectPage(pageReqVO);
    }

    @Override
    public PageResult<TaskDO> getTaskPage2(TaskPageReqVO pageReqVO) {
        return taskMapper.selectPage2(pageReqVO);
    }

    // ==================== 子表（生产任务单明细） ====================
    @Override
    public List<TaskDO> selectList(List<Integer> status) {
        return taskMapper.selectList(status);
    }

    @Override
    public List<TaskDetailDO> getTaskDetailListByTaskId(Long taskId) {
        return taskDetailMapper.selectListByTaskId(taskId);
    }

    private void createTaskDetailList(Long taskId, List<TaskDetailDO> list) {
        list.forEach(o -> o.setTaskId(taskId));
        taskDetailMapper.insertBatch(list);
    }

    private void updateTaskDetailList(Long taskId, List<TaskDetailDO> list) {
        deleteTaskDetailByTaskId(taskId);
        list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下：1）id 冲突；2）updateTime 不更新
        createTaskDetailList(taskId, list);
    }

    private void deleteTaskDetailByTaskId(Long taskId) {
        taskDetailMapper.deleteByTaskId(taskId);
    }

    // ==================== 子表（生产任务单明细） ====================
    @Resource
    private ErpProductService productService;
    @Resource
    private ErpProductUnitService productUnitService;
    @Resource
    private ViewTaskProductSummaryMapper summaryMapper;
    @Resource
    private PlanMapper planMapper;

    @Override
    public PageResult<TaskDetailRespVO> getTaskDetailPage(PageParam pageReqVO, Long taskId) {
        PageResult<TaskDetailDO> pageResult = taskDetailMapper.selectPage(pageReqVO, taskId);
        return new PageResult<>(buildDetailVOList(pageResult.getList()), pageResult.getTotal());
    }

    @Override
    public List<ViewTaskProductSummary> getTaskProductSummaryList(Long taskId) {
//        List<TaskDetailSumResult> resultList = taskDetailMapper.selectSumListByTaskId(taskId);
//        System.out.println(Arrays.toString(resultList.toArray()));
        List<ViewTaskProductSummary> summaryList = summaryMapper.selectListByTaskId(taskId);
//        for (ViewTaskProductSummary summary:summaryList) {
//            Long planTotalNumber = planMapper.selectSum(summary.getTaskId(),summary.getProductId(),null);
//            summary.setPlanNumber(planTotalNumber);
//        }
        return summaryList;
    }

    @Override
    public List<TaskDetailRespVO> buildDetailVOList(List<TaskDetailDO> list) {
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        Map<Long, ErpProductDO> map = productService.getProductMap(
                convertSet(list, TaskDetailDO::getProductId));
        Map<Long, ErpProductUnitDO> unitMap = productUnitService.getProductUnitMap(
                convertSet(list, TaskDetailDO::getUnitId));

        List<TaskDetailRespVO> resList =  BeanUtils.toBean(list, TaskDetailRespVO.class, item -> {
            MapUtils.findAndThen(map, item.getProductId(),
                    product -> item.setProductName(product.getName()).setBarCode(product.getBarCode()));
            MapUtils.findAndThen(unitMap, item.getUnitId(),
                    unit -> item.setUnitName(unit.getName()));
        });
        for (TaskDetailRespVO respVO : resList) {
            Long number = planMapper.selectSumTaskDetail(respVO.getId(),null);
            respVO.setPlanNumber(number);
        }

        return resList;
    }

    @Override
    public Long createTaskDetail(TaskDetailDO taskDetail) {
        taskDetailMapper.insert(taskDetail);
        return taskDetail.getId();
    }

    @Override
    public void updateTaskDetail(TaskDetailDO taskDetail) {
        // 校验存在
        validateTaskDetailExists(taskDetail.getId());
        // 更新
        taskDetailMapper.updateById(taskDetail);
    }

    @Override
    public void deleteTaskDetail(Long id) {
        // 校验存在
        validateTaskDetailExists(id);
        // 删除
        taskDetailMapper.deleteById(id);
    }

    @Override
    public TaskDetailDO getTaskDetail(Long id) {
        return taskDetailMapper.selectById(id);
    }

    private void validateTaskDetailExists(Long id) {
        if (taskDetailMapper.selectById(id) == null) {
            throw exception(TASK_DETAIL_NOT_EXISTS);
        }
    }


    @Override
    public Map<Long, List<PlanDO>> generatePlan(Long taskId, int sizeOfPlan, int productsOfPlan) {

        List<ViewTaskProductSummary> summaryList = summaryMapper.selectListByTaskId(taskId);
        Map<Long, List<PlanDO>> planMap = new HashMap<>();
        for (ViewTaskProductSummary summary : summaryList) {
            if(summary.getPlanNumber()==null)
                summary.setPlanNumber(0L);
            if(summary.getTotalNumber()==null)
                summary.setTotalNumber(0L);

            Long unplanNumber = summary.getTotalNumber() - summary.getPlanNumber();
            unplanNumber = unplanNumber > 0 ? unplanNumber : 0;
            List<PlanDO> planDOList = generatePlan2(taskId, summary.getProductId(), unplanNumber, productsOfPlan);
            planMap.put(summary.getProductId(), planDOList);
        }
        return planMap;
    }

    @Override
    public List<PlanDO> generatePlan2(Long taskId, Long productId, Long totalNumber, int productsOfPlan) {
        List<PlanDO> list = new ArrayList<>();
        for (; totalNumber > 0; ) {
            PlanDO planDO = new PlanDO().setTaskId(taskId).setProductId(productId).setFinishNumber(0L)
                    .setIsEnable(true).setStatus(PlanStatusEnum.计划.getValue());
            //剩下的不一定满productsOfPlan，
            if (totalNumber - productsOfPlan >= 0)
                planDO.setPlanNumber((long) productsOfPlan);
            else planDO.setPlanNumber((long) totalNumber);
            totalNumber = totalNumber - productsOfPlan;
            planDO.setCode(noRedisDAO.generate3(MesNoRedisDAO.PLAN_NO_PREFIX));
            planDO.setPriorityNum(1L);
            list.add(planDO);
        }
        return list;
    }
    //根据生产任务单明细生成排产计划
    @Override
    public List<PlanDO> generatePlan3(Long taskId,Long taskDetailId, Long productId, Long totalNumber, int productsOfPlan) {
        List<PlanDO> list = new ArrayList<>();
        for (; totalNumber > 0; ) {
            PlanDO planDO = new PlanDO().setTaskId(taskId).setTaskDetailId(taskDetailId).setProductId(productId).setFinishNumber(0L)
                    .setIsEnable(true).setStatus(PlanStatusEnum.计划.getValue());
            //剩下的不一定满productsOfPlan，
            if (totalNumber - productsOfPlan >= 0)
                planDO.setPlanNumber((long) productsOfPlan);
            else planDO.setPlanNumber((long) totalNumber);
            totalNumber = totalNumber - productsOfPlan;
            planDO.setCode(noRedisDAO.generate3(MesNoRedisDAO.PLAN_NO_PREFIX));
            planDO.setPriorityNum(1L);
            planDO.setReyaNumber(planDO.getPlanNumber());
            list.add(planDO);
        }
        return list;
    }
}