@page "/server/{ServerUuid}/{Route?}"
@using Task = System.Threading.Tasks.Task
@using Moonlight.App.Repositories.Servers
@using Microsoft.EntityFrameworkCore
@using Moonlight.App.Database.Entities
@using Moonlight.App.Events
@using Moonlight.App.Helpers
@using Moonlight.App.Helpers.Wings
@using Moonlight.App.Helpers.Wings.Enums
@using Moonlight.App.Plugin.UI
@using Moonlight.App.Plugin.UI.Servers
@using Moonlight.App.Repositories
@using Moonlight.App.Services
@using Moonlight.App.Services.Plugins
@using Moonlight.App.Services.Sessions
@using Moonlight.Shared.Components.Xterm
@using Moonlight.Shared.Views.Server.Settings
@using Newtonsoft.Json

@inject ImageRepository ImageRepository
@inject ServerRepository ServerRepository
@inject WingsConsoleHelper WingsConsoleHelper
@inject EventSystem Event
@inject ServerService ServerService
@inject NavigationManager NavigationManager
@inject DynamicBackgroundService DynamicBackgroundService
@inject SmartTranslateService SmartTranslateService
@inject IdentityService IdentityService
@inject PluginService PluginService

@implements IDisposable

<LazyLoader Load="Load">
    @if (CurrentServer == null)
    {
        <NotFoundAlert/>
    }
    else
    {
        if (NodeOnline)
        {
            if (Console != null && Console.ConsoleState == ConsoleState.Connected)
            {
                if (Console.ServerState == ServerState.Installing || CurrentServer.Installing)
                {
                    <div class="card">
                        <div class="card-body">
                            <div class="fs-2hx fw-bold text-gray-800 text-center mb-5">
                                <TL>Server installation is currently running</TL>
                            </div>
                            <div class="rounded bg-black p-3">
                                <Terminal @ref="InstallConsole"></Terminal>
                            </div>
                        </div>
                    </div>
                }
                else if (CurrentServer.IsArchived)
                {
                    <div class="d-flex justify-content-center flex-center">
                        <div class="card">
                            <img src="/assets/media/svg/archive.svg" class="card-img-top w-50 mx-auto pt-5" alt="Not found image"/>
                            <div class="card-body text-center">
                                <h1 class="card-title">
                                    <TL>Server is currently archived</TL>
                                </h1>
                                <p class="card-text fs-4">
                                    <TL>This server is archived. The data of this server is stored as a backup. To restore click the unarchive button an be patient</TL>
                                </p>

                                <WButton Text="@(SmartTranslateService.Translate("Unarchive"))"
                                         WorkingText="@(SmartTranslateService.Translate("Please wait"))"
                                         CssClasses="btn-primary"
                                         OnClick="UnArchive">
                                </WButton>
                            </div>
                        </div>
                    </div>
                }
                else
                {
                    <CascadingValue Value="Console">
                        <CascadingValue Value="CurrentServer">
                            <CascadingValue Value="Tags">
                                <CascadingValue Value="Context">
                                    <SmartRouter Route="@Route">
                                        @foreach (var tab in Context.Tabs)
                                        {
                                            <Route Path="@(tab.Route)">
                                                <ServerNavigation Route="@(tab.Route)">
                                                    @(tab.Component)
                                                </ServerNavigation>
                                            </Route>
                                        }
                                    </SmartRouter>
                                </CascadingValue>
                            </CascadingValue>
                        </CascadingValue>
                    </CascadingValue>
                }
            }
            else
            {
                <div class="d-flex justify-content-center flex-center">
                    <div class="card">
                        <div class="card-body text-center">
                            <h1 class="card-title">
                                <TL>Connecting</TL>
                            </h1>
                            <p class="card-text fs-4">
                                <TL>Connecting to the servers console to stream logs and the current resource usage</TL>
                            </p>
                        </div>
                    </div>
                </div>
            }
        }
        else
        {
            <div class="d-flex justify-content-center flex-center">
                <div class="card">
                    <img src="/assets/media/svg/serverdown.svg" class="card-img-top w-50 mx-auto pt-5" alt="Not found image"/>
                    <div class="card-body text-center">
                        <h1 class="card-title">
                            <TL>Node offline</TL>
                        </h1>
                        <p class="card-text fs-4">
                            <TL>The node the server is running on is currently offline</TL>
                        </p>
                    </div>
                </div>
            </div>
        }
    }
</LazyLoader>

