using Atomx.Admin.Models;
using Microsoft.Extensions.Options;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace Atomx.Admin.Middlewares
{
    public class MonitoringMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<MonitoringMiddleware> _logger;
        private readonly MonitoringOptions _options;

        public MonitoringMiddleware(RequestDelegate next, ILogger<MonitoringMiddleware> logger, IOptions<MonitoringOptions> options)
        {
            _next = next;
            _logger = logger;
            _options = options.Value;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            // 检查是否应该跳过监控
            if (ShouldSkipMonitoring(context))
            {
                await _next(context);
                return;
            }

            var logInfo = new
            {
                Path = context.Request.Path,
                Method = context.Request.Method,
                StartTime = DateTime.UtcNow,
            };

            _logger.LogInformation($"API 请求监控：{logInfo}");
            var stopwatch = Stopwatch.StartNew();
            var startTime = DateTime.UtcNow;

            try
            {
                await _next(context);
            }
            finally
            {
                stopwatch.Stop();


                var logData = new
                {
                    Path = context.Request.Path,
                    Method = context.Request.Method,
                    StatusCode = context.Response.StatusCode,
                    EndTime = DateTime.UtcNow,
                    UserAgent = context.Request.Headers.UserAgent.ToString(),
                    ClientIP = context.Connection.RemoteIpAddress?.ToString()
                };

                // 详细日志，包含更多上下文信息
                if (stopwatch.ElapsedMilliseconds > _options.SlowRequestThresholdMs)
                {
                    _logger.LogWarning("API 响应监控: 慢API,响应时间{@ResponseTime}ms,超阈值 {@ThresholdMs}ms, {@LogData}", stopwatch.ElapsedMilliseconds, _options.SlowRequestThresholdMs, logData);
                }
                else
                {
                    _logger.LogInformation("API 响应监控: 响应时间{@ResponseTime}ms: {@LogData}", stopwatch.ElapsedMilliseconds, logData);
                }
            }
        }

        private bool ShouldSkipMonitoring(HttpContext context)
        {
            var path = context.Request.Path.ToString();
            var method = context.Request.Method;

            // 检查健康检查端点
            if (_options.ExcludeHealthChecks && IsHealthCheckEndpoint(path))
                return true;

            // 检查精确匹配的忽略路径
            if (_options.ExactExcludePaths?.Any(p =>
                p.Path.Equals(path, StringComparison.OrdinalIgnoreCase) &&
                (string.IsNullOrEmpty(p.Method) || p.Method.Equals(method, StringComparison.OrdinalIgnoreCase))) == true)
            {
                return true;
            }

            // 检查通配符忽略路径
            if (_options.WildcardExcludePaths?.Any(p =>
                PathMatchesPattern(path, p.Path) &&
                (string.IsNullOrEmpty(p.Method) || p.Method.Equals(method, StringComparison.OrdinalIgnoreCase))) == true)
            {
                return true;
            }

            // 检查包含路径（如果设置了包含列表）
            if (_options.IncludePaths?.Any() == true)
            {
                return !_options.IncludePaths.Any(p =>
                    PathMatchesPattern(path, p.Path) &&
                    (string.IsNullOrEmpty(p.Method) || p.Method.Equals(method, StringComparison.OrdinalIgnoreCase)));
            }

            return false;
        }

        private bool PathMatchesPattern(string path, string pattern)
        {
            if (pattern.Contains('*'))
            {
                var regexPattern = "^" + Regex.Escape(pattern).Replace("\\*", ".*") + "$";
                return Regex.IsMatch(path, regexPattern, RegexOptions.IgnoreCase);
            }
            return path.Equals(pattern, StringComparison.OrdinalIgnoreCase);
        }

        private bool IsHealthCheckEndpoint(string path)
        {
            return path.Contains("/health") || path.Contains("/ready") || path.Contains("/live");
        }
    }
}