using Insight.Agent.Enums;
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Bson;
using MongoDB.Driver;
using MudBlazor;
using System.Text.RegularExpressions;
using SortDirection = MudBlazor.SortDirection;

namespace Insight.Web.Pages.Management.Hosts;

[Route(Navigation.Management.Hosts.Logs)]
public partial class Logs
{
    [Parameter] public string? HostId { get; set; }

    [Inject] private IMongoDatabase Database { get; init; } = default!;
    [Inject] private ISnackbar Snackbar { get; init; } = default!;
    [Inject] private NavigationManager NavigationManager { get; init; } = default!;

    private TableContainer<HostLogEntity>? Container { get; set; }
    private string Title { get; set; } = Global.Name;
    private List<BreadcrumbItem> Breadcrumbs { get; } = new();
    private string? Search { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (string.IsNullOrWhiteSpace(HostId) || ObjectId.TryParse(HostId, out var hostId) is false)
        {
            Notification.Error(Snackbar, "Not Found");
            NavigationManager.NavigateTo(Navigation.Management.Hosts.Index);
            return;
        }

        Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
        Breadcrumbs.Add(new BreadcrumbItem("Hosts", href: Navigation.Management.Hosts.Index));

        var host = await Database.Host()
                .Find(Builders<HostEntity>
                .Filter
                .Eq(p => p.Id, HostId))
                .FirstOrDefaultAsync(default);

        if (host is null)
        {
            Notification.Error(Snackbar, "Not Found");
            NavigationManager.NavigateTo(Navigation.Management.Hosts.Index);
            return;
        }

        Title = $"Host » {host.Name}｜Insight";
        Breadcrumbs.Add(new BreadcrumbItem(host.Name, href: Navigation.Management.Hosts.DetailsHref(HostId)));
        Breadcrumbs.Add(new BreadcrumbItem("Logs", href: "#", true));
    }

    private async Task<TableData<HostLogEntity>> LoadDataAsync(TableState state)
    {
        try
        {
            var filter = Builders<HostLogEntity>.Filter.Eq(p => p.Host, HostId);

            if (string.IsNullOrWhiteSpace(Search) is false)
            {
                var regex = new BsonRegularExpression(new Regex(Search, RegexOptions.IgnoreCase));
                filter &= Builders<HostLogEntity>.Filter.Regex(x => x.Category, regex) |
                    Builders<HostLogEntity>.Filter.Regex(x => x.Status, regex) |
                    Builders<HostLogEntity>.Filter.Regex(x => x.Source, regex) |
                    Builders<HostLogEntity>.Filter.Regex(x => x.Message, regex) |
                    Builders<HostLogEntity>.Filter.Regex(x => x.Timestamp, regex);
            }

            if (FilterDate?.Start is not null)
            {
                if (FilterDate.Start == FilterDate.End)
                {
                    filter &= Builders<HostLogEntity>.Filter.Gte(x => x.Timestamp, FilterDate.Start);
                    filter &= Builders<HostLogEntity>.Filter.Lt(x => x.Timestamp, FilterDate.Start.Value.AddDays(1));
                }
                else
                {
                    filter &= Builders<HostLogEntity>.Filter.Gte(x => x.Timestamp, FilterDate.Start);
                    filter &= Builders<HostLogEntity>.Filter.Lt(x => x.Timestamp, FilterDate.End);
                }
            }

            if (FilterCategory is not null)
            {
                filter &= Builders<HostLogEntity>.Filter.Eq(x => x.Category, FilterCategory.ToString());
            }

            if (FilterStatus is not null)
            {
                filter &= Builders<HostLogEntity>.Filter.Eq(x => x.Status, FilterStatus.ToString());
            }

            var query = Database.HostLog()
                .Find(filter)
                .Sort(state.SortDirection switch
                {
                    SortDirection.Ascending => state.SortLabel switch
                    {
                        "Category" => Builders<HostLogEntity>.Sort.Ascending(p => p.Category),
                        "Status" => Builders<HostLogEntity>.Sort.Ascending(p => p.Status),
                        "Source" => Builders<HostLogEntity>.Sort.Ascending(p => p.Source),
                        "Message" => Builders<HostLogEntity>.Sort.Ascending(p => p.Message),
                        "Timestamp" => Builders<HostLogEntity>.Sort.Ascending(p => p.Timestamp),
                        _ => null
                    },
                    SortDirection.Descending => state.SortLabel switch
                    {
                        "Category" => Builders<HostLogEntity>.Sort.Descending(p => p.Category),
                        "Status" => Builders<HostLogEntity>.Sort.Descending(p => p.Status),
                        "Source" => Builders<HostLogEntity>.Sort.Descending(p => p.Source),
                        "Message" => Builders<HostLogEntity>.Sort.Descending(p => p.Message),
                        "Timestamp" => Builders<HostLogEntity>.Sort.Descending(p => p.Timestamp),
                        _ => null
                    },
                    _ => Builders<HostLogEntity>.Sort.Descending(p => p.Timestamp)
                });

            return new TableData<HostLogEntity>()
            {
                TotalItems = (int)await query.CountDocumentsAsync(default),
                Items = await query.Skip(state.Page * state.PageSize).Limit(state.PageSize).ToListAsync(default)
            };
        }
        catch (Exception)
        {
            Notification.Error(Snackbar);
            return new TableData<HostLogEntity>();
        }
    }

    private bool _filter;
    public bool Filter
    {
        get
        {
            return _filter;
        }
        set
        {
            if (value != _filter)
            {
                _filter = value;
                StateHasChanged();
            }
        }
    }

    private bool Filtered => (FilterDate is not null) || (FilterCategory is not null) || (FilterStatus is not null);

    private MudDateRangePicker? _picker;
    private DateRange? _filterDate;
    public DateRange? FilterDate
    {
        get
        {
            return _filterDate;
        }
        set
        {
            if (value != _filterDate)
            {
                _filterDate = value;

                Container?.RefreshAsync();

                if (value is not null)
                {
                    Notification.Warning(Snackbar, "Filtered");
                }
            }
        }
    }

    private CategoryEnum? _filterCategory;
    public CategoryEnum? FilterCategory
    {
        get
        {
            return _filterCategory;
        }
        set
        {
            if (value != _filterCategory)
            {
                _filterCategory = value;

                Container?.RefreshAsync();

                if (value is not null)
                {
                    Notification.Warning(Snackbar, "Filtered");
                }
            }
        }
    }

    private StatusEnum? _filterStatus;
    public StatusEnum? FilterStatus
    {
        get
        {
            return _filterStatus;
        }
        set
        {
            if (value != _filterStatus)
            {
                _filterStatus = value;

                Container?.RefreshAsync();

                if (value is not null)
                {
                    Notification.Warning(Snackbar, "Filtered");
                }
            }
        }
    }

    private void OnFilterReset()
    {
        FilterDate = null;
        FilterCategory = null;
        FilterStatus = null;
    }
}