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

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.mes.controller.admin.machine.vo.MachineComponentListReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.machine.vo.MachineComponentSaveReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.machine.vo.MachineTypeEnum;
import cn.iocoder.yudao.module.mes.dal.dataobject.machine.MachineComponentDO;
import cn.iocoder.yudao.module.mes.dal.mysql.machine.MachineComponentMapper;
import cn.iocoder.yudao.module.mes.dal.redis.no.MesNoRedisDAO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PURCHASE_ORDER_NO_EXISTS;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;

/**
 * 机台 Service 实现类
 *
 * @author 内蒙必硕
 */
@Service
@Validated
public class MachineComponentServiceImpl implements MachineComponentService {

    @Resource
    private MachineComponentMapper machineComponentMapper;
    @Resource
    private MesNoRedisDAO noRedisDAO;
    @Override
    public Long createMachineComponent(MachineComponentSaveReqVO createReqVO) {
        // 校验父id的有效性
        validateParentMachineComponent(null, createReqVO.getParentId());
        // 校验装备名称的唯一性
        validateMachineComponentNameUnique(null, createReqVO.getParentId(), createReqVO.getName());

        // 插入
        MachineComponentDO machineComponent = BeanUtils.toBean(createReqVO, MachineComponentDO.class);
        if (StringUtils.isEmpty(machineComponent.getCode())) {
            // 1.4 编码，并校验唯一性
            String no = null;
            if(machineComponent.getComponentType().equals(MachineTypeEnum.机台.getValue()))
                no = noRedisDAO.generate2(MesNoRedisDAO.ORG_MACHINE);
            if(machineComponent.getComponentType().equals(MachineTypeEnum.关键件.getValue()))
                no = noRedisDAO.generate2(MesNoRedisDAO.ORG_COMPONENT);
            if(StringUtils.isNotEmpty(no)){
                if (machineComponentMapper.selectByNo(no) != null) {
                    throw exception(PURCHASE_ORDER_NO_EXISTS);
                }
                machineComponent.setCode(no);
            }
        }
        machineComponentMapper.insert(machineComponent);
        // 返回
        return machineComponent.getId();
    }

    @Override
    public void updateMachineComponent(MachineComponentSaveReqVO updateReqVO) {
        // 校验存在
        validateMachineComponentExists(updateReqVO.getId());
        // 校验父id的有效性
        validateParentMachineComponent(updateReqVO.getId(), updateReqVO.getParentId());
        // 校验装备名称的唯一性
        validateMachineComponentNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());

        // 更新
        MachineComponentDO updateObj = BeanUtils.toBean(updateReqVO, MachineComponentDO.class);
        machineComponentMapper.updateById(updateObj);
    }

    @Override
    public void deleteMachineComponent(Long id) {
        // 校验存在
        validateMachineComponentExists(id);
        // 校验是否有子机台
        if (machineComponentMapper.selectCountByParentId(id) > 0) {
            throw exception(MACHINE_COMPONENT_EXITS_CHILDREN);
        }
        // 删除
        machineComponentMapper.deleteById(id);
    }

    private void validateMachineComponentExists(Long id) {
        if (machineComponentMapper.selectById(id) == null) {
            throw exception(MACHINE_COMPONENT_NOT_EXISTS);
        }
    }

    private void validateParentMachineComponent(Long id, Long parentId) {
        if (parentId == null || MachineComponentDO.PARENT_ID_ROOT.equals(parentId)) {
            return;
        }
        // 1. 不能设置自己为父机台
        if (Objects.equals(id, parentId)) {
            throw exception(MACHINE_COMPONENT_PARENT_ERROR);
        }
        // 2. 父机台不存在
        MachineComponentDO parentMachineComponent = machineComponentMapper.selectById(parentId);
        if (parentMachineComponent == null) {
            throw exception(MACHINE_COMPONENT_PARENT_NOT_EXITS);
        }
        // 3. 递归校验父机台，如果父机台是自己的子机台，则报错，避免形成环路
        if (id == null) { // id 为空，说明新增，不需要考虑环路
            return;
        }
        for (int i = 0; i < Short.MAX_VALUE; i++) {
            // 3.1 校验环路
            parentId = parentMachineComponent.getParentId();
            if (Objects.equals(id, parentId)) {
                throw exception(MACHINE_COMPONENT_PARENT_IS_CHILD);
            }
            // 3.2 继续递归下一级父机台
            if (parentId == null || MachineComponentDO.PARENT_ID_ROOT.equals(parentId)) {
                break;
            }
            parentMachineComponent = machineComponentMapper.selectById(parentId);
            if (parentMachineComponent == null) {
                break;
            }
        }
    }

    private void validateMachineComponentNameUnique(Long id, Long parentId, String name) {
        MachineComponentDO machineComponent = machineComponentMapper.selectByParentIdAndName(parentId, name);
        if (machineComponent == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的机台
        if (id == null) {
            throw exception(MACHINE_COMPONENT_NAME_DUPLICATE);
        }
        if (!Objects.equals(machineComponent.getId(), id)) {
            throw exception(MACHINE_COMPONENT_NAME_DUPLICATE);
        }
    }

    @Override
    public MachineComponentDO getMachineComponent(Long id) {
        return machineComponentMapper.selectById(id);
    }

    @Override
    public List<MachineComponentDO> getMachineComponentList(MachineComponentListReqVO listReqVO) {
        return machineComponentMapper.selectList(listReqVO);
    }
    @Override
    public List<MachineComponentDO> getList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return machineComponentMapper.selectBatchIds(ids);
    }
}