package com.cf.imes.module.executor.service.manage.remainplaten;

import com.cf.imes.framework.common.enums.DeletedCodeEnum;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.module.executor.controller.admin.manage.plate.vo.remain.RemainPlatePageReqVO;
import com.cf.imes.module.executor.controller.admin.manage.plate.vo.remain.RemainPlateSaveReqVO;
import com.cf.imes.module.executor.dal.dataobject.remainplaten.RemainPlateDO;
import com.cf.imes.module.executor.dal.mysql.remainplaten.RemainPlateMapper;
import com.cf.imes.module.executor.enums.manage.remainPlate.RemainPlateStatusEnum;
import com.cf.imes.module.executor.enums.manage.remainPlate.RemainPlateUseTypeEnum;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.REMAIN_PLATE_COUNT_MAX;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.REMAIN_PLATE_ID_NOT_EXISTS;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.REMAIN_PLATE_NOT_EXISTS;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.REMAIN_PLATE_STATUS_NO_USED;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.REMAIN_PLATE_STATUS_USED;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.REMAIN_PLATE_USR_TYPE;

/**
 * 生产单余料板表 order_remain_plate_{N} Service 实现类
 *
 * @author 晨丰科技
 */
@Service
@Validated
public class RemainPlateManageServiceImpl implements RemainPlateManageService {

    @Resource
    private RemainPlateMapper remainPlateMapper;

