using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using RpgRoller.Contracts;
using RpgRoller.Domain;

namespace RpgRoller.Components.Pages.HomeControls;

[ExcludeFromCodeCoverage]
public partial class AdminHome
{
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (!firstRender)
            return;

        await InitializeAsync();
        await InvokeAsync(StateHasChanged);
    }

    private async Task InitializeAsync()
    {
        try
        {
            var me = await ApiClient.RequestAsync<MeResponse>("GET", "/api/me");
            CurrentUser = me.User;
            IsCurrentUserAdmin = HasAdminRole(me.User);
            if (!IsCurrentUserAdmin)
                return;

            Users = (await ApiClient.RequestAsync<IReadOnlyList<AdminUserSummary>>("GET", "/api/admin/users")).OrderBy(user => user.Username, StringComparer.OrdinalIgnoreCase).ToList();
        }
        catch (ApiRequestException ex) when (ex.StatusCode == 401)
        {
            await LoggedOut.InvokeAsync("Session expired. Please log in again.");
        }
        catch (ApiRequestException ex)
        {
            SetStatus(ex.Message, true);
        }
        finally
        {
            IsLoading = false;
        }
    }

    private Task OpenPlayAsync()
    {
        return OpenWorkspaceAsync("play");
    }

    private Task OpenCampaignManagementAsync()
    {
        return OpenWorkspaceAsync("management");
    }

    private Task OpenAdminAsync()
    {
        IsScreenMenuOpen = false;
        return Task.CompletedTask;
    }

    private async Task LogoutAsync()
    {
        if (IsMutating)
            return;

        IsMutating = true;
        try
        {
            await ApiClient.RequestWithoutPayloadAsync("POST", "/api/auth/logout");
        }
        catch (ApiRequestException)
        {
        }
        finally
        {
            IsMutating = false;
        }

        await LoggedOut.InvokeAsync("Logged out.");
    }

    private async Task ToggleAdminRoleAsync(AdminUserSummary user)
    {
        if (IsMutating || CurrentUser is null || user.Id == CurrentUser.Id)
            return;

        IsMutating = true;
        try
        {
            IReadOnlyList<string> roles = HasAdminRole(user) ? Array.Empty<string>() : [UserRoles.Admin];
            _ = await ApiClient.RequestAsync<AdminUserSummary>("PUT", $"/api/admin/users/{user.Id}/roles", new UpdateUserRolesRequest(roles));

            await ReloadUsersAsync();
            SetStatus("User roles updated.", false);
        }
        catch (ApiRequestException ex)
        {
            SetStatus(ex.Message, true);
        }
        finally
        {
            IsMutating = false;
        }
    }

    private async Task DeleteUserAsync(AdminUserSummary user)
    {
        if (IsMutating || CurrentUser is null || user.Id == CurrentUser.Id)
            return;

        var confirmed = await JS.InvokeAsync<bool>("confirm", $"Delete user '{user.Username}'?");
        if (!confirmed)
            return;

        IsMutating = true;
        try
        {
            _ = await ApiClient.RequestAsync<bool>("DELETE", $"/api/admin/users/{user.Id}");
            await ReloadUsersAsync();
            SetStatus("User deleted.", false);
        }
        catch (ApiRequestException ex)
        {
            SetStatus(ex.Message, true);
        }
        finally
        {
            IsMutating = false;
        }
    }

    private async Task ReloadUsersAsync()
    {
        Users = (await ApiClient.RequestAsync<IReadOnlyList<AdminUserSummary>>("GET", "/api/admin/users")).OrderBy(user => user.Username, StringComparer.OrdinalIgnoreCase).ToList();
    }

    private static bool HasAdminRole(UserSummary user)
    {
        return user.Roles.Contains(UserRoles.Admin, StringComparer.OrdinalIgnoreCase);
    }

    private static bool HasAdminRole(AdminUserSummary user)
    {
        return user.Roles.Contains(UserRoles.Admin, StringComparer.OrdinalIgnoreCase);
    }

    private void SetStatus(string message, bool isError)
    {
        StatusMessage = message;
        StatusIsError = isError;
    }

    private void ToggleScreenMenu()
    {
        IsScreenMenuOpen = !IsScreenMenuOpen;
    }

    private async Task OpenWorkspaceAsync(string screen)
    {
        IsScreenMenuOpen = false;
        await WorkspaceRequested.InvokeAsync(screen);
    }

    [Inject]
    private RpgRollerApiClient ApiClient { get; set; } = null!;

    [Inject]
    private IJSRuntime JS { get; set; } = null!;

    private bool IsLoading { get; set; } = true;
    private bool IsMutating { get; set; }
    private bool IsScreenMenuOpen { get; set; }
    private bool IsCurrentUserAdmin { get; set; }
    private UserSummary? CurrentUser { get; set; }
    private List<AdminUserSummary> Users { get; set; } = [];
    private string? StatusMessage { get; set; }
    private bool StatusIsError { get; set; }

    private IReadOnlyList<AppHeaderMenuItem> HeaderMenuItems =>
    [
        new()
        {
            Label = "Play",
            IsActive = false,
            OnSelected = OpenPlayAsync
        },
        new()
        {
            Label = "Campaign Management",
            IsActive = false,
            OnSelected = OpenCampaignManagementAsync
        },
        new()
        {
            Label = "Admin",
            IsActive = true,
            OnSelected = OpenAdminAsync
        }
    ];

    [Parameter]
    public EventCallback<string?> LoggedOut { get; set; }

    [Parameter]
    public EventCallback<string> WorkspaceRequested { get; set; }
}