@code
{

    [Parameter]
    public string ServerUuid { get; set; }

    [Parameter]
    public string? Route { get; set; }

    private WingsConsole? Console;
    private Server? CurrentServer;
    private bool NodeOnline = false;
    private NodeAllocation NodeAllocation;
    private string[] Tags;

    private Terminal? InstallConsole;

    private ServerPageContext Context;

    protected override void OnInitialized()
    {
        Console = new();

        Console.OnConsoleStateUpdated += (_, _) => { InvokeAsync(StateHasChanged); };
        Console.OnResourceUpdated += (_, _) => { InvokeAsync(StateHasChanged); };
        Console.OnServerStateUpdated += (_, _) => { InvokeAsync(StateHasChanged); };

        Console.OnRequestNewToken += async _ => await WingsConsoleHelper.GenerateToken(CurrentServer!);

        Console.OnMessage += async (_, s) =>
        {
            if (Console.ServerState == ServerState.Installing && InstallConsole != null)
            {
                if (s.IsInternal)
                    await InstallConsole.WriteLine("\x1b[38;5;16;48;5;135m\x1b[39m\x1b[1m Moonlight \x1b[0m " + s.Content + "\x1b[0m");
                else
                    await InstallConsole.WriteLine(s.Content);
            }
        };
    }

    private async Task Load(LazyLoader lazyLoader)
    {
        await lazyLoader.SetText("Requesting server data");

        if (!Guid.TryParse(ServerUuid, out var uuid))
            return;

        CurrentServer = ServerRepository
            .Get()
            .Include(x => x.Allocations)
            .Include(x => x.Image)
            .ThenInclude(x => x.Variables)
            .Include(x => x.Node)
            .Include(x => x.Variables)
            .Include(x => x.MainAllocation)
            .Include(x => x.Owner)
            .FirstOrDefault(x => x.Uuid == uuid);

        if (CurrentServer != null)
        {
            if (CurrentServer.Owner.Id != IdentityService.User.Id && !IdentityService.User.Admin)
            {
                CurrentServer = null;
                return;
            }

            if (string.IsNullOrEmpty(CurrentServer.Image.BackgroundImageUrl))
                await DynamicBackgroundService.Reset();
            else
                await DynamicBackgroundService.Change(CurrentServer.Image.BackgroundImageUrl);

            await lazyLoader.SetText("Checking node online status");

            NodeOnline = await ServerService.IsHostUp(CurrentServer);

            if (!NodeOnline)
                return;

            await lazyLoader.SetText("Checking server variables");

    // Live variable migration

            foreach (var variable in CurrentServer.Image.Variables)
            {
                if (CurrentServer.Variables.All(x => x.Key != variable.Key))
                {
                    CurrentServer.Variables.Add(new ServerVariable()
                    {
                        Key = variable.Key,
                        Value = variable.DefaultValue
                    });

                    ServerRepository.Update(CurrentServer);
                }
            }

    // Tags

            await lazyLoader.SetText("Reading tags");

            Tags = JsonConvert.DeserializeObject<string[]>(CurrentServer.Image.TagsJson) ?? Array.Empty<string>();

    // Build server pages and settings

            Context = new ServerPageContext()
            {
                Server = CurrentServer,
                User = IdentityService.User,
                ImageTags = Tags
            };

            Context.Tabs.Add(new()
            {
                Name = "Console",
                Route = "/",
                Icon = "bx-terminal",
                Component = ComponentHelper.FromType(typeof(ServerConsole))
            });

            Context.Tabs.Add(new()
            {
                Name = "Files",
                Route = "/files",
                Icon = "bx-folder",
                Component = ComponentHelper.FromType(typeof(ServerFiles))
            });

            Context.Tabs.Add(new()
            {
                Name = "Backups",
                Route = "/backups",
                Icon = "bx-box",
                Component = ComponentHelper.FromType(typeof(ServerBackups))
            });

            Context.Tabs.Add(new()
            {
                Name = "Network",
                Route = "/network",
                Icon = "bx-wifi",
                Component = ComponentHelper.FromType(typeof(ServerNetwork))
            });

            Context.Tabs.Add(new()
            {
                Name = "Settings",
                Route = "/settings",
                Icon = "bx-cog",
                Component = ComponentHelper.FromType(typeof(ServerSettings))
            });
            
            // Add default settings
            
            Context.Settings.Add(new()
            {
                Name = "Rename",
                Component = ComponentHelper.FromType(typeof(ServerRenameSetting))
            });
            
            Context.Settings.Add(new()
            {
                Name = "Reset",
                Component = ComponentHelper.FromType(typeof(ServerResetSetting))
            });
            
            Context.Settings.Add(new()
            {
                Name = "Delete",
                Component = ComponentHelper.FromType(typeof(ServerDeleteSetting))
            });

            Context = await PluginService.BuildServerPage(Context);

            await lazyLoader.SetText("Connecting to console");
            await ReconnectConsole();

    // Register event system

            await Event.On<Server>($"server.{CurrentServer.Uuid}.installComplete", this, server =>
            {
                NavigationManager.NavigateTo(NavigationManager.Uri, true);

                return Task.CompletedTask;
            });

            await Event.On<Server>($"server.{CurrentServer.Uuid}.archiveStatusChanged", this, server =>
            {
                NavigationManager.NavigateTo(NavigationManager.Uri, true);

                return Task.CompletedTask;
            });
        }
    }

    private async Task ReconnectConsole()
    {
        await Console!.Disconnect();
        await WingsConsoleHelper.ConnectWings(Console!, CurrentServer!);
    }

    public async void Dispose()
    {
        if (CurrentServer != null)
        {
            await Event.Off($"server.{CurrentServer.Uuid}.installComplete", this);
            await Event.Off($"server.{CurrentServer.Uuid}.archiveStatusChanged", this);
        }

        if (Console != null)
        {
            Console.Dispose();
        }
    }

    private async Task UnArchive()
    {
        await ServerService.UnArchiveServer(CurrentServer!);
    }
}