package com.xjrsoft.module.magicapi.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.xjrsoft.common.utils.TreeUtil;
import com.xjrsoft.module.magicapi.service.IMagicApiService;
import com.xjrsoft.module.magicapi.vo.MagicApiGroupTreeVo;
import com.xjrsoft.module.magicapi.vo.MagicApiInfoVo;
import com.xjrsoft.module.magicapi.vo.MagicApiTreeVo;
import lombok.AllArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.ssssssss.magicapi.core.model.ApiInfo;
import org.ssssssss.magicapi.core.model.BaseDefinition;
import org.ssssssss.magicapi.core.model.Group;
import org.ssssssss.magicapi.core.model.MagicEntity;
import org.ssssssss.magicapi.core.model.Parameter;
import org.ssssssss.magicapi.core.model.TreeNode;
import org.ssssssss.magicapi.core.service.MagicAPIService;
import org.ssssssss.magicapi.core.service.MagicResourceService;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * magic-api服务
 *
 * @author apple
 */
@Service
@AllArgsConstructor
public class MagicApiServiceImpl implements IMagicApiService {

    private final MagicResourceService magicResourceService;

    private final MagicAPIService magicAPIService;

    @Override
    public List<MagicApiTreeVo> tree(String keyword) {
        TreeNode<Group> tree = magicResourceService.tree("api");

        List<TreeNode<Group>> children = tree.getChildren();

        return TreeUtil.build(buildTreeData(children, keyword));
    }

    @Override
    public List<MagicApiGroupTreeVo> groupTree() {
        TreeNode<Group> tree = magicResourceService.tree("api");

        List<TreeNode<Group>> children = tree.getChildren();
        List<MagicApiGroupTreeVo> treeVoList = new ArrayList<>();
        buildGroupTreeData(treeVoList, children);
        return TreeUtil.build(treeVoList);
    }

    @Override
    public MagicApiInfoVo info(String id) {
        MagicEntity entity = magicResourceService.file(id);
        BaseDefinition requestBodyDefinition = ((ApiInfo) entity).getRequestBodyDefinition();
        MagicApiInfoVo magicApiInfoVo = BeanUtil.toBean(entity, MagicApiInfoVo.class);
        String groupId = entity.getGroupId();
        if (StringUtils.isNotEmpty(groupId)) {
            String groupPath = magicResourceService.getGroupPath(groupId);
            magicApiInfoVo.setPath(groupPath + "/" + magicApiInfoVo.getPath());
        }
        magicApiInfoVo.setRequestBodyDefinition(requestBodyDefinition);
        return magicApiInfoVo;
    }

    @Override
    public List<MagicApiInfoVo> list(String groupId) {
        String groupPath = magicResourceService.getGroupPath(groupId);

        List<MagicEntity> magicEntities = magicResourceService.listFiles(groupId);

        List<MagicApiInfoVo> magicApiInfoVos = BeanUtil.copyToList(magicEntities, MagicApiInfoVo.class);
        for (MagicApiInfoVo magicApiInfoVo : magicApiInfoVos) {
            magicApiInfoVo.setPath(groupPath + "/" + magicApiInfoVo.getPath());
        }

        return magicApiInfoVos;
    }

    public <T> T executeApi(String id) {
        MagicApiInfoVo info = info(id);
        Map<String, Object> parameters = new HashMap();
        for (Parameter parameter : info.getParameters()){
            parameters.put(parameter.getName(),parameter.getValue());
        }
        return magicAPIService.execute(info.getMethod(), info.getPath(), parameters);
    }


    /**
     * 查询分组以及api 树结构
     *
     * @param treeNodes
     * @return
     */
    private List<MagicApiTreeVo> buildTreeData(List<TreeNode<Group>> treeNodes, String keyword) {

        List<MagicApiTreeVo> treeVoList = new ArrayList<>();
        for (TreeNode<Group> treeNode : treeNodes) {
            Group node = treeNode.getNode();

            List<MagicEntity> nodeEntity = magicResourceService.listFiles(node.getId());


            if (StringUtils.isNotBlank(keyword) && !node.getName().contains(keyword) && nodeEntity.stream().noneMatch(x -> x.getName().contains(keyword) || ((ApiInfo) x).getPath().contains(keyword))) {
                continue;
            }

            MagicApiTreeVo groupVo = new MagicApiTreeVo();
            groupVo.setId(node.getId());
            groupVo.setParentId(node.getParentId());
            groupVo.setType("group");
            groupVo.setName(node.getName());

            treeVoList.add(groupVo);


            for (MagicEntity magicEntity : nodeEntity) {
                MagicApiTreeVo vo = new MagicApiTreeVo();

                ApiInfo apiInfo = (ApiInfo) magicEntity;
                if (StringUtils.isNotBlank(keyword) && !magicEntity.getName().contains(keyword) && !apiInfo.getPath().contains(keyword)) {
                    continue;
                }

                vo.setId(magicEntity.getId());
                vo.setType("api");
                vo.setParentId(magicEntity.getGroupId());
                vo.setName(magicEntity.getName());
                String groupPath = StringUtils.isEmpty(node.getPath()) ? StringPool.EMPTY : node.getPath();

                vo.setPath(groupPath + apiInfo.getPath());
                vo.setMethod(apiInfo.getMethod());

                treeVoList.add(vo);
            }


            if (treeNode.getChildren().size() > 0) {
                treeVoList.addAll(buildTreeData(treeNode.getChildren(), keyword));
            }

        }

        return treeVoList;
    }

    /**
     * 构建 分组树结构
     *
     * @param treeNodes
     * @return
     */
    private void buildGroupTreeData(List<MagicApiGroupTreeVo> treeVoList, List<TreeNode<Group>> treeNodes) {

        for (TreeNode<Group> treeNode : treeNodes) {
            Group node = treeNode.getNode();

            MagicApiGroupTreeVo groupVo = new MagicApiGroupTreeVo();

            groupVo.setId(node.getId());
            groupVo.setParentId(node.getParentId());
            groupVo.setName(node.getName());

            treeVoList.add(groupVo);
            List<TreeNode<Group>> children = treeNode.getChildren();
            if (CollectionUtils.isNotEmpty(children)) {
                buildGroupTreeData(treeVoList, children);
            }

        }
    }
}
