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

namespace RpgRoller.Components.Pages;

[ExcludeFromCodeCoverage]
public sealed class WorkspaceCampaignCoordinator(
    WorkspaceState state,
    WorkspaceFeedbackService feedback,
    IJSRuntime js,
    RpgRollerApiClient apiClient,
    Func<Task> loadKnownUsernamesAsync,
    Func<Guid?, Task> reloadCampaignsAsync,
    Func<Task> reloadCharacterCampaignOptionsAsync,
    Func<Task> refreshCampaignScopeAsync,
    Func<Task> syncStateEventsAsync,
    Func<Task> requestRefreshAsync)
{
    public async Task OnCampaignSelectionChangedAsync(ChangeEventArgs args)
    {
        if (!Guid.TryParse(args.Value?.ToString(), out var campaignId))
            return;

        state.SelectedCampaignId = campaignId;
        await js.InvokeVoidAsync("rpgRollerApi.setSessionValue", CampaignSessionKey, campaignId.ToString());
        await refreshCampaignScopeAsync();
        await syncStateEventsAsync();
        state.IsScreenMenuOpen = false;
    }

    public async Task OnCampaignCreatedAsync(Guid campaignId)
    {
        await reloadCampaignsAsync(campaignId);
        await reloadCharacterCampaignOptionsAsync();
        await refreshCampaignScopeAsync();
        await syncStateEventsAsync();
        feedback.SetStatus("Campaign created.", false);
        await requestRefreshAsync();
    }

    public void OpenCreateCharacterModal()
    {
        state.CreateCharacterInitialModel = new()
        {
            Name = string.Empty,
            CampaignId = state.SelectedCampaignId?.ToString() ??
                         state.CharacterCampaignOptions.FirstOrDefault()?.Id.ToString() ?? string.Empty,
            OwnerUsername = string.Empty
        };

        state.CreateCharacterFormVersion += 1;
        state.CanEditCharacterOwner = false;
        state.ShowCreateCharacterModal = true;
    }

    public async Task OpenEditCharacterModal(CharacterSummary character)
    {
        if (state.IsCurrentUserGm || state.IsCurrentUserAdmin)
            await loadKnownUsernamesAsync();

        state.EditingCharacterId = character.Id;
        state.EditCharacterInitialModel = new()
        {
            Name = character.Name,
            CampaignId = character.CampaignId?.ToString() ?? string.Empty,
            OwnerUsername = string.Empty
        };

        state.EditCharacterFormVersion += 1;
        state.CanEditCharacterOwner = state.IsCurrentUserGm || state.IsCurrentUserAdmin;
        state.ShowEditCharacterModal = true;
    }

    public void CloseCharacterModals()
    {
        state.ShowCreateCharacterModal = false;
        state.ShowEditCharacterModal = false;
        state.CanEditCharacterOwner = false;
        state.EditingCharacterId = null;
    }

    public async Task OnCharacterCreatedAsync(Guid? campaignId)
    {
        CloseCharacterModals();
        await reloadCampaignsAsync(campaignId);
        await reloadCharacterCampaignOptionsAsync();
        await refreshCampaignScopeAsync();
        await syncStateEventsAsync();
        feedback.SetStatus("Character created.", false);
        await requestRefreshAsync();
    }

    public async Task OnCharacterUpdatedAsync(Guid? campaignId)
    {
        CloseCharacterModals();
        await reloadCampaignsAsync(campaignId);
        await reloadCharacterCampaignOptionsAsync();
        await refreshCampaignScopeAsync();
        await syncStateEventsAsync();
        feedback.SetStatus(campaignId.HasValue ? "Character updated." : "Character unlinked from campaign.", false);
        await requestRefreshAsync();
    }

    public async Task DeleteSelectedCampaignAsync()
    {
        if (state.SelectedCampaign is null || state.IsMutating || !state.CanDeleteSelectedCampaign)
            return;

        var confirmed = await js.InvokeAsync<bool>("confirm", $"Delete campaign '{state.SelectedCampaign.Name}'?");
        if (!confirmed)
            return;

        state.IsMutating = true;
        try
        {
            _ = await apiClient.RequestAsync<bool>("DELETE", $"/api/campaigns/{state.SelectedCampaign.Id}");
            await reloadCampaignsAsync(null);
            await reloadCharacterCampaignOptionsAsync();
            await refreshCampaignScopeAsync();
            await syncStateEventsAsync();
            feedback.SetStatus("Campaign deleted.", false);
        }
        catch (ApiRequestException ex)
        {
            feedback.SetStatus(ex.Message, true);
        }
        finally
        {
            state.IsMutating = false;
            await requestRefreshAsync();
        }
    }

    public async Task DeleteCharacterAsync(CharacterSummary character)
    {
        if (state.IsMutating || !CanDeleteCharacter(character))
            return;

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

        state.IsMutating = true;
        try
        {
            _ = await apiClient.RequestAsync<bool>("DELETE", $"/api/characters/{character.Id}");
            await reloadCampaignsAsync(state.SelectedCampaignId);
            await reloadCharacterCampaignOptionsAsync();
            await refreshCampaignScopeAsync();
            await syncStateEventsAsync();
            feedback.SetStatus("Character deleted.", false);
        }
        catch (ApiRequestException ex)
        {
            feedback.SetStatus(ex.Message, true);
        }
        finally
        {
            state.IsMutating = false;
            await requestRefreshAsync();
        }
    }

    public bool CanEditCharacter(CharacterSummary character)
    {
        return state.User is not null &&
               (character.OwnerUserId == state.User.Id || state.IsCurrentUserGm || state.IsCurrentUserAdmin);
    }

    public bool CanDeleteCharacter(CharacterSummary character)
    {
        return state.User is not null && (character.OwnerUserId == state.User.Id || state.IsCurrentUserAdmin);
    }

    private const string CampaignSessionKey = "campaign";
}