package com.multictrl.common.config;

import com.multictrl.common.annotation.ApiOrder;
import com.multictrl.common.constant.Constant;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * Swagger配置
 *
 * @author Sdy
 */
@Slf4j
@Configuration
public class SwaggerConfig {

    @Bean
    public OpenAPI createRestApi() {
        return new OpenAPI()
                .info(apiInfo())
                .security(security());
    }

    /**
     * 按Controller上的@ApiOrder注解对Swagger Tag排序
     */
    @Bean
    public OpenApiCustomizer openApiCustomizer(@Lazy ApplicationContext ctx) {
        return openApi -> {
            Map<String, Integer> tagOrderMap = buildTagOrderMap(ctx);
            log.info("=== Swagger Tag Order Map: {} ===", tagOrderMap);

            // springdoc 3.x: openApi.getTags() 为空，需要从Paths中收集Tag
            List<io.swagger.v3.oas.models.tags.Tag> allTags = collectTagsFromPaths(openApi);
            log.info("=== Collected Tags: {} ===",
                    allTags.stream().map(io.swagger.v3.oas.models.tags.Tag::getName).collect(Collectors.toList()));

            // 按@ApiOrder排序
            allTags.sort(Comparator.comparingInt(
                    t -> tagOrderMap.getOrDefault(t.getName(), 9999)
            ));

            openApi.tags(allTags);
        };
    }

    /**
     * 从OpenAPI的Paths中收集所有用到的Tag（去重）
     */
    private List<io.swagger.v3.oas.models.tags.Tag> collectTagsFromPaths(OpenAPI openApi) {
        Set<String> tagNameSet = new LinkedHashSet<>();
        if (openApi.getPaths() != null) {
            for (PathItem pathItem : openApi.getPaths().values()) {
                for (Operation op : pathItem.readOperations()) {
                    if (op.getTags() != null) {
                        tagNameSet.addAll(op.getTags());
                    }
                }
            }
        }
        return tagNameSet.stream()
                .map(name -> new io.swagger.v3.oas.models.tags.Tag().name(name))
                .collect(Collectors.toList());
    }

    /**
     * 扫描所有带@RestController和@Tag的类，读取@ApiOrder值
     */
    private Map<String, Integer> buildTagOrderMap(ApplicationContext ctx) {
        Map<String, Integer> orderMap = new ConcurrentHashMap<>();
        try {
            String[] beanNames = ctx.getBeanNamesForAnnotation(RestController.class);
            for (String beanName : beanNames) {
                Object bean = ctx.getBean(beanName);
                Class<?> clazz = bean.getClass();
                // 处理CGLIB/JDK代理，获取原始类
                while (clazz.getName().contains("$$") || clazz.getName().contains("Proxy")) {
                    Class<?> superClazz = clazz.getSuperclass();
                    if (superClazz != null && !superClazz.equals(Object.class)) {
                        clazz = superClazz;
                    } else {
                        break;
                    }
                }

                ApiOrder apiOrder = AnnotationUtils.findAnnotation(clazz, ApiOrder.class);
                Tag tag = AnnotationUtils.findAnnotation(clazz, Tag.class);

                if (tag != null && apiOrder != null) {
                    orderMap.put(tag.name(), apiOrder.value());
                    log.info("Found ApiOrder: {} -> {}", tag.name(), apiOrder.value());
                }
            }
        } catch (Exception e) {
            log.warn("Failed to build tag order map: {}", e.getMessage());
        }
        return orderMap;
    }

    private Info apiInfo() {
        return new Info()
                .title("大疆机场操控系统")
                .description("api文档")
                .version("5.x");
    }

    private List<SecurityRequirement> security() {
        SecurityRequirement key = new SecurityRequirement();
        key.addList(Constant.TOKEN_HEADER, Constant.TOKEN_HEADER);

        List<SecurityRequirement> list = new ArrayList<>();
        list.add(key);
        return list;
    }
}