    private static final Integer MAX_NUM = 999; // 余料单次最大条数
    @Override
    public Boolean createRemainPlate(RemainPlateSaveReqVO createReqVO) {
        List<RemainPlateDO> remainPlates = new ArrayList<>();
        // 限制新增数量不能超过999
        if (createReqVO.getCount() > MAX_NUM) {
            throw exception(REMAIN_PLATE_COUNT_MAX);
        }
        // 插入
        if (createReqVO.getCount() >= 1) {
            for (int i = 0; i < createReqVO.getCount(); i++) {
                RemainPlateDO remainPlate = BeanUtils.toBean(createReqVO, RemainPlateDO.class).setCount(1).setOrganId(OrganContextHolder.getOrganId());
                remainPlates.add(remainPlate);
            }
        }
        // 批量增加
        return remainPlateMapper.insertBatch(remainPlates);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean createRemainPlateMultiple(Set<RemainPlateSaveReqVO> createReqVOS) {
        Collection<RemainPlateDO> remainPlates = new ArrayList<>();
        createReqVOS.forEach(createReqVO -> {
            // 判断该排单是否已经添加过余料
            if (remainPlateMapper.selectRemainPlatesByInitPlanId(createReqVO.getInitPlanId(), DeletedCodeEnum.NOT_DELETED.getStatus(), OrganContextHolder.getOrganId()).size() > 0) {
                // 删除余料
                remainPlateMapper.deleteRemainPlate(createReqVO.getInitPlanId(), OrganContextHolder.getOrganId());
            }
            RemainPlateDO remainPlate = BeanUtils.toBean(createReqVO, RemainPlateDO.class);
            remainPlates.add(remainPlate);
        });
        return remainPlateMapper.insertBatch(remainPlates);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRemainPlateStatus(Set<Long> ids, Integer status, Integer useType, Long planId) {
        // 余料存在判断
        validateRemainPlateExists(ids);
        if (useType != RemainPlateUseTypeEnum.TYPE_ONE.getStatus() && useType != RemainPlateUseTypeEnum.TYPE_ZERO.getStatus()) { //余料使用状态为2或3
            // 判断该排单是否存在以使用的余料
            if (remainPlateMapper.selectRemainPlatesByPlanId(planId, RemainPlateStatusEnum.USED.getStatus(),
                    DeletedCodeEnum.NOT_DELETED.getStatus(), OrganContextHolder.getOrganId()).size() > 0) {
                // 余料状态还原
                remainPlateMapper.updateRemainPlateStatusByPlanId(RemainPlateStatusEnum.UNUSED.getStatus(), RemainPlateUseTypeEnum.TYPE_ZERO.getStatus(),
                        OrganContextHolder.getOrganId(), planId);
            }
        }
        if (ids != null){
            //判断是否符合核销标准
            validateRemainPlateStatus(ids, RemainPlateStatusEnum.USED.getStatus());
            //以id为条件批量修改余料库中的状态
            remainPlateMapper.updateRemainPlateStatus(ids, status, useType, OrganContextHolder.getOrganId(), planId);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void revertRemainPlateStatus(Set<Long> ids, Integer status) {
        if (ids == null) {
            throw exception(REMAIN_PLATE_ID_NOT_EXISTS);
        }
        // 判断余料的状态是否存在使用中
        validateRemainPlateStatus(ids, RemainPlateStatusEnum.UNUSED.getStatus());
        // 判断使用类型是否为核销
        for (Long id : ids) {
            if (!validateRemainPlateUseType(id).equals(RemainPlateUseTypeEnum.TYPE_ONE.getStatus())) {
                throw exception(REMAIN_PLATE_USR_TYPE);
            }
        }
        remainPlateMapper.updateRemainPlateStatus(ids, status, null, OrganContextHolder.getOrganId(), 0L);
    }

    @Override
    public void updateRemainPlate(RemainPlateSaveReqVO updateReqVO) {
        // 校验存在
        validateRemainPlateExists(updateReqVO.getId());
        // 是否使用
        if (validateRemainPlateStatus(updateReqVO.getId()) == RemainPlateStatusEnum.USED.getStatus()) {
            throw exception(REMAIN_PLATE_STATUS_USED);
        }
        // 判断是否为开料添加
        RemainPlateDO updateObj = validateRemainPlateIsCutting(updateReqVO.getId());
        RemainPlateDO updateUpSaveVO = BeanUtils.toBean(updateReqVO, RemainPlateDO.class);
        updateObj.setWidth(updateUpSaveVO.getWidth()).setLength(updateUpSaveVO.getLength()).setThickness(updateUpSaveVO.getThickness())
                .setMaterial(updateUpSaveVO.getMaterial()).setColor(updateUpSaveVO.getColor()).setBrand(updateUpSaveVO.getBrand())
                .setRemark(updateUpSaveVO.getRemark()).setStore(updateUpSaveVO.getStore()).setTexture(updateUpSaveVO.getTexture())
                .setPlaceStyle(updateUpSaveVO.getPlaceStyle()).setOutLineJson(updateUpSaveVO.getOutLineJson());
        remainPlateMapper.updateById(updateUpSaveVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRemainPlate(Set<Long> ids) {
        if (ids == null) {
            throw exception(REMAIN_PLATE_ID_NOT_EXISTS);
        }
        // 余料存在判断
        validateRemainPlateExists(ids);
        // 判断余料的状态是否存在使用中
        validateRemainPlateStatus(ids, RemainPlateStatusEnum.USED.getStatus());
        // 删除
        remainPlateMapper.deleteBatchIds(ids);
    }

    // 判断余料板是否正在使用
    private void validateRemainPlateStatus(Set<Long> ids, Integer status) {
        for (Long id : ids) {
            if (validateRemainPlateStatus(id) == status) {
                if (status == RemainPlateStatusEnum.USED.getStatus())
                    throw exception(REMAIN_PLATE_STATUS_USED);
                if (status == RemainPlateStatusEnum.UNUSED.getStatus())
                    throw exception(REMAIN_PLATE_STATUS_NO_USED);
            }
        }
    }

    private void validateRemainPlateExists(Long id) {
        if (remainPlateMapper.selectById(id) == null) {
            throw exception(REMAIN_PLATE_NOT_EXISTS);
        }
    }
    private void validateRemainPlateExists(Set<Long> id) {
        if (remainPlateMapper.selectBatchIds(id).isEmpty()) {
            throw exception(REMAIN_PLATE_NOT_EXISTS);
        }
    }
    private RemainPlateDO validateRemainPlateIsCutting(Long id) {
        return remainPlateMapper.selectById(id);
    }

    private Integer validateRemainPlateStatus(Long id) {
        return remainPlateMapper.selectById(id).getStatus();
    }

    private Integer validateRemainPlateUseType(Long id) {
        return remainPlateMapper.selectById(id).getUseType();
    }

    @Override
    public RemainPlateDO getRemainPlate(Long id) {
        return remainPlateMapper.selectById(id);
    }

    @Override
    public PageResult<RemainPlateDO> getRemainPlatePage(RemainPlatePageReqVO pageReqVO) {
        return remainPlateMapper.selectPage(pageReqVO);
    }

    @Override
    public PageResult<RemainPlateDO> getRemainPlatePageToAdd(RemainPlatePageReqVO pageReqVO) {
        return remainPlateMapper.selectPageToAdd(pageReqVO.setStatus(RemainPlateStatusEnum.UNUSED.getStatus()));
    }

}