using FJPSite.Attributes;
using FJPSite.Data;
using FJPSite.Data.Authorisation;
using FJPSite.Data.Identity;
using FJPSite.Enums;
using Microsoft.Build.Framework;

namespace FJPSite.Factories.EntitySeeders;

[SeedMigration("20260409123724_CreatePermissions")]
public class PermissionSeederFactory : EntitySeederFactory
{
    private struct FeatureActionLink
    {
        public FeatureEnum linkFeature { get; set; }
        public IList<ActionEnum> linkActions { get; set; }
    }

    private void SeedModules(ApplicationDbContext context)
    {
        foreach (var moduleName in Enum.GetNames(typeof(ModuleEnum)))
        {
            if (context.Modules.FirstOrDefault(m => m.Name == moduleName) == null)
            {
                context.Modules.Add(new Module { Name = moduleName, IsActive = true });
            }
        }
        context.SaveChanges();
    }

    private void SeedFeatures(ApplicationDbContext context)
    {
        foreach (var featureName in Enum.GetNames(typeof(FeatureEnum)))
        {
            if (context.Features.FirstOrDefault(m => m.Name == featureName) == null)
            {
                context.Features.Add(new Feature { Name = featureName });
            }
        }
        context.SaveChanges();
    }

    private void SeedActions(ApplicationDbContext context)
    {
        foreach (var actionName in Enum.GetNames(typeof(ActionEnum)))
        {
            if (context.Actions.FirstOrDefault(m => m.Name == actionName) == null)
            {
                context.Actions.Add(new PermissionAction { Name = actionName });
            }
        }
        context.SaveChanges();
    }

    private void SeedModuleFeatures(ApplicationDbContext context)
    {
        Dictionary<ModuleEnum, IList<FeatureEnum>> moduleFeatureList = new Dictionary<ModuleEnum, IList<FeatureEnum>>
        {
            {ModuleEnum.Authentication, new List<FeatureEnum>{FeatureEnum.Permissions, FeatureEnum.Users} },
            {ModuleEnum.Funerals, new List<FeatureEnum>{FeatureEnum.Funerals} },
            {ModuleEnum.Site, new List<FeatureEnum>{FeatureEnum.Settings, FeatureEnum.Pages} }
        };

        foreach (var module in moduleFeatureList)
        {
            var moduleEntity = context.Modules.First(f => f.Name == Enum.GetName(module.Key));
            foreach (var feature in module.Value)
            {
                var featureEntity = context.Features.First(f => f.Name == Enum.GetName(feature));
                if (context.ModuleFeatures.FirstOrDefault(f => f.ModuleId == moduleEntity.Id && f.FeatureId == featureEntity.Id) == null)
                {
                    context.ModuleFeatures.Add(new ModuleFeature
                    {
                        ModuleId = moduleEntity.Id,
                        FeatureId = featureEntity.Id,
                    });
                }
            }
        }
        context.SaveChanges();
    }

    private void SeedFeatureAction(ApplicationDbContext context)
    {
        Dictionary<FeatureEnum, IList<ActionEnum>> featureActionList = new Dictionary<FeatureEnum, IList<ActionEnum>>
        {
            {FeatureEnum.Permissions, new List<ActionEnum>{ActionEnum.View, ActionEnum.Assign } },
            {FeatureEnum.Roles, new List<ActionEnum>{ ActionEnum.View, ActionEnum.Assign} },
            {FeatureEnum.Pages, new List<ActionEnum>{ ActionEnum.View, ActionEnum.Create, ActionEnum.Edit, ActionEnum.Delete } },
            {FeatureEnum.Users, new List<ActionEnum>{ ActionEnum.View, ActionEnum.Create, ActionEnum.Edit, ActionEnum.Delete } },
            {FeatureEnum.Settings, new List<ActionEnum>{ ActionEnum.View, ActionEnum.Edit } },
            {FeatureEnum.Funerals, new List<ActionEnum>{ ActionEnum.View, ActionEnum.Create, ActionEnum.Edit, ActionEnum.Delete } },
        };

        foreach (var feature in featureActionList)
        {
            var featureEntity = context.Features.First(f => f.Name == Enum.GetName(feature.Key));
            foreach (var action in feature.Value)
            {
                var actionEntity = context.Actions.First(f => f.Name == Enum.GetName(action));
                if (context.FeatureActions.FirstOrDefault(f => f.FeatureId == featureEntity.Id && f.ActionId == actionEntity.Id) == null)
                {
                    context.FeatureActions.Add(new FeatureAction
                    {
                        ActionId = actionEntity.Id,
                        FeatureId = featureEntity.Id,
                    });
                }
            }
        }

        context.SaveChanges();
    }

