package com.red.circle.example.api;

import com.red.circle.framework.dto.IResponseErrorCode;
import com.red.circle.framework.dto.ResErrorCode;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.json.JacksonUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.Data;
import lombok.experimental.Accessors;
import org.reflections.Reflections;

/**
 * @author pengliang on 2023/11/28
 */
public class ApiErrorCodeTool {

  /**
   * 检查定义code是否存在错误定义.
   */
  public static void printErrorDefinition() {
    List<ErrorCodeDefinition> errorCodeDefinitions = getErrorDefinition();

    if (CollectionUtils.isEmpty(errorCodeDefinitions)) {
      System.out.println("没有获取到结果");
      return;
    }
    for (ErrorCodeDefinition errorCodeDefinition : errorCodeDefinitions) {

      if (errorCodeDefinition.getErrorCodes().isEmpty()) {
        continue;
      }

      System.out.println(
          errorCodeDefinition.getDescribe() + "(" + errorCodeDefinition.getClassName() + ")、范围:"
              + errorCodeDefinition.getMinCode() + "~" + errorCodeDefinition.getMaxCode()
              + "==================");
      System.out.println("状态：" + (
              errorCodeDefinition.getErrorCodes().isEmpty()
                  ? "正常" : "异常"
          )
      );
      if (!errorCodeDefinition.getErrorCodes().isEmpty()) {
        System.out.println(
            "异常Code: " + StringUtils.join(errorCodeDefinition.getErrorCodes(), "、"));
      }
    }
  }

  /**
   * 获取code定义情况.
   */
  public static List<ErrorCodeDefinition> getErrorDefinition() {
    List<ErrorCodeDoc> errorCodeDocs = ApiErrorCodeTool.getErrorCodeDoc();
    if (CollectionUtils.isEmpty(errorCodeDocs)) {
      return new ArrayList<>();
    }

    List<ErrorCodeDefinition> definitions = new ArrayList<>();
    for (ErrorCodeDoc errorCodeDoc : errorCodeDocs) {

      ErrorCodeDefinition codeDefinition = new ErrorCodeDefinition();
      codeDefinition.setMinCode(errorCodeDoc.getMinCode());
      codeDefinition.setMaxCode(errorCodeDoc.getMaxCode());
      codeDefinition.setClassName(errorCodeDoc.getClassName());
      codeDefinition.setDescribe(errorCodeDoc.getDescribe());

      List<Integer> errorCodes = new ArrayList<>();
      for (ErrorCodeDetails errorCodeDetail : errorCodeDoc.getErrorCodeDetails()) {
        int code = Integer.parseInt(errorCodeDetail.getCode());
        if (code < errorCodeDoc.getMinCode() || code > errorCodeDoc.getMaxCode()) {
          errorCodes.add(code);
        }
      }

      codeDefinition.setErrorCodes(errorCodes);
      definitions.add(codeDefinition);
    }

    return definitions;
  }

  /**
   * 打印可用Code.
   */
  public static void printAvailableCode(Class<? extends IResponseErrorCode> errorCodeClass) {

    if (Objects.isNull(errorCodeClass)) {
      System.out.println("请输入参数.");
      return;
    }

    List<ErrorCodeDoc> errorCodeDocs = ApiErrorCodeTool.getErrorCodeDoc();
    if (CollectionUtils.isEmpty(errorCodeDocs)) {
      System.out.println("没有找到 IResponseErrorCode.class 实现");
      return;
    }

    ErrorCodeDoc doc = errorCodeDocs.stream()
        .filter(obj -> Objects.equals(obj.getClassName(), errorCodeClass.getSimpleName()))
        .findFirst()
        .orElse(null);

    if (Objects.isNull(doc)) {
      System.out.println("没有找到: " + errorCodeClass.getName());
      return;
    }

    List<Integer> codes = new ArrayList<>();
    for (int index = doc.getMinCode(); index <= doc.getMaxCode(); index++) {
      codes.add(index);
    }

    codes.removeAll(doc.getErrorCodeDetails().stream()
        .map(ErrorCodeDetails::getCode)
        .map(Integer::valueOf)
        .collect(Collectors.toList()));

    for (Integer code : codes) {
      System.out.println("Code: " + code);
    }
  }

  /**
   * 打印错误编码文档.
   */
  public static void printErrorCodeDoc() {
    List<ErrorCodeDoc> errorCodeDocs = ApiErrorCodeTool.getErrorCodeDoc();
    if (CollectionUtils.isEmpty(errorCodeDocs)) {
      System.out.println("没有找到 IResponseErrorCode.class 实现");
      return;
    }

    System.out.println("### 概括");
    System.out.println("|CodeClass|Describe|CodeRange|");
    System.out.println("|:--------------------|");
    for (ErrorCodeDoc errorCodeDoc : errorCodeDocs) {
      String describeCol = String.format("|%s|%s|%s~%s|",
          errorCodeDoc.getClassName(),
          errorCodeDoc.getDescribe(),
          errorCodeDoc.getMinCode(),
          errorCodeDoc.getMaxCode()
      );
      System.out.println(describeCol);
    }

    for (ErrorCodeDoc errorCodeDoc : errorCodeDocs) {
      System.out.println();
      System.out.println("### " + errorCodeDoc.getClassName());
      System.out.println(
          errorCodeDoc.getDescribe() + ", Code范围：" + errorCodeDoc.getMinCode() + "~"
              + errorCodeDoc.getMaxCode());
      System.out.println();
      System.out.println("|CodeName|Code|Message|");
      System.out.println("|:--------------------|");
      for (ErrorCodeDetails errorCodeDetail : errorCodeDoc.getErrorCodeDetails()) {
        String col = String.format("|%s|%s|%s|",
            errorCodeDetail.getCodeName(),
            errorCodeDetail.getCode(),
            errorCodeDetail.getMessage()
        );
        System.out.println(col);
      }
    }
  }

