using FsCheck;
using FsCheck.Xunit;
using HoneyBox.Admin.Business.Attributes;
using HoneyBox.Admin.Business.Controllers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Routing;
using System.Reflection;
using Xunit;

namespace HoneyBox.Tests.Services;

/// <summary>
/// 权限验证属性测试
/// Property 18: Authentication Enforcement - 所有业务控制器方法都需要认证
/// Property 19: Permission Enforcement - 所有业务控制器方法都有权限标记
/// </summary>
public class PermissionPropertyTests
{
    private static readonly Type[] BusinessControllerTypes = new[]
    {
        typeof(ConfigController),
        typeof(UserController),
        typeof(VipController),
        typeof(GoodsController),
        typeof(PrizesController),
        typeof(GoodsTypesController),
        typeof(OrderController),
        typeof(FinanceController),
        typeof(DashboardController)
    };

    /// <summary>
    /// Property 18: 所有业务控制器都继承自 BusinessControllerBase
    /// 验证所有业务控制器都有统一的基类，确保认证机制一致
    /// </summary>
    [Fact]
    public void Property18_AllBusinessControllers_InheritFromBusinessControllerBase()
    {
        foreach (var controllerType in BusinessControllerTypes)
        {
            Assert.True(
                typeof(BusinessControllerBase).IsAssignableFrom(controllerType),
                $"{controllerType.Name} should inherit from BusinessControllerBase"
            );
        }
    }

    /// <summary>
    /// Property 18: 所有业务控制器都有 Route 特性
    /// 验证所有业务控制器都有正确的路由配置
    /// </summary>
    [Fact]
    public void Property18_AllBusinessControllers_HaveRouteAttribute()
    {
        foreach (var controllerType in BusinessControllerTypes)
        {
            var routeAttr = controllerType.GetCustomAttribute<RouteAttribute>();
            Assert.NotNull(routeAttr);
            Assert.StartsWith("api/admin/business", routeAttr.Template);
        }
    }

    /// <summary>
    /// Property 19: 所有公开的 Action 方法都有 BusinessPermission 特性
    /// 验证权限控制的完整性
    /// </summary>
    [Fact]
    public void Property19_AllPublicActions_HaveBusinessPermissionAttribute()
    {
        var exceptions = new List<string>
        {
            "ConfigController.GetConfigKeys" // 获取配置键列表不需要权限
        };

        foreach (var controllerType in BusinessControllerTypes)
        {
            var actionMethods = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
                .Where(m => m.GetCustomAttributes().Any(a => a is HttpMethodAttribute))
                .ToList();

            foreach (var method in actionMethods)
            {
                var fullName = $"{controllerType.Name}.{method.Name}";
                if (exceptions.Contains(fullName))
                    continue;

                var permissionAttr = method.GetCustomAttribute<BusinessPermissionAttribute>();
                Assert.NotNull(permissionAttr);
                Assert.False(string.IsNullOrEmpty(permissionAttr.PermissionCode),
                    $"{fullName} should have a non-empty permission code");
            }
        }
    }

    /// <summary>
    /// Property 19: 权限编码格式正确 (module:action)
    /// </summary>
    [Fact]
    public void Property19_PermissionCodes_HaveCorrectFormat()
    {
        var allPermissionCodes = new HashSet<string>();

        foreach (var controllerType in BusinessControllerTypes)
        {
            var actionMethods = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
                .Where(m => m.GetCustomAttributes().Any(a => a is HttpMethodAttribute));

            foreach (var method in actionMethods)
            {
                var permissionAttr = method.GetCustomAttribute<BusinessPermissionAttribute>();
                if (permissionAttr != null)
                {
                    allPermissionCodes.Add(permissionAttr.PermissionCode);
                }
            }
        }

        foreach (var code in allPermissionCodes)
        {
            // 权限编码格式: module:action
            Assert.Matches(@"^[a-z]+:[a-z_]+$", code);
            
            var parts = code.Split(':');
            Assert.Equal(2, parts.Length);
            Assert.False(string.IsNullOrEmpty(parts[0]), $"Module part of {code} should not be empty");
            Assert.False(string.IsNullOrEmpty(parts[1]), $"Action part of {code} should not be empty");
        }
    }

    /// <summary>
    /// Property 19: 验证所有预期的权限编码都已使用
    /// </summary>
    [Fact]
    public void Property19_AllExpectedPermissionCodes_AreUsed()
    {
        var expectedPermissions = new HashSet<string>
        {
            // 配置模块
            "config:view", "config:edit",
            // 用户模块
            "user:list", "user:view", "user:money", "user:status", "user:test", "user:clear", "user:gift",
            // VIP模块
            "vip:list", "vip:edit",
            // 商品模块
            "goods:list", "goods:view", "goods:add", "goods:edit", "goods:delete", "goods:status",
            // 订单模块
            "order:list", "order:view", "order:ship", "order:export",
            // 财务模块
            "finance:view",
            // 仪表盘模块
            "dashboard:view", "dashboard:edit"
        };

        var actualPermissions = new HashSet<string>();

        foreach (var controllerType in BusinessControllerTypes)
        {
            var actionMethods = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
                .Where(m => m.GetCustomAttributes().Any(a => a is HttpMethodAttribute));

            foreach (var method in actionMethods)
            {
                var permissionAttr = method.GetCustomAttribute<BusinessPermissionAttribute>();
                if (permissionAttr != null)
                {
                    actualPermissions.Add(permissionAttr.PermissionCode);
                }
            }
        }

        // 验证所有预期的权限都被使用
        foreach (var expected in expectedPermissions)
        {
            Assert.Contains(expected, actualPermissions);
        }
    }

    /// <summary>
    /// Property 19: 同一模块的权限应该有一致的前缀
    /// </summary>
    [Fact]
    public void Property19_PermissionCodes_HaveConsistentModulePrefix()
    {
        var controllerPermissions = new Dictionary<string, HashSet<string>>
        {
            { "ConfigController", new HashSet<string> { "config" } },
            { "UserController", new HashSet<string> { "user" } },
            { "VipController", new HashSet<string> { "vip" } },
            { "GoodsController", new HashSet<string> { "goods" } },
            { "PrizesController", new HashSet<string> { "goods" } }, // 奖品属于商品模块
            { "GoodsTypesController", new HashSet<string> { "goods" } }, // 商品类型属于商品模块
            { "OrderController", new HashSet<string> { "order" } },
            { "FinanceController", new HashSet<string> { "finance" } },
            { "DashboardController", new HashSet<string> { "dashboard" } }
        };

        foreach (var controllerType in BusinessControllerTypes)
        {
            var expectedModules = controllerPermissions[controllerType.Name];
            
            var actionMethods = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
                .Where(m => m.GetCustomAttributes().Any(a => a is HttpMethodAttribute));

            foreach (var method in actionMethods)
            {
                var permissionAttr = method.GetCustomAttribute<BusinessPermissionAttribute>();
                if (permissionAttr != null)
                {
                    var module = permissionAttr.PermissionCode.Split(':')[0];
                    Assert.Contains(module, expectedModules);
                }
            }
        }
    }
}
