@using Vaitr.Bus;
@using Blazored.LocalStorage;
@using Microsoft.AspNetCore.Identity;
@using MongoDB.Driver;
@using Insight.Infrastructure

@inherits LayoutComponentBase
@implements IDisposable

@inject AuthenticationStateProvider AuthenticationStateProvider
@inject IServiceScopeFactory ServiceScopeFactory
@inject ILocalStorageService LocalStorageService
@inject IMongoDatabase Database
@inject Bus Bus

<MudThemeProvider Theme="_currentTheme" IsDarkMode="_darkMode" />
<MudSnackbarProvider />
<MudDialogProvider />

<MudLayout>
    <MudAppBar Elevation="0" Fixed>
        <MudLink Href="@Navigation.Home" Typo="Typo.h6" Underline="Underline.None" Class="mr-4" Style="color: white !important; text-transform:uppercase;">
            @Global.Name
        </MudLink>
        <AuthorizeView>
            <Authorized>
                <MudIconButton OnClick="()=>_drawer?.Toggle()" Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" />
            </Authorized>
        </AuthorizeView>
        <MudSpacer />
        @if (_darkModeSwitch is false)
        {
            <MudIconButton OnClick="@OnDarkModeToggleAsync" Icon="@(_darkMode ? Icons.Material.Filled.Brightness5 : Icons.Material.Filled.Brightness4)" Color="Color.Inherit" />
        }
        <ChatProvider />
        <ProfileProvider />
    </MudAppBar>
    <AuthorizeView>
        <Authorized>
            <CascadingValue Value="RouteValues">
                <DrawerProvider @ref="_drawer" />
            </CascadingValue>
        </Authorized>
    </AuthorizeView>
    <MudMainContent>
        <MudContainer MaxWidth="MaxWidth.ExtraExtraLarge">
            @Body
        </MudContainer>
    </MudMainContent>
</MudLayout>

@code{
    public IReadOnlyDictionary<string, object>? RouteValues { get; set; }

    private MudTheme _currentTheme = Themes.Default();
    private DrawerProvider? _drawer;
    private bool _darkMode;
    private bool _darkModeSwitch;
    private bool _disposed;
    
    protected override void OnParametersSet()
    {
        RouteValues = (Body?.Target as RouteView)?.RouteData.RouteValues;

        base.OnParametersSet();
    }

    protected override async Task OnInitializedAsync()
    {
        await LoadDarkModeAsync();
    }

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

        }

        await Bus.PublishAsync(Events.Layout.Rendered).ConfigureAwait(false);
    }

    private async Task LoadDarkModeAsync()
    {
        // local storage
        var storageDarkMode = await LocalStorageService.GetItemAsync<bool?>("darkmode");
        if (storageDarkMode is bool darkmodeValue) _darkMode = darkmodeValue;

        // database override
        var state = await AuthenticationStateProvider.GetAuthenticationStateAsync();

        if (state?.User.Identity is not null && state.User.Identity.IsAuthenticated)
        {
            using var scope = ServiceScopeFactory.CreateScope();
            var userManager = scope.ServiceProvider.GetRequiredService<UserManager<InsightUser>>();

            if (await userManager.FindByNameAsync(state.User.Identity.Name) is not InsightUser user) return;

            var userPrefs = await Database.UserPreference()
                .Find(p => p.User == user.Id.ToString())
                .FirstOrDefaultAsync();

            if (userPrefs is null) return;

            _darkMode = userPrefs.DarkMode;

            await LocalStorageService.SetItemAsync("darkmode", _darkMode);
        }
    }

    private async Task OnDarkModeToggleAsync()
    {
        // update current
        _darkMode = !_darkMode;

        // update local storage
        await LocalStorageService.SetItemAsync("darkmode", _darkMode);

        // update database
        var state = await AuthenticationStateProvider.GetAuthenticationStateAsync();

        if (state?.User.Identity is not null && state.User.Identity.IsAuthenticated)
        {
            using var scope = ServiceScopeFactory.CreateScope();
            var userManager = scope.ServiceProvider.GetRequiredService<UserManager<InsightUser>>();

            if (await userManager.FindByNameAsync(state.User.Identity.Name) is not InsightUser user) return;

            var date = DateTime.Now;

            var userPrefs = await Database.UserPreference()
                .UpdateOneAsync(p => p.User == user.Id.ToString(), Builders<InsightUserPreferences>.Update
                .SetOnInsert(p => p.User, user.Id.ToString())
                .SetOnInsert(p => p.Insert, date)
                .Set(p => p.Update, date)
                .Set(p => p.DarkMode, _darkMode), new UpdateOptions
                    {
                        IsUpsert = true
                    });
        }

        await InvokeAsync(StateHasChanged);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (_disposed is false) return;
        if (disposing is false) return;

        try
        {

        }
        finally
        {
            _disposed = true;
        }
    }
}