package cn.stylefeng.team.meta.modular.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kernel.db.api.factory.PageFactory;
import cn.stylefeng.roses.kernel.db.api.factory.PageResultFactory;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.team.meta.api.entity.MetaDefinition;
import cn.stylefeng.team.meta.modular.enums.MetaDefinitionExceptionEnum;
import cn.stylefeng.team.meta.modular.mapper.MetaDefinitionMapper;
import cn.stylefeng.team.meta.modular.pojo.request.MetaDefinitionRequest;
import cn.stylefeng.team.meta.modular.service.MetaDefinitionService;
import cn.stylefeng.team.meta.modular.service.MetaModelService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class MetaDefinitionServiceImpl extends ServiceImpl<MetaDefinitionMapper, MetaDefinition> implements MetaDefinitionService {

    @Resource
    private MetaModelService metaModelService;

    @Override
    public void add(MetaDefinitionRequest metaDefinitionRequest) {
        MetaDefinition metaDefinition = new MetaDefinition();
        BeanUtil.copyProperties(metaDefinitionRequest, metaDefinition);
        this.save(metaDefinition);
    }

    @Override
    public void del(MetaDefinitionRequest metaDefinitionRequest) {
        MetaDefinition metaDefinition = this.queryMetaDefinition(metaDefinitionRequest);
        this.removeById(metaDefinition.getMetaDefinitionId());
    }

    @Override
    public void edit(MetaDefinitionRequest metaDefinitionRequest) {
        MetaDefinition metaDefinition = this.queryMetaDefinition(metaDefinitionRequest);
        BeanUtil.copyProperties(metaDefinitionRequest, metaDefinition);
        this.updateById(metaDefinition);
    }

    @Override
    public MetaDefinition detail(MetaDefinitionRequest metaDefinitionRequest) {
        return this.queryMetaDefinition(metaDefinitionRequest);
    }

    @Override
    public PageResult<MetaDefinition> findPage(MetaDefinitionRequest metaDefinitionRequest) {
        LambdaQueryWrapper<MetaDefinition> wrapper = createWrapper(metaDefinitionRequest);
        Page<MetaDefinition> sysRolePage = this.page(PageFactory.defaultPage(), wrapper);
        return PageResultFactory.createPageResult(sysRolePage);
    }

    @Override
    public MetaDefinition findModelNewestDefinition(Long metaModelId) {

        LambdaQueryWrapper<MetaDefinition> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MetaDefinition::getMetaModelId, metaModelId);

        wrapper.orderByDesc(MetaDefinition::getFldVersion);

        Page<MetaDefinition> result = this.page(PageFactory.defaultPage(), wrapper);
        if (ObjectUtil.isNotEmpty(result.getRecords())) {
            return result.getRecords().get(0);
        } else {
            return null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> removeDefinitionList(Long metaModelId) {

        if (metaModelId == null) {
            return new ArrayList<>();
        }

        LambdaQueryWrapper<MetaDefinition> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MetaDefinition::getMetaModelId, metaModelId);
        queryWrapper.select(MetaDefinition::getMetaDefinitionId);
        List<MetaDefinition> classDefinitionList = this.list(queryWrapper);

        List<Long> definitionIdList = classDefinitionList.stream().map(MetaDefinition::getMetaDefinitionId).collect(Collectors.toList());
        this.removeByIds(definitionIdList);

        return definitionIdList;
    }

    @Override
    public Long getMetaModelIdByDefinitionId(Long metaDefinitionId) {
        LambdaQueryWrapper<MetaDefinition> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MetaDefinition::getMetaDefinitionId, metaDefinitionId);
        queryWrapper.select(MetaDefinition::getMetaModelId);
        MetaDefinition metaDefinition = this.getOne(queryWrapper, false);
        if (metaDefinition == null) {
            return null;
        } else {
            return metaDefinition.getMetaModelId();
        }
    }

    @Override
    public void cleanBusinessDefinitions(Long businessId) {
        LambdaQueryWrapper<MetaDefinition> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MetaDefinition::getBusinessId,  businessId);
        this.remove(wrapper);
    }

    @Override
    public List<MetaDefinition> findList(MetaDefinitionRequest metaDefinitionRequest) {
        LambdaQueryWrapper<MetaDefinition> wrapper = this.createWrapper(metaDefinitionRequest);
        return this.list(wrapper);
    }

    private MetaDefinition queryMetaDefinition(MetaDefinitionRequest metaDefinitionRequest) {
        MetaDefinition metaDefinition = this.getById(metaDefinitionRequest.getMetaDefinitionId());
        if (ObjectUtil.isEmpty(metaDefinition)) {
            throw new ServiceException(MetaDefinitionExceptionEnum.META_DEFINITION_NOT_EXISTED);
        }
        return metaDefinition;
    }

    private LambdaQueryWrapper<MetaDefinition> createWrapper(MetaDefinitionRequest metaDefinitionRequest) {
        LambdaQueryWrapper<MetaDefinition> queryWrapper = new LambdaQueryWrapper<>();

        Long metaDefinitionId = metaDefinitionRequest.getMetaDefinitionId();
        Long metaModelId = metaDefinitionRequest.getMetaModelId();
        String fldVersion = metaDefinitionRequest.getFldVersion();

        queryWrapper.eq(ObjectUtil.isNotNull(metaDefinitionId), MetaDefinition::getMetaDefinitionId, metaDefinitionId);
        queryWrapper.eq(ObjectUtil.isNotNull(metaModelId), MetaDefinition::getMetaModelId, metaModelId);
        queryWrapper.like(ObjectUtil.isNotEmpty(fldVersion), MetaDefinition::getFldVersion, fldVersion);

        return queryWrapper;
    }

}