package org.matrix.autotest.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.matrix.database.entity.Environment;
import org.matrix.database.entity.InterfaceInformation;
import org.matrix.database.entity.Parameter;
import org.matrix.database.service.IEnvironmentService;
import org.matrix.database.vo.CommonPage;
import org.matrix.exception.GlobalException;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author mry
 */
@RestController
@RequestMapping("/swaggers")
@CrossOrigin
@Api(tags = "Swagger接口读取与解析")
public class SwaggerController {

    private final IEnvironmentService environmentService;

    public SwaggerController(IEnvironmentService environmentService) {
        this.environmentService = environmentService;
    }

    /**
     * 读取swagger地址里的JSON信息
     *
     * @param url swagger地址
     * @return swagger中的JSON数据
     */
    public String loadJson(String url) {
        BufferedReader reader;
        StringBuilder json = new StringBuilder();
        try {
            URL urlObject = new URL(url);
            URLConnection uc = urlObject.openConnection();
            InputStream inputStream = uc.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
            String inputLine;
            while ((inputLine = reader.readLine()) != null) {
                json.append(inputLine);
            }
            reader.close();
        } catch (IOException e) {
            throw new GlobalException(String.format("请求swagger数据失败,您读的swagger地址ip为 %d", url));
        }
        return json.toString();
    }

    /**
     * 根据标签名称模糊查询list集合
     *
     * @param name 查询条件: 名称
     * @param list 查询的集合
     * @return 模糊查询的结果
     */
    public List<InterfaceInformation> search(String name, List<InterfaceInformation> list) {
        @SuppressWarnings(value = "all")
        List<InterfaceInformation> results = new ArrayList();
        Pattern pattern = Pattern.compile(name, Pattern.CASE_INSENSITIVE);
        for (InterfaceInformation o : list) {
            Matcher matcher = pattern.matcher(o.getTags());
            if (matcher.find()) {
                results.add(o);
            }
        }
        return results;
    }

    /**
     * 用来获取Swagger中的信息
     *
     * @param json json字符串
     * @return json中过滤出的信息
     */
    private List<InterfaceInformation> getList(String json) {
        long i = 0;
        JSONObject swaggerJson = JSONObject.parseObject(json);
        //localhost:8765
        Object host = swaggerJson.get("host");
        //"/"
        Object basePath = swaggerJson.get("basePath");
        Object paths = swaggerJson.get("paths");
        //将paths转成map集合
        @SuppressWarnings(value = "unchecked")
        Map<String, String> pathsMaps = (Map<String, String>) paths;
        //获取key
        Set<String> methodUrls = pathsMaps.keySet();
        List<InterfaceInformation> list = new ArrayList<>();
        //循环获取每个methodUrl
        for (String methodUrl : methodUrls) {
            //将paths转成JSON
            JSONObject objPaths = (JSONObject) paths;
            //通过JSON获取到methodUrl,用来获取methodUrl内部的信息
            Object objMethodUrls = objPaths.get(methodUrl);
            JSONObject objUrlsJson = (JSONObject) objMethodUrls;
            @SuppressWarnings(value = "unchecked")
            Map<String, String> objMethodUrlsMaps = (Map<String, String>) objMethodUrls;
            Set<String> requests = objMethodUrlsMaps.keySet();
            for (String request : requests) {
                //拿到请求内部的信息
                Object objRequest = objUrlsJson.get(request);
                @SuppressWarnings(value = "unchecked")
                Map<String, String> objRequestMaps = (Map<String, String>) objRequest;
                Object parameters = objRequestMaps.get("parameters");
                Object tags = objRequestMaps.get("tags");
                Object summary = objRequestMaps.get("summary");
                List<Parameter> parameterAllList = new ArrayList<>();
                InterfaceInformation interfaceInformation = new InterfaceInformation();
                @SuppressWarnings(value = "all")
                List<String> parameterLists = parameters == null ? new ArrayList<>() : (List<String>) parameters;
                for (Object parameterList : parameterLists) {
                    @SuppressWarnings(value = "unchecked")
                    Map<String, String> parameterMaps = (Map<String, String>) parameterList;
                    String methodIn = parameterMaps.get("in");
                    String methodName = parameterMaps.get("name");
                    String methodType = parameterMaps.get("type");
                    Parameter parameter = new Parameter();
                    //传参格式
                    parameter.setIn(methodIn);
                    //拿到参数名称
                    parameter.setName(methodName);
                    //拿到参数类型
                    parameter.setType(methodType);
                    parameterAllList.add(parameter);
                }
                interfaceInformation.setId(i++);
                interfaceInformation.setHost(String.valueOf(host));
                interfaceInformation.setParameterAllList(parameterAllList);
                interfaceInformation.setBasePath(String.valueOf(basePath));
                interfaceInformation.setRequest(request.toUpperCase());
                interfaceInformation.setSummary(String.valueOf(summary));
                interfaceInformation.setMethodUrl(methodUrl);
                interfaceInformation.setTags(String.valueOf(tags));
                list.add(interfaceInformation);
            }
        }
        return list;
    }

    /**
     * 快速添加接口
     *
     * @param projectId  项目id
     * @param id         环境id
     * @param pageSize   每页多少条数据
     * @param pageNum    当前第几页
     * @param name       查询条件: 标签名称
     * @param swaggerUrl 查询条件: 方法的url
     * @return Swagger中的数据
     */
    @PostMapping
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "快速添加接口")
    public CommonPage<List<InterfaceInformation>> parameter(
            Long projectId,
            Long id,
            @RequestParam(defaultValue = "10") int pageSize,
            @RequestParam(defaultValue = "1") int pageNum,
            String name,
            String swaggerUrl) {
        //将所有的默认选项置为false
        environmentService.setIsDefaultByWrapper(false,
                Wrappers.lambdaQuery(Environment.class).eq(Environment::getProjectId, projectId));
        //将选中的环境置为true,后续默认选择这个环境
        environmentService.setIsDefaultByWrapper(true,
                Wrappers.lambdaQuery(Environment.class).eq(Environment::getId, id));
        Environment environment = environmentService.getById(id);
        String url = String.format("%s/v2/api-docs", environment.getIp());
        //获得json字符串
        String json = loadJson(url);
        List<InterfaceInformation> list = getList(json);
        List<InterfaceInformation> swaggerUrlSearch;
        if (swaggerUrl != null) {
            swaggerUrlSearch = search(swaggerUrl, list);
        } else {
            swaggerUrlSearch = list;
        }
        List<InterfaceInformation> swaggerNameSearch;
        if (name != null) {
            swaggerNameSearch = search(name, swaggerUrlSearch);
        } else {
            swaggerNameSearch = list;
        }
        int total = swaggerNameSearch.size();
        List<InterfaceInformation> subList = swaggerNameSearch.subList(pageSize * (pageNum - 1), (Math.min((pageNum * pageSize), total)));
        CommonPage<List<InterfaceInformation>> listCommonPage = new CommonPage<>();
        listCommonPage.setList(subList);
        listCommonPage.setTotal(total);
        listCommonPage.setPageNum(pageNum);
        listCommonPage.setPageSize(pageSize);
        return listCommonPage;
    }
}
