package cn.novalon.gym.manage.gateway.metrics;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 网关指标收集器
 * 
 * 文件定义：收集和暴露网关自定义指标
 * 涉及业务：请求统计、错误统计、性能监控
 * 
 * 指标类型：
 * 1. Counter：计数器，用于统计请求总数、错误总数等
 * 2. Gauge：仪表盘，用于统计当前值，如活跃连接数
 * 3. Timer：计时器，用于统计请求耗时
 * 
 * @author 张翔
 * @date 2026-03-26
 */
@Component
public class GatewayMetrics {

    private static final Logger logger = LoggerFactory.getLogger(GatewayMetrics.class);

    private final MeterRegistry meterRegistry;
    
    private final Counter totalRequestsCounter;
    private final Counter successRequestsCounter;
    private final Counter failedRequestsCounter;
    private final Counter rateLimitedRequestsCounter;
    private final Counter circuitBreakerOpenCounter;
    private final Counter unauthorizedRequestsCounter;
    
    private final AtomicLong activeConnections = new AtomicLong(0);
    private final ConcurrentHashMap<String, AtomicLong> pathRequestCounts = new ConcurrentHashMap<>();

    public GatewayMetrics(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;

        this.totalRequestsCounter = Counter.builder("gateway.requests.total")
                .description("Total number of gateway requests")
                .register(meterRegistry);

        this.successRequestsCounter = Counter.builder("gateway.requests.success")
                .description("Number of successful gateway requests")
                .register(meterRegistry);

        this.failedRequestsCounter = Counter.builder("gateway.requests.failed")
                .description("Number of failed gateway requests")
                .register(meterRegistry);

        this.rateLimitedRequestsCounter = Counter.builder("gateway.requests.rate_limited")
                .description("Number of rate limited requests")
                .register(meterRegistry);

        this.circuitBreakerOpenCounter = Counter.builder("gateway.circuit_breaker.open")
                .description("Number of circuit breaker open events")
                .register(meterRegistry);

        this.unauthorizedRequestsCounter = Counter.builder("gateway.requests.unauthorized")
                .description("Number of unauthorized requests")
                .register(meterRegistry);

        Gauge.builder("gateway.connections.active", activeConnections, AtomicLong::get)
                .description("Number of active connections")
                .register(meterRegistry);

        logger.info("Gateway metrics initialized");
    }

    public void incrementTotalRequests() {
        totalRequestsCounter.increment();
    }

    public void incrementSuccessRequests() {
        successRequestsCounter.increment();
    }

    public void incrementFailedRequests() {
        failedRequestsCounter.increment();
    }

    public void incrementRateLimitedRequests() {
        rateLimitedRequestsCounter.increment();
    }

    public void incrementCircuitBreakerOpen() {
        circuitBreakerOpenCounter.increment();
    }

    public void incrementUnauthorizedRequests() {
        unauthorizedRequestsCounter.increment();
    }

    public void incrementActiveConnections() {
        activeConnections.incrementAndGet();
    }

    public void decrementActiveConnections() {
        activeConnections.decrementAndGet();
    }

    public void recordRequestDuration(String path, Duration duration) {
        Timer.builder("gateway.request.duration")
                .description("Request duration")
                .tag("path", path)
                .register(meterRegistry)
                .record(duration);

        pathRequestCounts.computeIfAbsent(path, k -> {
            AtomicLong counter = new AtomicLong(0);
            Gauge.builder("gateway.path.requests", counter, AtomicLong::get)
                    .description("Number of requests per path")
                    .tag("path", path)
                    .register(meterRegistry);
            return counter;
        }).incrementAndGet();
    }

    public void recordCustomMetric(String name, double value, String... tags) {
        Counter.builder(name)
                .tags(tags)
                .register(meterRegistry)
                .increment(value);
    }

    public long getTotalRequests() {
        return (long) totalRequestsCounter.count();
    }

    public long getSuccessRequests() {
        return (long) successRequestsCounter.count();
    }

    public long getFailedRequests() {
        return (long) failedRequestsCounter.count();
    }

    public long getActiveConnections() {
        return activeConnections.get();
    }
}
