@page "/admin/sys/settings"

@using Moonlight.Core.UI.Components.Navigations
@using System.Reflection
@using MoonCore.Services
@using MoonCoreUI.Services
@using MoonCoreUI.Helpers
@using Moonlight.Core.Configuration

@inject ConfigService<CoreConfiguration> ConfigService
@inject ToastService ToastService

@attribute [RequirePermission(9999)]

<AdminSysNavigation Index="1" />

@if (ModelToShow == null)
{
    <IconAlert Title="No resource to show" Icon="bx-x">
        No model found to show. Please refresh the page to go back
    </IconAlert>
}
else
{
    <div class="card mt-5">
        <div class="card-header border-bottom-0">
            @{
                string title;

                if (Path.Length == 0)
                    title = "Configuration";
                else
                {
                    title = "Configuration - " + string.Join(" - ", Path);
                }
            }

            <h3 class="card-title">@(title)</h3>
            <div class="card-toolbar">
                <WButton OnClick="Reload" CssClasses="btn btn-icon btn-warning me-3">
                    <i class="bx bx-sm bx-revision"></i>
                </WButton>
                <WButton OnClick="Save" CssClasses="btn btn-icon btn-success">
                    <i class="bx bx-sm bx-save"></i>
                </WButton>
            </div>
        </div>
    </div>
    
    <Tooltip>
        Changes to these settings are live applied. The save button only make the changes persistently saved to disk
    </Tooltip>
    
    <div class="row mt-5">
        <div class="col-md-3 col-12 mb-5">
            <div class="card card-body">
                @{
                    var props = ModelToShow
                        .GetType()
                        .GetProperties()
                        .Where(x => x.PropertyType.Assembly.FullName!.Contains("Moonlight") && x.PropertyType.IsClass)
                        .ToArray();
                }

                @foreach (var prop in props)
                {
                    <div class="d-flex flex-stack">
                        <div class="d-flex align-items-center flex-row-fluid flex-wrap">
                            <a href="/admin/sys/settings?section=@(Section + "/" + prop.Name)" class="fs-4 text-primary">@(prop.Name)</a>
                        </div>
                    </div>
                }

                @if (Path.Length != 0)
                {
                    <div class="d-flex flex-stack @(props.Length != 0 ? "mt-5" : "")">
                        <div class="d-flex align-items-center flex-row-fluid flex-wrap">
                            <a href="/admin/sys/@(GetBackPath())" class="fs-4 text-primary">Back</a>
                        </div>
                    </div>
                }
            </div>
        </div>
        <div class="col-md-9 col-12">
            <div class="card card-body">
                <div class="row">
                    <LazyLoader @ref="LazyLoader" Load="Load">
                        @foreach (var prop in Properties)
                        {
                            <div class="col-md-6 col-12">
                                @{
                                    var typeToCreate = typeof(AutoProperty<>).MakeGenericType(prop.PropertyType);
                                    var rf = ComponentHelper.FromType(typeToCreate, parameters =>
                                    {
                                        parameters.Add("Data", ModelToShow);
                                        parameters.Add("Property", prop);
                                    });
                                }
                                
                                @rf
                            </div>
                        }
                    </LazyLoader>
                </div>
            </div>
        </div>
    </div>
}

@code
{
    [Parameter]
    [SupplyParameterFromQuery]
    public string? Section { get; set; } = "";

    private object? ModelToShow;
    private PropertyInfo[] Properties = Array.Empty<PropertyInfo>();
    private string[] Path = Array.Empty<string>();

    private LazyLoader? LazyLoader;

    protected override async Task OnParametersSetAsync()
    {
        if (Section != null && Section.StartsWith("/"))
            Section = Section.TrimStart('/');

        Path = Section != null ? Section.Split("/") : Array.Empty<string>();

        ModelToShow = Resolve(ConfigService.Get(), Path, 0);

        if (ModelToShow != null)
        {
            Properties = ModelToShow
                .GetType()
                .GetProperties()
                .Where(x => !x.PropertyType.Assembly.FullName!.Contains("Moonlight"))
                .ToArray();
        }
        else
        {
            Properties = Array.Empty<PropertyInfo>();
        }

        await InvokeAsync(StateHasChanged);

        if (LazyLoader != null)
            await LazyLoader.Reload();
    }

    private string GetBackPath()
    {
        if (Path.Length == 1)
            return "settings";
        else
        {
            var path = string.Join('/', Path.Take(Path.Length - 1)).TrimEnd('/');
            return $"settings?section={path}";
        }
    }

    private object? Resolve(object model, string[] path, int index)
    {
        if (path.Length == 0)
            return model;

        if (path.Length == index)
            return model;

        var prop = model
            .GetType()
            .GetProperties()
            .FirstOrDefault(x => x.PropertyType.Assembly.FullName!.Contains("Moonlight") && x.Name == path[index]);

        if (prop == null)
            return null;

        return Resolve(prop.GetValue(model)!, path, index + 1);
    }

    private Task Load(LazyLoader arg)
    {
        return Task.CompletedTask;
    }

    private async Task Save()
    {
        ConfigService.Save();
        await ToastService.Success("Successfully saved config to disk");
    }

    private async Task Reload()
    {
        ConfigService.Reload();
        await ToastService.Info("Reloaded configuration from disk");
    }
}