using Insight.Infrastructure.Services;
using Insight.Web.Constants;
using Insight.Web.Models;
using Insight.Web.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.JSInterop;
using MongoDB.Driver;
using MudBlazor;
using Vaitr.MemoryBus;
using static Insight.Web.Constants.Events.Chat;

namespace Insight.Web.Components.Dialogs;

public partial class ChatDialog
{
    [Inject] private IMemoryBus Bus { get; init; } = default!;
    [Inject] private ChatService ChatService { get; init; } = default!;
    [Inject] private SessionPool SessionCache { get; init; } = default!;
    [Inject] private SessionHandler SessionHandler { get; init; } = default!;
    [Inject] private IdentityService IdentityService { get; init; } = default!;
    [Inject] private AuthenticationStateProvider AuthenticationStateProvider { get; init; } = default!;
    [Inject] private IMongoDatabase Database { get; init; } = default!;
    [Inject] private IJSRuntime JSRuntime { get; init; } = default!;
    [Inject] private ISnackbar Snackbar { get; init; } = default!;
    [Inject] private ILogger<ChatDialog> Logger { get; init; } = default!;

    private int _newMessages;
    public int NewMessages
    {
        get
        {
            return _newMessages;
        }
        set
        {
            if (value != _newMessages)
            {
                _newMessages = value;
                //Bus.Publish(Events.Sessions.Changed); // test, bugt hölle
            }
        }
    }

    private enum Content { Contacts, Chat }
    private Content _content = Content.Contacts;

    private ChatUser? _currentUser;
    private ChatSession? _currentSession;
    private string? _currentMessage;

    private readonly List<IDisposable> _subscriptions = new();

    protected override async Task OnInitializedAsync()
    {
        _subscriptions.Add(Bus.SubscribeAsync<ChatUserConnected>(UserConnected, p => p.User.Uid != SessionHandler.State.Uid));
        _subscriptions.Add(Bus.SubscribeAsync<ChatUserDisconnected>(UserDisconnected, p => p.User.Uid != SessionHandler.State.Uid));
        _subscriptions.Add(Bus.SubscribeAsync<ChatRefresh>(RefreshAsync, null));
        _subscriptions.Add(Bus.SubscribeAsync<ChatMessageReceived>(MessageReceived, p => p.Message.SenderId != SessionHandler.State.Uid));
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {

        }
        else
        {
            _currentUser = ChatService.Users.FirstOrDefault(p => p.Key.Uid == SessionHandler.State.Uid).Key;

            if (_content == Content.Chat)
            {
                await JSRuntime.InvokeAsync<string>("ScrollToBottom", "chatContainer");

                // mock
                NewMessages = 0;
            }
        }
    }

    private async Task GetSessionAsync(ChatUser user)
    {
        var members = new List<ChatUser>() { _currentUser, user };
        var session = await ChatService.AddOrGetSession(members);

        _currentSession = session;

        _content = Content.Chat;
        await InvokeAsync(StateHasChanged);
    }

    private async Task SendAsync()
    {
        if (_currentSession is null || string.IsNullOrWhiteSpace(_currentMessage)) return;

        await _currentSession.SendMessage(_currentUser, _currentMessage, default);
        _currentMessage = string.Empty;

        await InvokeAsync(StateHasChanged);

        //await JSRuntime.InvokeAsync<string>("ScrollToBottom", "chatContainer");
    }

    private async ValueTask UserConnected(ChatUserConnected model, CancellationToken cancellationToken)
    {
        try
        {
            Notification.Information(Snackbar, $"{model.User.Username} Online", options =>
            {
                //options.Onclick = (x) => null;
                options.HideIcon = true;
                options.ShowCloseIcon = false;
                options.RequireInteraction = false;
                options.ShowTransitionDuration = 0;
                options.HideTransitionDuration = 1000;
                options.VisibleStateDuration = 10000;
            });

            _ = JSRuntime.InvokeAsync<string>("PlayAudio", "chat_user_online");
        }
        catch (Exception ex)
        {
            Logger.LogError(ex.Message);
        }
    }

    private async ValueTask UserDisconnected(ChatUserDisconnected model, CancellationToken cancellationToken)
    {
        try
        {
            Notification.Information(Snackbar, $"{model.User.Username} Offline", options =>
            {
                //options.Onclick = (x) => null;
                options.HideIcon = true;
                options.ShowCloseIcon = false;
                options.RequireInteraction = false;
                options.ShowTransitionDuration = 0;
                options.HideTransitionDuration = 1000;
                options.VisibleStateDuration = 10000;
            });

            _ = JSRuntime.InvokeAsync<string>("PlayAudio", "chat_user_online");
        }
        catch (Exception ex)
        {
            Logger.LogError(ex.Message);
        }
    }

    private async ValueTask RefreshAsync(ChatRefresh model, CancellationToken cancellationToken)
    {
        _ = InvokeAsync(StateHasChanged);
    }

    private async ValueTask MessageReceived(ChatMessageReceived model, CancellationToken cancellationToken)
    {
        try
        {
            Notification.Information(Snackbar, $"New message from: {model.Session.Members.FirstOrDefault(p => p.Uid == model.Message.SenderId)?.Username}", options =>
            {
                options.Onclick = (x) => OpenSpecificChatWindow(model.Session);
                options.HideIcon = true;
                options.ShowCloseIcon = true;
                options.RequireInteraction = true;
                options.ShowTransitionDuration = 0;
                options.HideTransitionDuration = 0;
                options.VisibleStateDuration = 10000;
                options.DuplicatesBehavior = SnackbarDuplicatesBehavior.Prevent;
            });

            // mock
            NewMessages++;

            if (_content != Content.Chat)
            {
                _ = JSRuntime.InvokeAsync<string>("PlayAudio", "chat_message");
            }

            _ = InvokeAsync(StateHasChanged);
        }
        catch (Exception ex)
        {
            Logger.LogError(ex.ToString());
        }
    }

    private async Task OpenSpecificChatWindow(ChatSession session)
    {
        _currentSession = session;
        _content = Content.Chat;
        _visible = true;

        await InvokeAsync(StateHasChanged);
    }
}