    private void SeedRolePermission(ApplicationDbContext context)
    {
        Dictionary<RoleEnum, IList<FeatureActionLink>> rolePermissions = new Dictionary<RoleEnum, IList<FeatureActionLink>>
        {
            { RoleEnum.Admin, new List<FeatureActionLink> 
                {
                    new FeatureActionLink {linkFeature = FeatureEnum.Permissions, linkActions = new List<ActionEnum> { ActionEnum.View, ActionEnum.Assign } },
                    new FeatureActionLink {linkFeature = FeatureEnum.Roles, linkActions = new List<ActionEnum> { ActionEnum.View, ActionEnum.Assign } },
                    new FeatureActionLink {linkFeature = FeatureEnum.Pages, linkActions = new List<ActionEnum>{ ActionEnum.View, ActionEnum.Create, ActionEnum.Edit, ActionEnum.Delete } },
                    new FeatureActionLink {linkFeature = FeatureEnum.Users, linkActions = new List<ActionEnum>{ ActionEnum.View, ActionEnum.Create, ActionEnum.Edit, ActionEnum.Delete } },
                    new FeatureActionLink {linkFeature = FeatureEnum.Settings, linkActions = new List<ActionEnum>{ ActionEnum.View, ActionEnum.Edit } },
                    new FeatureActionLink {linkFeature = FeatureEnum.Funerals, linkActions = new List<ActionEnum>{ ActionEnum.View, ActionEnum.Create, ActionEnum.Edit, ActionEnum.Delete } },
                }
            },
            { RoleEnum.Director, new List<FeatureActionLink>
                {
                    new FeatureActionLink {linkFeature = FeatureEnum.Funerals, linkActions = new List<ActionEnum>{ ActionEnum.View, ActionEnum.Create, ActionEnum.Edit, ActionEnum.Delete } },
                }
            },
            { RoleEnum.User, new List<FeatureActionLink>
                {
                    new FeatureActionLink {linkFeature = FeatureEnum.Funerals, linkActions = new List<ActionEnum>{ ActionEnum.View, ActionEnum.Create } },
                }
            },
        };

        foreach (var roleFeatures in rolePermissions)
        {
            var roleEntity = context.Roles.First(f => f.Name == Enum.GetName(roleFeatures.Key));
            foreach (var feature in roleFeatures.Value)
            {
                var featureEntity = context.Features.First(f => f.Name == Enum.GetName(feature.linkFeature));
                foreach (var action in feature.linkActions)
                {
                    var actionEntity = context.Actions.First(f => f.Name == Enum.GetName(action));
                    var featureActionEntity = context.FeatureActions.First(f => f.FeatureId == featureEntity.Id && f.ActionId == actionEntity.Id);
                    if (context.RolePermissions.FirstOrDefault(f => f.RoleId == roleEntity.Id && f.FeatureActionId == featureActionEntity.Id) == null)
                    {
                        context.RolePermissions.Add(new RolePermission
                        {
                            FeatureActionId = featureActionEntity.Id,
                            RoleId = roleEntity.Id
                        });
                    }
                }
            }
        }
        context.SaveChanges();
    }

    public override void Seed(ApplicationDbContext context)
    {
        SeedModules(context);
        SeedFeatures(context);
        SeedActions(context);
        SeedModuleFeatures(context);
        SeedFeatureAction(context);
        SeedRolePermission(context);
    }
}
