package com.dsideal;

import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dsideal.sso.Plugin.PostmanDocPlugin;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.jfinal.aop.Before;
import com.jfinal.core.Controller;
import com.jfinal.ext.interceptor.GET;
import com.jfinal.ext.interceptor.POST;
import io.github.yedaxia.apidocs.DocContext;
import io.github.yedaxia.apidocs.Docs;
import io.github.yedaxia.apidocs.DocsConfig;

import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * JApiDocs 无需额外注解的 API 文档生成工具
 * <p>
 * 源码 https://github.com/YeDaxia/JApiDocs
 * 文档 https://japidocs.agilestudio.cn/#/zh-cn/
 *
 * @author zxd 2022-02-17
 */
public class JApiDocsGenerator {

    private static String getHttpType(Before before) {
        for (Class<?> interceptClass : before.value()) {
            if (interceptClass.equals(GET.class)) {
                return "GET";
            } else if (interceptClass.equals(POST.class)) {
                return "POST";
            }
        }
        return "UNKNOWN";
    }

    /**
     * 获取指定目录下所有JAVA文件
     * @param directory 指定目录
     * @return 所有Java文件
     */
    public static List<File> findJavaFiles(File directory) {
        List<File> javaFiles = new ArrayList<>();
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    javaFiles.addAll(findJavaFiles(file)); // 递归遍历子目录
                } else if (file.getName().endsWith(".java")) {
                    javaFiles.add(file); // 添加Java文件
                }
            }
        }
        return javaFiles;
    }

    /**
     * 功能：获取所有 Controller 名称
     *
     * @param sourceJava JAVA目录
     * @return Controller名称集合
     */
    public static Map<String, String> getControllMap(String sourceJava) {
        Map<String, String> res = new HashMap<>();
        List<File> files = findJavaFiles(new File(sourceJava));
        for (File file : files) {
            String className = file.getAbsolutePath().replace("\\", "/").replace(sourceJava + "/", "");
            className = className.replace("/", ".");
            className = className.replace(".java", "");
            try {
                // 去掉.class后缀并加载类
                Class<?> cls = Class.forName(className);
                if (Controller.class.isAssignableFrom(cls) && !Modifier.isAbstract(cls.getModifiers())) {
                    // 获取类上的所有方法
                    Method[] methods = cls.getDeclaredMethods();
                    for (Method method : methods) {
                        // 检查方法上是否有@Before注解
                        var before = method.getAnnotation(Before.class);
                        if (before != null) {
                            String httpType = getHttpType(before);
                            res.put(cls.getSimpleName() + "." + method.getName(), httpType);
                        }
                    }
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return res;
    }

    /**
     * JApiDocs 生成器
     * 如果报错，做如下检查：
     * 1 javadoc @param 后是否有注释
     * 2 src.main.java 目录中非 .java 扩展名文件的内容要 // 注释起来
     * 3 删除 config.setDocsPath 目录中的文件，再生成试试
     * <p>
     * 如果生成的 api 文档不是预期的，作如下检查：
     * 1 必须在 configRoute(Routes me) 中已该方式 me.add("/xx/yy", xx.class, "/"); 定义 Controller
     * 2 在需要生成 api 的 Controller 中添加 @ApiDoc 注解
     * 3 如果要忽略某 action，在 action 上添加 @Ignore
     * https://jfinal.com/share/2528
     * <p>
     * 在需要生成Doc文档的Controller类上面加上@ApiDoc注解
     * <p>
     * https://japidocs.agilestudio.cn/#/zh-cn/
     */
    public static void main(String[] args) {
        //可以限制只生成哪个接口,数组内容为空，则表示生成全部
        //String[] generateInterfacesList = {"getWxTj"};
        String[] generateInterfacesList = {};

        String projectPath = System.getProperty("user.dir");
        projectPath = projectPath.replace("\\", "/");
        String projectName = projectPath.substring(projectPath.lastIndexOf("/") + 1);
        DocsConfig config = new DocsConfig();
        String sourceJava = projectPath + "/src/main/java";
        config.setProjectPath(sourceJava); // root project path
        config.setProjectName(projectName); // project name
        String version = "v1.0";
        config.setApiVersion(version);       // api version
        String docPath = projectPath + "/Doc";
        config.setDocsPath(docPath); // api docs target path
        config.addPlugin(new PostmanDocPlugin());
        config.setAutoGenerate(Boolean.FALSE);  // auto generate
        config.setMvcFramework("JFinal");
        Docs.buildHtmlDocs(config); // execute to generate

        // 获取项目路径
        Map<String, String> map = getControllMap(sourceJava);
        //修正一下 postman 的请求方式
        String docFileName = String.format("%s-%s-api-docs.json", DocContext.getDocsConfig().getProjectName(), DocContext.getDocsConfig().getApiVersion());
        String jsonPath = docPath + "/" + version + "/" + docFileName;
        String jsonContent = FileUtil.readUtf8String(jsonPath);
        JSONObject jo = JSONObject.parseObject(jsonContent);
        //第一层item
        for (Object item : jo.getJSONArray("item")) {
            JSONObject j2 = (JSONObject) item;
            //Controller类名
            String className = j2.getString("name");
            //第二层item
            for (Object o : j2.getJSONArray("item")) {
                JSONObject j3 = (JSONObject) o;
                JSONObject jRequest = j3.getJSONObject("request");
                String x = jRequest.getJSONObject("url").getString("raw");
                x = x.substring(x.lastIndexOf("/") + 1);
                jRequest.put("method", map.get(className + "." + x));
            }
        }
        //限制只生成哪个接口
        Set<String> _set = new HashSet<>();
        Collections.addAll(_set, generateInterfacesList);

        // 获取JSONArray
        jo = jo.getJSONArray("item").getJSONObject(0);
        JSONArray jsonArray = jo.getJSONArray("item");

        if (!_set.isEmpty()) {
            // 遍历JSONArray
            for (int i = 0; i < jsonArray.size(); i++) {
                // 获取当前的JSONObject
                JSONObject obj = jsonArray.getJSONObject(i);
                JSONObject jRequest = obj.getJSONObject("request");
                // 检查条件，例如，如果名字不是"John"，则删除这个条目
                String x = jRequest.getJSONObject("url").getString("raw");
                x = x.substring(x.lastIndexOf("/") + 1);
                if (!_set.contains(x)) {
                    // 从JSONArray中移除当前条目
                    jsonArray.remove(i);
                    // 由于移除操作会改变数组的长度和索引，所以i需要减1以保持正确的索引位置
                    i--;
                }
            }
            // 将修改后的JSONArray重新设置回JSONObject
            jo.put("item", jsonArray);
        }
        //美化JSON格式化保存
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        String jsonString = gson.toJson(jo);
        FileUtil.writeUtf8String(jsonString, jsonPath);
        System.out.println("恭喜，文档JSON处理完成！");
    }
}