package com.liquidnet.common.swagger.service;

import com.liquidnet.common.swagger.annotation.ApiLevel;
import com.liquidnet.common.swagger.dto.ApiLevelStatisticsDto;
import com.liquidnet.common.swagger.dto.MultiServiceStatisticsDto;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.lang.reflect.Method;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 多服务接口分级统计服务（合并了本地和远程统计功能）
 * 
 * @author system
 * @since 2024-10-29
 */
@Service
@Slf4j
public class MultiServiceApiLevelStatisticsService {
    
    private final ApplicationContext applicationContext;
    private final RestTemplate restTemplate;
    
    @Value("${liquidnet.info.context:/}")
    private String contextPath;
    
    @Value("${liquidnet.services.adam.url:http://localhost:9001}")
    private String adamServiceUrl;
    
    @Value("${liquidnet.services.kylin.urlxxx:http://localhost:9002}")
    private String kylinServiceUrl;
    
    @Value("${liquidnet.services.candy.urlxxx:http://localhost:9009}")
    private String candyServiceUrl;
    
    @Value("${liquidnet.services.order.urlxxx:http://localhost:9004}")
    private String orderServiceUrl;
    
    @Value("${liquidnet.services.names:adam,kylin,candy,order}")
    private String[] serviceNames;
    
    public MultiServiceApiLevelStatisticsService(ApplicationContext applicationContext, RestTemplateBuilder restTemplateBuilder) {
        this.applicationContext = applicationContext;
        this.restTemplate = restTemplateBuilder
                .setConnectTimeout(Duration.ofSeconds(5))
                .setReadTimeout(Duration.ofSeconds(10))
                .build();
    }
    
    /**
     * 获取本服务的接口分级统计信息
     */
    public ApiLevelStatisticsDto getLocalServiceStatistics() {
        List<ApiLevelStatisticsDto.ApiInfo> apiInfoList = new ArrayList<>();
        
        // 获取所有Controller
        Map<String, Object> controllers = applicationContext.getBeansWithAnnotation(RestController.class);
        controllers.putAll(applicationContext.getBeansWithAnnotation(Controller.class));
        
        for (Map.Entry<String, Object> entry : controllers.entrySet()) {
            Object controller = entry.getValue();
            Class<?> controllerClass = controller.getClass();
            
            // 跳过代理类
            if (controllerClass.getName().contains("$")) {
                controllerClass = controllerClass.getSuperclass();
            }
            
            // 过滤掉系统Controller
            if (isSystemController(controllerClass)) {
                continue;
            }
            
            // 获取服务名称
            String serviceName = getServiceName();
            
            // 获取类级别的ApiLevel注解
            ApiLevel classApiLevel = controllerClass.getAnnotation(ApiLevel.class);
            
            // 遍历所有方法
            Method[] methods = controllerClass.getDeclaredMethods();
            for (Method method : methods) {
                if (isApiMethod(method)) {
                    ApiLevelStatisticsDto.ApiInfo apiInfo = buildApiInfo(method, controllerClass, serviceName, classApiLevel);
                    if (apiInfo != null) {
                        apiInfoList.add(apiInfo);
                    }
                }
            }
        }
        
        // 构建统计结果
        ApiLevelStatisticsDto statisticsDto = new ApiLevelStatisticsDto();
        statisticsDto.setTotalCount(apiInfoList.size());
        statisticsDto.setLevelStatistics(calculateLevelStatistics(apiInfoList));
        statisticsDto.setApisByLevel(calculateLevelApiList(apiInfoList));
        
        return statisticsDto;
    }
    
    /**
     * 判断是否为系统Controller
     */
    private boolean isSystemController(Class<?> controllerClass) {
        String className = controllerClass.getName();
        String simpleName = controllerClass.getSimpleName();
        
        // 过滤掉系统自带的Controller
        return className.contains("ApiResourceController") ||
               className.contains("BasicErrorController") ||
               simpleName.equals("ApiResourceController") ||
               simpleName.equals("BasicErrorController") ||
               // 过滤掉接口分级统计相关的Controller
               simpleName.equals("ApiLevelStatisticsController") ||
               className.contains("com.liquidnet.common.swagger.controller") ||
               // 过滤掉Spring Boot Actuator相关的Controller
               className.contains("org.springframework.boot.actuate") ||
               // 过滤掉Spring Security相关的Controller
               className.contains("org.springframework.security") ||
               // 过滤掉其他框架的Controller
               className.contains("springfox.documentation") ||
               className.contains("com.github.xiaoymin.knife4j");
    }
    
