package cn.axzo.workflow.core.service.impl;

import cn.axzo.workflow.common.constant.BpmnConstants;
import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO;
import cn.axzo.workflow.common.model.request.category.CategorySearchDTO;
import cn.axzo.workflow.common.model.request.category.CategoryUpdateDTO;
import cn.axzo.workflow.common.model.response.category.CategoryItemVO;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.repository.entity.ExtAxDictDO;
import cn.axzo.workflow.core.repository.mapper.ExtAxDictMapper;
import cn.axzo.workflow.core.service.CategoryService;
import cn.axzo.workflow.core.service.converter.CategoryConverter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CATEGORY_ID_NOT_EXISTS;
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CATEGORY_VALUE_EXISTS;

@Service
@RequiredArgsConstructor
@Slf4j
public class CategoryServiceImpl extends ServiceImpl<ExtAxDictMapper, ExtAxDictDO> implements CategoryService
        , BpmnConstants {
    @Resource
    private ExtAxDictMapper bpmDictDataMapper;

    private final CategoryConverter categoryConverter;

    @Override
    public int createCategory(CategoryCreateDTO dto) {
        Optional<ExtAxDictDO> oneOpt = this.lambdaQuery().eq(ExtAxDictDO::getLabel, dto.getLabel())
                .eq(ExtAxDictDO::getValue, dto.getValue())
                .oneOpt();
        if (oneOpt.isPresent()) {
            throw new WorkflowEngineException(CATEGORY_VALUE_EXISTS, dto.getLabel());
        }
        ExtAxDictDO dict = new ExtAxDictDO();
        populateDict(dto, dict);
        return bpmDictDataMapper.insert(dict);
    }

    private static void populateDict(CategoryCreateDTO dto, ExtAxDictDO dict) {
        dict.setType(BPM_MODEL_CATEGORY);
        dict.setLabel(dto.getLabel());
        dict.setValue(dto.getValue());
        dict.setRemark(dto.getRemark());
        dict.setSort(dto.getSort());
        dict.setStatus(dto.getStatus() ? 1 : 0);
        dict.setTenantId(dto.getTenantId());
    }

    @Override
    public int updateCategory(CategoryUpdateDTO dto) {
        Optional<ExtAxDictDO> dictDO = this.lambdaQuery().eq(ExtAxDictDO::getId, dto.getId())
                .oneOpt();
        if (!dictDO.isPresent()) {
            throw new WorkflowEngineException(CATEGORY_ID_NOT_EXISTS, String.valueOf(dto.getId()));
        }
        dictDO.ifPresent(dict -> {
            populateDict(dto, dict);
        });
        return bpmDictDataMapper.updateById(dictDO.get());
    }

    @Override
    public int deleteCategory(Long id) {
        return bpmDictDataMapper.deleteById(id);
    }

    @Override
    public Page<CategoryItemVO> findCategory(CategorySearchDTO dto) {

        LambdaQueryWrapper<ExtAxDictDO> queryWrapper = Wrappers.lambdaQuery(ExtAxDictDO.class)
                .eq(StringUtils.isNotBlank(dto.getDictType()), ExtAxDictDO::getType, dto.getDictType())
                .eq(StringUtils.isNotBlank(dto.getLabel()), ExtAxDictDO::getLabel, dto.getLabel())
                .eq(StringUtils.isNotBlank(dto.getValue()), ExtAxDictDO::getValue, dto.getValue())
                .eq(Objects.nonNull(dto.getStatus()), ExtAxDictDO::getStatus, dto.getStatus())
                .eq(StringUtils.isNotBlank(dto.getTenantId()), ExtAxDictDO::getTenantId, dto.getTenantId());

        Page<ExtAxDictDO> page = bpmDictDataMapper.selectPage(new Page<>(dto.getPageNo(), dto.getPageSize()),
                queryWrapper);

        List<CategoryItemVO> categoryVOS =
                page.getRecords().stream().map(categoryConverter::toVo).collect(Collectors.toList());

        Page<CategoryItemVO> result = new Page<>();
        result.setRecords(categoryVOS);
        result.setSize(page.getSize());
        result.setTotal(page.getTotal());
        result.setCurrent(page.getCurrent());

        return result;
    }

    @Override
    public Boolean updateState(Long id, Boolean state) {
        Optional<ExtAxDictDO> dictDO = this.lambdaQuery().eq(ExtAxDictDO::getId, id).oneOpt();
        if (!dictDO.isPresent()) {
            throw new WorkflowEngineException(CATEGORY_ID_NOT_EXISTS, String.valueOf(id));
        }
        dictDO.ifPresent(dict -> {
            dict.setStatus(state ? 1 : 0);
        });
        bpmDictDataMapper.updateById(dictDO.get());
        return true;
    }
}
