// Copyright © Selmo Technology GmbH. All Rights Reserved

using Microsoft.AspNetCore.Components;
using Radzen;
using SelmoStudio.Hmi.Plugin.Model.RestApi;
using SelmoStudio.Hmi.Plugin.Model.User;
using SelmoStudio.Hmi.Plugin.Services;
using SelmoStudio.Hmi.Server.SelmoHmi.Authentication.Service;
using SelmoStudio.Hmi.Server.SelmoHmi.Shared.Component;
using SelmoStudio.Hmi.Server.SelmoHmi.Shared.WellKnownTypes;
using SelmoStudio.Hmi.Server.Shared.Resources;

namespace SelmoStudio.Hmi.Server.SelmoHmi.UserManagement.Pages
{
    public partial class UserManagementView
    {
        [Inject]
        private IAuthenticationStateService _authenticationStateService { get; set; }

        [Inject]
        private IPluginAuthenticationService _pluginAuthenticationService { get; set; }

        [Inject]
        private DialogService _dialogService { get; set; }

        private WellKnownContentFlexDirection contentFlexDirection = WellKnownContentFlexDirection.Column;

        private int _checkboxWidth = 20;
        private int _checkboxHeight = 20;

        private string _password;
        private string _passwordConfirmation;
        private string _selectedUserOriginalUsername;

        private string _validationMessage;

        private bool _addingNewUserMode;
        private bool _userNameChangeIsDisabled => GetUserNameChangeDisabledStatus();
        private bool _saveIsDisabled => GetSaveButtonDisabledStatus();
        private bool _deleteIsDisabled => GetDeleteButtonDisabledStatus();

        private UserSettings _selectedUser;

        private IList<UserSettings> _users = new List<UserSettings>();
        private IList<UserPermission> _userPermissions = new List<UserPermission>();

        private string _currentUserName;

        protected override async Task OnInitializedAsync()
        {
            _selectedUser = GetNewUser();
            await LoadUsersAsync();
            LoadPermissions();

            await base.OnInitializedAsync();
        }

        private bool GetSaveButtonDisabledStatus()
        {
            return string.IsNullOrEmpty(_selectedUser?.Username) || string.IsNullOrEmpty(_selectedUser.Email)
                || (_addingNewUserMode && (string.IsNullOrEmpty(_password) || string.IsNullOrEmpty(_passwordConfirmation)));
        }

        private bool GetDeleteButtonDisabledStatus()
        {
            return GetUserNameChangeDisabledStatus() || _addingNewUserMode;
        }

        private bool GetUserNameChangeDisabledStatus()
        {
            return _selectedUser.Username.Equals(_currentUserName);
        }

        private async Task LoadUsersAsync(UserSettings? userToSelect = null)
        {
            _users = await _pluginAuthenticationService.InternalGetAll();
            SetSelectedUser(userToSelect ?? _users.FirstOrDefault() ?? GetNewUser());
            SetAddingNewUserModeStatus(false);

            await UpdateCurrentUser();
        }

        private void SetSelectedUser(UserSettings user)
        {
            _selectedUser = user;
            _selectedUserOriginalUsername = _selectedUser.Username;
        }

        private void LoadPermissions()
        {
            _userPermissions = WellKnownPermissions.KnownPermissions.ToList();
        }

        private async Task New()
        {
            ResetValidationMessage();

            SetSelectedUser(GetNewUser());
        }

        private void ResetPasswordFields()
        {
            _password = string.Empty;
            _passwordConfirmation = string.Empty;
        }

        private UserSettings GetNewUser()
        {
            ResetPasswordFields();

            SetAddingNewUserModeStatus(true);

            return new UserSettings()
            {
                Id = new(Guid.NewGuid()),
                Username = string.Empty,
                Password = string.Empty,
                Permissions = new()
            };
        }

        private void UpdatePassword(string value)
        {
            _password = value;
        }

        private void UpdatePasswordConfirmation(string value)
        {
            _passwordConfirmation = value;
        }

        private void SetAddingNewUserModeStatus(bool isMode)
        {
            _addingNewUserMode = isMode;
        }