    /**
     * 判断是否为API方法
     */
    private boolean isApiMethod(Method method) {
        return method.isAnnotationPresent(RequestMapping.class) ||
               method.isAnnotationPresent(GetMapping.class) ||
               method.isAnnotationPresent(PostMapping.class) ||
               method.isAnnotationPresent(PutMapping.class) ||
               method.isAnnotationPresent(DeleteMapping.class) ||
               method.isAnnotationPresent(PatchMapping.class);
    }
    
    /**
     * 获取服务名称
     */
    private String getServiceName() {
        if (contextPath != null && !contextPath.isEmpty() && !"/".equals(contextPath)) {
            // 去除前后的斜杠
            String serviceName = contextPath;
            if (serviceName.startsWith("/")) {
                serviceName = serviceName.substring(1);
            }
            if (serviceName.endsWith("/")) {
                serviceName = serviceName.substring(0, serviceName.length() - 1);
            }
            return serviceName;
        }
        return "unknown-service";
    }
    
    /**
     * 构建API信息
     */
    private ApiLevelStatisticsDto.ApiInfo buildApiInfo(Method method, Class<?> controllerClass, 
                                                      String serviceName, ApiLevel classApiLevel) {
        ApiLevelStatisticsDto.ApiInfo apiInfo = new ApiLevelStatisticsDto.ApiInfo();
        
        // 获取方法级别的ApiLevel注解
        ApiLevel methodApiLevel = method.getAnnotation(ApiLevel.class);
        ApiLevel effectiveApiLevel = methodApiLevel != null ? methodApiLevel : classApiLevel;
        
        // 如果没有ApiLevel注解，使用L99表示未配置
        if (effectiveApiLevel == null) {
            ApiLevel.Level unconfiguredLevel = ApiLevel.Level.L99;
            apiInfo.setLevel(unconfiguredLevel);
            apiInfo.setDescription(unconfiguredLevel.getDesc()); // 使用枚举中的描述
        } else {
            // 所有配置的级别都是正常的分级
            apiInfo.setLevel(effectiveApiLevel.level());
            apiInfo.setDescription(effectiveApiLevel.description());
        }
        
        // 设置基本信息
        apiInfo.setServiceName(serviceName);
        apiInfo.setControllerName(controllerClass.getSimpleName());
        apiInfo.setMethodName(method.getName());
        apiInfo.setUrl(getApiUrl(method, controllerClass));
        apiInfo.setHttpMethod(getHttpMethod(method));
        
        // 获取API描述
        ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
        if (apiOperation != null) {
            apiInfo.setApiDescription(apiOperation.value());
        }
        
        return apiInfo;
    }
    
    /**
     * 获取API URL
     */
    private String getApiUrl(Method method, Class<?> controllerClass) {
        StringBuilder url = new StringBuilder();
        
        // 获取类级别的RequestMapping
        RequestMapping classMapping = controllerClass.getAnnotation(RequestMapping.class);
        if (classMapping != null && classMapping.value().length > 0) {
            url.append(classMapping.value()[0]);
        }
        
        // 获取方法级别的映射
        String methodPath = getMethodPath(method);
        if (methodPath != null && !methodPath.isEmpty()) {
            if (!url.toString().endsWith("/") && !methodPath.startsWith("/")) {
                url.append("/");
            }
            url.append(methodPath);
        }
        
        return url.toString();
    }
    