  /**
   * 输出eolink code json.
   */
  public static void printEoLinkJson() {
    List<ErrorCodeDoc> errorCodeDocs = ApiErrorCodeTool.getErrorCodeDoc();
    List<EoLinkCode> eoLinkCodes = errorCodeDocs.stream().map(ErrorCodeDoc::getErrorCodeDetails)
        .flatMap(Collection::stream)
        .map(code -> new EoLinkCode()
            .setCode(code.getCode())
            .setCodeDescription(String.format("[%s] %s", code.getCodeName(), code.getMessage())))
        .toList();
    System.out.println(JacksonUtils.toJson(eoLinkCodes));
  }

  private static List<ErrorCodeDoc> getErrorCodeDoc() {
    List<ErrorCodeDoc> errorCodeDocs = new ArrayList<>();
    List<Class<?>> implementations = findResponseErrorCodeImplementations();
    for (Class<?> enumClass : implementations) {
      // 检查是否是枚举
      if (enumClass.isEnum()) {
        ErrorCodeDoc errorCodeDoc = new ErrorCodeDoc();
        errorCodeDoc.setClassName(enumClass.getSimpleName());

        ResErrorCode resErrorCode = enumClass.getAnnotation(ResErrorCode.class);

        if (Objects.nonNull(resErrorCode)) {
          errorCodeDoc.setDescribe(resErrorCode.describe());
          errorCodeDoc.setMinCode(resErrorCode.minCode());
          errorCodeDoc.setMaxCode(resErrorCode.maxCode());
        } else {
          errorCodeDoc.setDescribe("没有写描述");
          errorCodeDoc.setMinCode(0);
          errorCodeDoc.setMaxCode(0);
        }

        // 获取所有枚举实例
        Object[] enumConstants = enumClass.getEnumConstants();
        List<ErrorCodeDetails> errorCodeDetails = new ArrayList<>();
        for (Object enumConstant : enumConstants) {
          try {
            // 使用反射获取枚举名称和值
            Field codeField = enumClass.getDeclaredField("code");
            Field messageField = enumClass.getDeclaredField("message");
            codeField.setAccessible(true);
            messageField.setAccessible(true);

            String name = ((Enum<?>) enumConstant).name();
            String code = Objects.toString(codeField.get(enumConstant));
            String message = Objects.toString(messageField.get(enumConstant));

            ErrorCodeDetails codeDetails = new ErrorCodeDetails();
            codeDetails.setCode(code);
            codeDetails.setCodeName(name);
            codeDetails.setMessage(message);
            errorCodeDetails.add(codeDetails);
          } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
          }
        }
        errorCodeDoc.setErrorCodeDetails(errorCodeDetails);
        errorCodeDocs.add(errorCodeDoc);
      }
    }

    return errorCodeDocs.stream().sorted(Comparator.comparing(ErrorCodeDoc::getMinCode)).collect(
        Collectors.toList());
  }

  private static List<Class<?>> findResponseErrorCodeImplementations() {
    // 使用 Reflections 查找实现类
    Reflections reflections = new Reflections("com.red.circle");
    Set<Class<? extends IResponseErrorCode>> subTypes = reflections.getSubTypesOf(
        IResponseErrorCode.class);
    return new ArrayList<>(subTypes);
  }

  @Data
  static class ErrorCodeDefinition {

    /**
     * 类名.
     */
    private String className;

    /**
     * 描述.
     */
    private String describe;

    /**
     * 最小code.
     */
    private Integer minCode;

    /**
     * 最大code.
     */
    private Integer maxCode;

    /**
     * 错误编码.
     */
    private List<Integer> errorCodes;

  }


  @Data
  static class ErrorCodeDoc {

    /**
     * 类名.
     */
    private String className;

    /**
     * 描述.
     */
    private String describe;

    /**
     * 最小code.
     */
    private Integer minCode;

    /**
     * 最大code.
     */
    private Integer maxCode;

    /**
     * 错误编码信息.
     */
    private List<ErrorCodeDetails> errorCodeDetails;

  }

  @Data
  static class ErrorCodeDetails {

    private String codeName;
    private String code;
    private String message;

  }

  @Data
  @Accessors(chain = true)
  static class EoLinkCode {

    /**
     * code.
     */
    private String code;

    /**
     * 描述.
     */
    private String codeDescription;

  }

}
