using Meezi.Core.Enums;
using static Meezi.Core.Authorization.Permission;

namespace Meezi.Core.Authorization;

/// <summary>
/// The authoritative role→capability matrix. Change what a base role can do here
/// and every controller that calls <c>EnsurePermission</c> updates automatically.
/// Owners customise further with custom roles (which override this matrix entirely).
/// </summary>
public static class RolePermissions
{
    /// <summary>Capabilities reserved to the Owner — the rest is the Manager baseline.</summary>
    private static readonly HashSet<Permission> OwnerOnly = new()
    {
        ManageCafeSettings,
        ManageDiscoverProfile,
        ViewBilling,
        ManageBilling,
        CreateBranch,
        EditBranch,
        DeleteBranch,
        ManageRoles,
    };

    private static readonly IReadOnlyDictionary<EmployeeRole, HashSet<Permission>> Matrix =
        new Dictionary<EmployeeRole, HashSet<Permission>>
        {
            [EmployeeRole.Owner] = AllPermissions(),

            // Manager runs the café day to day: everything except the owner-only
            // governance (billing, branches, café identity, role definitions).
            [EmployeeRole.Manager] = AllExcept(OwnerOnly),

            [EmployeeRole.Cashier] = new()
            {
                ViewOrders, ProcessOrders, EditOrder, HandlePayments, UpdateOrderStatus,
                OperateRegister, OpenCashDrawer,
                ViewQueue, ManageQueue,
                ViewTables,
                ViewReservations, CreateReservation, EditReservation,
                ViewMenu,
                ViewCustomers, CreateCustomer,
                ViewCoupons,
            },

            [EmployeeRole.Waiter] = new()
            {
                ViewOrders, ProcessOrders, EditOrder, UpdateOrderStatus,
                ViewTables,
                ViewMenu,
                ViewReservations, CreateReservation, EditReservation,
                ViewQueue, ManageQueue,
            },

            [EmployeeRole.Chef] = new()
            {
                ViewKitchen, UpdateOrderStatus, ViewOrders, ViewMenu,
            },

            [EmployeeRole.Delivery] = new()
            {
                ViewDelivery, HandleDelivery, ViewOrders,
            },
        };

    public static bool Has(EmployeeRole role, Permission permission) =>
        Matrix.TryGetValue(role, out var set) && set.Contains(permission);

    public static IReadOnlySet<Permission> For(EmployeeRole role) =>
        Matrix.TryGetValue(role, out var set) ? set : new HashSet<Permission>();

    /// <summary>True for roles that administer the whole café across all branches.</summary>
    public static bool IsCafeWide(EmployeeRole role) => role == EmployeeRole.Owner;

    private static HashSet<Permission> AllPermissions() =>
        new(Enum.GetValues<Permission>());

    private static HashSet<Permission> AllExcept(HashSet<Permission> excluded) =>
        new(Enum.GetValues<Permission>().Where(p => !excluded.Contains(p)));
}