    /**
     * 获取方法路径
     */
    private String getMethodPath(Method method) {
        if (method.isAnnotationPresent(RequestMapping.class)) {
            RequestMapping mapping = method.getAnnotation(RequestMapping.class);
            return mapping.value().length > 0 ? mapping.value()[0] : "";
        }
        if (method.isAnnotationPresent(GetMapping.class)) {
            GetMapping mapping = method.getAnnotation(GetMapping.class);
            return mapping.value().length > 0 ? mapping.value()[0] : "";
        }
        if (method.isAnnotationPresent(PostMapping.class)) {
            PostMapping mapping = method.getAnnotation(PostMapping.class);
            return mapping.value().length > 0 ? mapping.value()[0] : "";
        }
        if (method.isAnnotationPresent(PutMapping.class)) {
            PutMapping mapping = method.getAnnotation(PutMapping.class);
            return mapping.value().length > 0 ? mapping.value()[0] : "";
        }
        if (method.isAnnotationPresent(DeleteMapping.class)) {
            DeleteMapping mapping = method.getAnnotation(DeleteMapping.class);
            return mapping.value().length > 0 ? mapping.value()[0] : "";
        }
        if (method.isAnnotationPresent(PatchMapping.class)) {
            PatchMapping mapping = method.getAnnotation(PatchMapping.class);
            return mapping.value().length > 0 ? mapping.value()[0] : "";
        }
        return "";
    }
    
    /**
     * 获取HTTP方法
     */
    private String getHttpMethod(Method method) {
        if (method.isAnnotationPresent(GetMapping.class)) return "GET";
        if (method.isAnnotationPresent(PostMapping.class)) return "POST";
        if (method.isAnnotationPresent(PutMapping.class)) return "PUT";
        if (method.isAnnotationPresent(DeleteMapping.class)) return "DELETE";
        if (method.isAnnotationPresent(PatchMapping.class)) return "PATCH";
        
        if (method.isAnnotationPresent(RequestMapping.class)) {
            RequestMapping mapping = method.getAnnotation(RequestMapping.class);
            if (mapping.method().length > 0) {
                return mapping.method()[0].name();
            }
        }
        return "GET";
    }
    
    /**
     * 获取所有服务的接口分级统计信息
     */
    public MultiServiceStatisticsDto getAllServicesStatistics() {
        MultiServiceStatisticsDto result = new MultiServiceStatisticsDto();
        List<MultiServiceStatisticsDto.ServiceStatistics> serviceStatisticsList = new ArrayList<>();
        List<ApiLevelStatisticsDto.ApiInfo> allApiInfoList = new ArrayList<>();
        
        // 获取服务健康状态
        Map<String, Boolean> healthStatus = getServicesHealth();
        result.setServiceHealth(healthStatus);
        
        // 获取所有配置的服务统计
        Map<String, String> serviceUrlMap = getServiceUrlMap();
        for (String serviceName : serviceNames) {
            String serviceUrl = serviceUrlMap.get(serviceName);
            if (serviceUrl != null) {
                MultiServiceStatisticsDto.ServiceStatistics serviceStats = new MultiServiceStatisticsDto.ServiceStatistics();
                serviceStats.setServiceName(serviceName);
                serviceStats.setIsHealthy(healthStatus.getOrDefault(serviceName, false));
                
                // 获取单个服务的统计数据
                ApiLevelStatisticsDto singleServiceStats = getRemoteServiceStatistics(serviceName, serviceUrl);
                if (singleServiceStats != null) {
                    serviceStats.setStatistics(singleServiceStats);
                    serviceStatisticsList.add(serviceStats);
                    
                    // 从apisByLevel中收集所有接口用于汇总统计
                    if (singleServiceStats.getApisByLevel() != null) {
                        for (List<ApiLevelStatisticsDto.ApiInfo> apiInfos : singleServiceStats.getApisByLevel().values()) {
                            allApiInfoList.addAll(apiInfos);
                        }
                    }
                } else {
                    // 服务不可用时也要显示
                    serviceStats.setStatistics(new ApiLevelStatisticsDto());
                    serviceStatisticsList.add(serviceStats);
                }
            }
        }
        
        // 设置各服务统计
        result.setServiceStatistics(serviceStatisticsList);
        
        // 计算汇总统计
        result.setTotalCount(allApiInfoList.size());
        result.setTotalLevelStatistics(calculateLevelStatistics(allApiInfoList));
        
        log.info("获取所有服务统计完成，总接口数量: {}，健康服务数: {}/{}", 
                allApiInfoList.size(), 
                healthStatus.values().stream().mapToInt(v -> v ? 1 : 0).sum(),
                healthStatus.size());
        
        return result;
    }
    
