@page "/logs"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using RobotNet.MapShares.Models

@inject IJSRuntime JSRuntime
@inject IHttpClientFactory HttpClientFactory
@inject IConfiguration Configuration
@inject ISnackbar Snackbar

<PageTitle>Logs</PageTitle>

<div class="w-100 h-100 d-flex flex-column">
    <div class="d-flex flex-row align-items-center justify-content-between" style="border-bottom: 1px solid silver">
        <MudTextField Class="mt-1 ms-2" T="string" Value="FilterLog" Adornment="Adornment.End" ValueChanged="OnSearch" AdornmentIcon="@Icons.Material.Filled.Search"
                      IconSize="Size.Medium" Variant="Variant.Outlined" Margin="Margin.Dense" AdornmentColor="Color.Secondary" Label="Search"></MudTextField>
        <MudSpacer />
        <div class="m-1 d-flex flex-row">
            <MudSelect T="LogConfiguration" Label="Proccess" AnchorOrigin="Origin.BottomLeft" @bind-Value="LogProccessSelected" @bind-Value:after="LoadLogs" Variant="Variant.Outlined" Margin="Margin.Dense" Style="width: 200px">
                @foreach (var proccess in LogsProccess)
                {
                    <MudSelectItem Value="@proccess">@proccess.Name</MudSelectItem>
                }
            </MudSelect>
            <MudDatePicker Class="mx-4" Label="Date" Date="DateLog" DateChanged="OnDateChanged" MaxDate="DateTime.Today" Variant="Variant.Outlined" Color="Color.Primary"
                           ShowToolbar="false" Margin="Margin.Dense" AdornmentColor="Color.Primary" />

            <MudTooltip Text="Export">
                <MudFab Class="mt-2" Color="Color.Info" StartIcon="@Icons.Material.Filled.ImportExport" Size="Size.Small" OnClick="ExportLogs" />
            </MudTooltip>
            <MudTooltip Text="Refresh">
                <MudFab Class="mx-4 mt-2" StartIcon="@Icons.Material.Filled.Refresh" Color="Color.Primary" Size="Size.Small" OnClick="LoadLogs" />
            </MudTooltip>
        </div>
    </div>
    <div class="flex-grow-1 mt-2 ms-2" style="background-color: rgba(0, 0, 0, 0);">
        <MudOverlay Visible="IsLoading" DarkBackground="true" Absolute="true">
            <MudProgressCircular Color="Color.Info" Indeterminate="true" />
        </MudOverlay>
        <div class="h-100 w-100 position-relative">
            <div class="log-container" @ref="LogContainerRef">
                @if (ShowRawLog)
                {
                    <div class="d-flex justify-content-center my-3">
                        <div><MudButton Variant="Variant.Outlined" Size="Size.Small" OnClick="@(() => ShowRawLog = false)">Normal</MudButton></div>
                    </div>
                    <big style="font-size: 14px;">
                        @foreach (var log in ShowLogs)
                        {
                            @log <br />
                        }
                    </big>
                }
                else
                {
                    @if (SearchLogs.Count < ShowLogs.Count)
                    {
                        <div class="d-flex justify-content-center my-3">
                            <div><MudButton Variant="Variant.Outlined" Size="Size.Small" OnClick="@(() => ShowRawLog = true)">Raw log</MudButton></div>
                        </div>
                    }

                    @foreach (var log in SearchLogs)
                    {
                        <div class="log">
                            <span class="log-head @log.BackgroundClass">
                                @log.Time <span class="log-level">@log.Level</span>
                            </span>
                            <span>@log.Message</span>
                            @if (log.HasException)
                            {
                                <br />
                                <pre class="log-exception">
                                    @log.Exception
                                                                    </pre>
                            }
                        </div>
                    }
                }
            </div>
        </div>
    </div>
</div>


@code {
    private DateTime DateLog = DateTime.Today;
    private bool IsLoading;
    private readonly List<string> ShowLogs = new();
    private readonly List<LoggerModel> SearchLogs = new();
    private ElementReference LogContainerRef { get; set; }
    private bool ShowRawLog { get; set; }
    private string? FilterLog { get; set; }

    private List<LogConfiguration> LogsProccess = [];
    private LogConfiguration LogProccessSelected = new();

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);
        if (!firstRender) return;

        LogsProccess = Configuration.GetSection("Logs").Get<List<LogConfiguration>>() ?? [];
        LogProccessSelected = LogsProccess.FirstOrDefault() ?? new LogConfiguration();
        await LoadLogs();
    }

    private async Task LoadLogs()
    {
        try
        {
            IsLoading = true;
            ShowLogs.Clear();
            StateHasChanged();

            using var Http = new HttpClient();
            var logs = await Http.GetFromJsonAsync<IEnumerable<string>>($"{LogProccessSelected.Url}?date={DateLog}");
            ShowLogs.AddRange(logs ?? []);

            IsLoading = false;
            StateHasChanged();

            await ReloadLogs();
        }
        catch (AccessTokenNotAvailableException ex)
        {
            ex.Redirect();
            return;
        }
    }

    private async Task ReloadLogs()
    {
        IsLoading = true;
        SearchLogs.Clear();
        StateHasChanged();

        foreach (var line in ShowLogs.Where(log => string.IsNullOrEmpty(FilterLog) || log.Contains(FilterLog)).TakeLast(2000))
        {
            try
            {
                var log = System.Text.Json.JsonSerializer.Deserialize<LoggerModel>(line);
                if (log is not null) SearchLogs.Add(log);
            }
            catch (System.Text.Json.JsonException)
            {
                continue;
            }
        }

        IsLoading = false;
        StateHasChanged();
        await JSRuntime.InvokeVoidAsync("ScrollToBottom", LogContainerRef);
    }

    private async Task OnSearch(string text)
    {
        FilterLog = text;
        await ReloadLogs();
    }

    private async Task OnDateChanged(DateTime? date)
    {
        if (date is not null && date.HasValue)
        {
            DateLog = date.Value;
            await LoadLogs();
        }
    }

    public class LogConfiguration
    {
        public string Name { get; set; } = "";
        public string Url { get; set; } = "";
    }

    private async Task ExportLogs()
    {
        try
        {
            using var Http = new HttpClient();
            var fileContent = await Http.GetFromJsonAsync<IEnumerable<string>>($"{LogProccessSelected.Url}?date={DateLog}");
            var formattedContent = string.Join("\n", fileContent ?? []);
            var fileName = $"{LogProccessSelected.Name}_{DateLog.ToShortDateString()}.txt";
            await JSRuntime.InvokeVoidAsync("downloadFile", fileName, formattedContent, "text/plain");
        }
        catch (Exception ex)
        {
            Snackbar.Add($"Lỗi khi tải file: {ex.Message}", Severity.Warning);
        }
    }
}