        private async Task SaveAsync()
        {
            // TODO Use the central Hmi validation
            ResetValidationMessage();

            var result = string.Empty;

            if (NewPasswordDoesNotMatch())
            {
                SetValidationMessage(_localizer[nameof(HmiResource.ValidationNewPasswordDoesNotMatch)]);

                return;
            }

            if (!string.IsNullOrEmpty(_selectedUserOriginalUsername) && await _pluginAuthenticationService
                .InternalExists(_selectedUserOriginalUsername))
            {
                UpdateRequest request = new()
                {
                    OldUsername = _selectedUserOriginalUsername,
                    NewUsername = _selectedUser.Username,
                    Password = _password,
                    Email = _selectedUser.Email,
                    Permissions = _selectedUser.Permissions
                };

                result = await _pluginAuthenticationService.InternalUpdate(request);
            }
            else
            {
                if (UsernameExists)
                {
                    SetValidationMessage(_localizer[nameof(HmiResource.ValidationUsernameExists)]);

                    return;
                }

                if (PasswordIsNotValid())
                {
                    SetValidationMessage(_localizer[nameof(HmiResource.ValidationPasswordNotValid)]);

                    return;
                }

                _selectedUser.Password = _password;

                RegisterRequest request = new()
                {
                    Username = _selectedUser.Username,
                    Password = _selectedUser.Password,
                    Email = _selectedUser.Email,
                    Permissions = _selectedUser.Permissions
                };

                result = await _pluginAuthenticationService.InternalRegister(request);
            }

            var updateSuccess = !string.IsNullOrEmpty(result) && !result.StartsWith("System.ArgumentException")
                   && result.Contains("Succeeded");

            if (!updateSuccess)
            {
                if (result.StartsWith("System.ArgumentException"))
                {
                    SetValidationMessage(result.Substring(0, result.IndexOf("\n")));
                }
                else
                {
                    SetValidationMessage(_localizer[nameof(HmiResource.ValidationUpdateNotSuccessful)]);
                }
            }
            else
            {
                await LoadUsersAsync(_selectedUser);
            }
        }

        private bool UsernameExists =>
            _users.FirstOrDefault(u => u.Username.Equals(_selectedUser.Username) && !u.Id.Equals(_selectedUser.Id)) != null;

        private bool NewPasswordDoesNotMatch()
        {
            if (string.IsNullOrEmpty(_password) && string.IsNullOrEmpty(_passwordConfirmation))
            {
                return false;
            }

            return !_password.Equals(_passwordConfirmation);
        }

        private bool PasswordIsNotValid()
        {
            // TODO Use the central Hmi validation
            return string.IsNullOrEmpty(_password);
        }

        private void SetValidationMessage(string message)
        {
            _validationMessage = message;
        }

        private void ResetValidationMessage()
        {
            _validationMessage = string.Empty;
        }

        private async Task DeleteAsync()
        {
            var result = await _dialogService.Confirm(_localizer[nameof(HmiResource.UserRemovalConfirmationText), _selectedUser.Username],
                _localizer[nameof(HmiResource.UserRemovalConfirmationTitle)], new ConfirmOptions
                {
                    OkButtonText = _localizer[nameof(HmiResource.Yes)],
                    CancelButtonText = _localizer[nameof(HmiResource.No)],
                });

            if (result.HasValue && result.Value)
            {
                ResetValidationMessage();

                var deleteSuccess = await _pluginAuthenticationService.InternalDelete(_selectedUser.Username);

                if (!deleteSuccess)
                {
                    SetValidationMessage(_localizer[nameof(HmiResource.ValidationDeleteNotSuccessful)]);
                }
                else
                {
                    await LoadUsersAsync();
                }
            }
        }

        private void UpdateSelectedUser(object value)
        {
            if (value is UserSettings user)
            {
                ResetValidationMessage();
                ResetPasswordFields();
                SetAddingNewUserModeStatus(false);
                SetSelectedUser(user);
            }
        }

        private bool GetUserPermission(UserPermission userPermission)
        {
            return _selectedUser?.Permissions.FirstOrDefault(p => p.PolicyKey.Equals(userPermission.PolicyKey)) != null;
        }

        private void UpdateUserPermission(UserPermission userPermission, (ComponentEventInfo EventArgs, bool Value) args)
        {
            bool value = args.Value;
            if (value)
            {
                _selectedUser.Permissions.Add(userPermission);
            }
            else
            {
                var permissionToRemove = _selectedUser.Permissions.FirstOrDefault(p => p.PolicyKey.Equals(userPermission.PolicyKey));

                if (permissionToRemove != null)
                {
                    _selectedUser.Permissions.Remove(permissionToRemove);
                }
            }
        }

        private async Task<string> GetLoggedInUserNameAsync()
        {
            var user = await _authenticationStateService.GetCurrentUserAsync();
            return user.Identity?.Name;
        }

        private async Task UpdateCurrentUser()
        {
            if (await _authenticationStateService.IsAuthenticatedAsync())
            {
                _currentUserName = await GetLoggedInUserNameAsync();
            }
        }
    }
}