@namespace Oqtane.Modules.Controls
@inherits ModuleControlBase
@inject IRoleService RoleService
@inject IUserService UserService

@if (_permissions != null)
{
    <br />
    <table class="table" style="width: 50%; min-width: 250px;">
        <tbody>
            <tr>
                <th scope="col">Role</th>
                @foreach (PermissionString permission in _permissions)
                {
                    <th style="text-align: center; width: 1px;">@permission.PermissionName</th>
                }
            </tr>
            @foreach (Role role in _roles)
            {
                <tr>
                    <td>@role.Name</td>
                    @foreach (PermissionString permission in _permissions)
                    {
                        var p = permission;
                        <td style="text-align: center;">
                            <TriStateCheckBox Value=@GetPermissionValue(p.Permissions, role.Name) Disabled=@GetPermissionDisabled(role.Name) OnChange="@(e => PermissionChanged(e, p.PermissionName, role.Name))" />
                        </td>
                    }
                </tr>
            }
        </tbody>
    </table>
    @if (_users.Count != 0)
    {
        <table class="table" style="width: 50%; min-width: 250px;">
            <thead>
                <tr>
                    <th scope="col">User</th>
                    @foreach (PermissionString permission in _permissions)
                    {
                        <th style="text-align: center; width: 1px;">@permission.PermissionName</th>
                    }
                </tr>
            </thead>
            <tbody>
                @foreach (User user in _users)
                {
                    string userid = "[" + user.UserId.ToString() + "]";
                    <tr>
                        <td>@user.DisplayName</td>
                        @foreach (PermissionString permission in _permissions)
                        {
                            var p = permission;
                            <td style="text-align: center; width: 1px;">
                                <TriStateCheckBox Value=@GetPermissionValue(p.Permissions, userid) Disabled=false OnChange="@(e => PermissionChanged(e, p.PermissionName, userid))" />
                            </td>
                        }
                    </tr>
                }
            </tbody>
        </table>
    }
    <table class="table" style="width: 50%; min-width: 250px;">
        <tbody>
            <tr>
                <td class="input-group">
                    <input type="text" name="Username" class="form-control" placeholder="Enter Username" @bind="@_username" />
                    <button type="button" class="btn btn-primary" @onclick="AddUser">Add</button>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    <ModuleMessage Type="MessageType.Error" Message="@_message" />
}

@code {
    private string _permissionnames = string.Empty;
    private List<Role> _roles;
    private List<PermissionString> _permissions;
    private List<User> _users = new List<User>();
    private string _username = string.Empty;
    private string _message = string.Empty;

    [Parameter]
    public string EntityName { get; set; }

    [Parameter]
    public string PermissionNames { get; set; }

    [Parameter]
    public string Permissions { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (string.IsNullOrEmpty(PermissionNames))
        {
            _permissionnames = Shared.PermissionNames.View + "," + Shared.PermissionNames.Edit;
        }
        else
        {
            _permissionnames = PermissionNames;
        }

        _roles = await RoleService.GetRolesAsync(ModuleState.SiteId);
        _roles.Insert(0, new Role { Name = Constants.AllUsersRole });

        _permissions = new List<PermissionString>();

        foreach (string permissionname in _permissionnames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            // initialize with admin role
            _permissions.Add(new PermissionString { PermissionName = permissionname, Permissions = Constants.AdminRole });
        }

        if (!string.IsNullOrEmpty(Permissions))
        {
            // populate permissions
            foreach (PermissionString permissionstring in UserSecurity.GetPermissionStrings(Permissions))
            {
                if (_permissions.Find(item => item.PermissionName == permissionstring.PermissionName) != null)
                {
                    _permissions[_permissions.FindIndex(item => item.PermissionName == permissionstring.PermissionName)].Permissions = permissionstring.Permissions;
                }

                if (permissionstring.Permissions.Contains("["))
                {
                    foreach (string user in permissionstring.Permissions.Split(new char[] { '[' }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        if (user.Contains("]"))
                        {
                            var userid = int.Parse(user.Substring(0, user.IndexOf("]")));
                            if (_users.Where(item => item.UserId == userid).FirstOrDefault() == null)
                            {
                                _users.Add(await UserService.GetUserAsync(userid, ModuleState.SiteId));
                            }
                        }
                    }
                }
            }
        }
    }

    private bool? GetPermissionValue(string permissions, string securityKey)
    {
        if ((";" + permissions + ";").Contains(";" + "!" + securityKey + ";"))
        {
            return false; // deny permission
        }
        else
        {
            if ((";" + permissions + ";").Contains(";" + securityKey + ";"))
            {
                return true; // grant permission
            }
            else
            {
                return null; // not specified
            }
        }
    }

    private bool GetPermissionDisabled(string roleName)
        => roleName == Constants.AdminRole
            ? true
            : false;

    private async Task AddUser()
    {
        if (_users.Where(item => item.Username == _username).FirstOrDefault() == null)
        {
            try
            {
                var user = await UserService.GetUserAsync(_username, ModuleState.SiteId);
                if (user != null)
                {
                    _users.Add(user);
                }
            }
            catch
            {
                _message = "Username Does Not Exist";
            }
        }

        _username = string.Empty;
    }

    private void PermissionChanged(bool? value, string permissionName, string securityId)
    {
        var selected = value;
        var permission = _permissions.Find(item => item.PermissionName == permissionName);
        if (permission != null)
        {
            var ids = permission.Permissions.Split(';').ToList();

            ids.Remove(securityId); // remove grant permission
            ids.Remove("!" + securityId); // remove deny permission

            switch (selected)
            {
                case true:
                    ids.Add(securityId); // add grant permission
                    break;
                case false:
                    ids.Add("!" + securityId); // add deny permission
                    break;
                case null:
                    break; // permission not specified
            }

            _permissions[_permissions.FindIndex(item => item.PermissionName == permissionName)].Permissions = string.Join(";", ids.ToArray());
        }
    }

    public string GetPermissions()
    {
        ValidatePermissions();
        return UserSecurity.SetPermissionStrings(_permissions);
    }

    private void ValidatePermissions()
    {
        PermissionString permission;
        for (int i = 0; i < _permissions.Count; i++)
        {
            permission = _permissions[i];
            List<string> ids = permission.Permissions.Split(';').ToList();
            ids.Remove("!" + Constants.AllUsersRole); // remove deny all users
            ids.Remove("!" + Constants.RegisteredRole); // remove deny registered users
            permission.Permissions = string.Join(";", ids.ToArray());
            _permissions[i] = permission;
        }
    }
}