    /**
     * 获取服务URL映射（动态从serviceNames生成）
     */
    private Map<String, String> getServiceUrlMap() {
        Map<String, String> serviceUrlMap = new HashMap<>();
        
        for (String serviceName : serviceNames) {
            try {
                // 动态获取对应的URL字段：serviceName + "ServiceUrl"
                String fieldName = serviceName + "ServiceUrl";
                java.lang.reflect.Field field = this.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                String serviceUrl = (String) field.get(this);
                serviceUrlMap.put(serviceName, serviceUrl);
            } catch (Exception e) {
                log.warn("无法获取服务{}的URL配置，跳过该服务", serviceName);
            }
        }
        
        return serviceUrlMap;
    }
    
    /**
     * 获取远程服务的统计信息
     */
    private ApiLevelStatisticsDto getRemoteServiceStatistics(String serviceName, String serviceUrl) {
        try {
            // 构建完整URL：域名 + context路径 + 接口路径
            // 使用/service接口，现在它返回ApiLevelStatisticsDto结构
            String url = serviceUrl + "/" + serviceName + "/levelStatistics/service";
            ApiLevelStatisticsDto remoteStats = restTemplate.getForObject(url, ApiLevelStatisticsDto.class);
            
            if (remoteStats != null) {
                return remoteStats;
            }
        } catch (Exception e) {
            log.warn("获取{}服务统计信息失败: {}", serviceName, e.getMessage());
        }
        
        return null;
    }
    
    /**
     * 计算级别统计
     */
    private Map<String, Integer> calculateLevelStatistics(List<ApiLevelStatisticsDto.ApiInfo> apiList) {
        // 统计实际数据，现在所有级别都在枚举中
        Map<String, Integer> actualStats = apiList.stream()
                .collect(Collectors.groupingBy(
                        api -> api.getLevel().name(),
                        Collectors.collectingAndThen(Collectors.counting(), Math::toIntExact)
                ));
        
        // 动态获取所有配置的级别，确保所有级别都显示
        Map<String, Integer> completeStats = new LinkedHashMap<>();
        
        // 遍历枚举中定义的所有级别（包括L99）
        for (ApiLevel.Level level : ApiLevel.Level.values()) {
            completeStats.put(level.name(), actualStats.getOrDefault(level.name(), 0));
        }
        
        return completeStats;
    }
    
    /**
     * 计算服务统计
     */
    private Map<String, List<ApiLevelStatisticsDto.ApiInfo>> calculateLevelApiList(List<ApiLevelStatisticsDto.ApiInfo> apiList) {
        // 按级别分组的接口列表 - 动态初始化所有级别
        Map<String, List<ApiLevelStatisticsDto.ApiInfo>> apisByLevel = new HashMap<>();
        for (ApiLevel.Level level : ApiLevel.Level.values()) {
            apisByLevel.put(level.name(), new ArrayList<>());
        }

        // 将接口按级别分组
        for (ApiLevelStatisticsDto.ApiInfo api : apiList) {
            String levelKey = api.getLevel().name();
            apisByLevel.get(levelKey).add(api);
        }

        return apisByLevel;
    }
    
    /**
     * 获取服务健康状态
     */
    public Map<String, Boolean> getServicesHealth() {
        Map<String, Boolean> healthStatus = new HashMap<>();
        Map<String, String> serviceUrlMap = getServiceUrlMap();
        
        for (String serviceName : serviceNames) {
            String serviceUrl = serviceUrlMap.get(serviceName);
            if (serviceUrl != null) {
                healthStatus.put(serviceName, checkServiceHealth(serviceName, serviceUrl));
            }
        }
        
        return healthStatus;
    }
    
    /**
     * 检查服务健康状态
     */
    private boolean checkServiceHealth(String serviceName, String serviceUrl) {
        try {
            // 构建完整URL：域名 + context路径 + 接口路径
            String url = serviceUrl + "/" + serviceName + "/levelStatistics/levels";
            restTemplate.getForObject(url, Object.class);
            return true;
        } catch (Exception e) {
            log.debug("服务{}健康检查失败: {}", serviceName, e.getMessage());
            return false;
        }
    }
}