package com.njcn.rdms.module.project.service.status;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.module.project.controller.admin.status.vo.transition.ObjectStatusTransitionPageReqVO;
import com.njcn.rdms.module.project.controller.admin.status.vo.transition.ObjectStatusTransitionRespVO;
import com.njcn.rdms.module.project.controller.admin.status.vo.transition.ObjectStatusTransitionSaveReqVO;
import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusModelDO;
import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusTransitionDO;
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper;
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusTransitionMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;

/**
 * 对象状态流转 Service 实现。
 */
@Service
public class ObjectStatusTransitionServiceImpl implements ObjectStatusTransitionService {

    @Resource
    private ObjectStatusTransitionMapper objectStatusTransitionMapper;
    @Resource
    private ObjectStatusModelMapper objectStatusModelMapper;

    private static final String FROM_OBJECT_STATUS_MODEL_NOT_FOUND = "起始对象状态模型不存在";
    private static final String TO_OBJECT_STATUS_MODEL_NOT_FOUND = "目标对象状态模型不存在";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createTransition(ObjectStatusTransitionSaveReqVO createReqVO) {
        ObjectStatusTransitionDO transition = BeanUtil.copyProperties(createReqVO, ObjectStatusTransitionDO.class);
        validateDuplicateTransition(transition.getObjectType(), transition.getFromStatusCode(), transition.getActionCode(), null);
        validateStatusModelExists(transition.getObjectType(), transition.getFromStatusCode(), FROM_OBJECT_STATUS_MODEL_NOT_FOUND);
        validateStatusModelExists(transition.getObjectType(), transition.getToStatusCode(), TO_OBJECT_STATUS_MODEL_NOT_FOUND);
        validateFromAndToStatus(transition.getFromStatusCode(), transition.getToStatusCode());
        objectStatusTransitionMapper.insert(transition);
        return transition.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTransition(ObjectStatusTransitionSaveReqVO updateReqVO) {
        ObjectStatusTransitionDO existing = validateTransitionExists(updateReqVO.getId());
        ObjectStatusTransitionDO update = BeanUtil.copyProperties(updateReqVO, ObjectStatusTransitionDO.class);

//        if (!Objects.equals(existing.getObjectType(), update.getObjectType())) {
//            throw invalidParamException("对象类型创建后不允许修改");
//        }
//        if (!Objects.equals(existing.getFromStatusCode(), update.getFromStatusCode())) {
//            throw invalidParamException("起始状态编码创建后不允许修改");
//        }
//        if (!Objects.equals(existing.getActionCode(), update.getActionCode())) {
//            throw invalidParamException("动作编码创建后不允许修改");
//        }

        validateDuplicateTransition(update.getObjectType(), update.getFromStatusCode(), update.getActionCode(), existing.getId());
        validateStatusModelExists(update.getObjectType(), update.getFromStatusCode(), FROM_OBJECT_STATUS_MODEL_NOT_FOUND);
        validateStatusModelExists(update.getObjectType(), update.getToStatusCode(), TO_OBJECT_STATUS_MODEL_NOT_FOUND);
        validateFromAndToStatus(update.getFromStatusCode(), update.getToStatusCode());

        BeanUtil.copyProperties(update, existing, "id");
        objectStatusTransitionMapper.updateById(existing);
    }

    @Override
    public ObjectStatusTransitionRespVO getTransition(Long id) {
        return BeanUtil.copyProperties(objectStatusTransitionMapper.selectById(id), ObjectStatusTransitionRespVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTransition(Long id) {
        validateTransitionExists(id);
        objectStatusTransitionMapper.physicalDeleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTransitionList(List<Long> ids) {
        for (int i = 0; i < ids.size(); i++) {
            this.deleteTransition(ids.get(i));
        }
    }

    @Override
    public PageResult<ObjectStatusTransitionDO> getTransitionPage(ObjectStatusTransitionPageReqVO pageReqVO) {
        return objectStatusTransitionMapper.selectPage(pageReqVO);
    }

    /**
     * 校验同一对象类型、起始状态、动作编码的流转不能重复。
     */
    private void validateDuplicateTransition(String objectType, String fromStatusCode, String actionCode, Long excludeId) {
        ObjectStatusTransitionDO duplicate = objectStatusTransitionMapper.selectByUniqueKey(objectType, fromStatusCode, actionCode);
        if (ObjectUtil.isNotNull(duplicate) && !Objects.equals(duplicate.getId(), excludeId)) {
            throw invalidParamException("对象类型 [{}] 下起始状态 [{}] 与动作编码 [{}] 的流转已存在",
                    objectType, fromStatusCode, actionCode);
        }
    }

    /**
     * 校验流转引用的状态编码存在。
     */
    private void validateStatusModelExists(String objectType, String statusCode, String message) {
        ObjectStatusModelDO objectStatusModel = objectStatusModelMapper.selectByObjectTypeAndStatusCode(objectType, statusCode);
        if (Objects.isNull(objectStatusModel)) {
            throw invalidParamException(message);
        }
    }

    /**
     * 校验起始状态和目标状态不能相同。
     */
    private void validateFromAndToStatus(String fromStatusCode, String toStatusCode) {
        if (Objects.equals(fromStatusCode, toStatusCode)) {
            throw invalidParamException("起始状态和目标状态不能相同");
        }
    }

    /**
     * 校验状态流转存在。
     */
    private ObjectStatusTransitionDO validateTransitionExists(Long id) {
        ObjectStatusTransitionDO transition = objectStatusTransitionMapper.selectById(id);
        if (Objects.isNull(transition)) {
            throw invalidParamException("状态流转不存在");
        }
        return transition;
    }

}
