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.Agents;

[Route(Navigation.Management.Agents.Logs)]
public partial class Logs
{
    [Parameter] public string? AgentId { 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<AgentLogEntity>? 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(AgentId) || ObjectId.TryParse(AgentId, out var agentId) is false)
        {
            Notification.Error(Snackbar, "Not Found");
            NavigationManager.NavigateTo(Navigation.Management.Agents.Index);
            return;
        }

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

        var agent = await Database.Agent()
                .Aggregate()
                .Match(Builders<AgentEntity>.Filter.Eq(p => p.Id, AgentId))
                .Lookup<AgentEntity, HostEntity, AgentEntity>(Database.Host(), p => p.Id, p => p.Agent, p => p.Hosts)
                .FirstOrDefaultAsync(default);

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

        Title = $"Agent » {agent.Hostname}｜Insight";

        Breadcrumbs.Add(new BreadcrumbItem(agent?.Hostname, href: Navigation.Management.Agents.DetailsHref(AgentId)));
        Breadcrumbs.Add(new BreadcrumbItem("Logs", href: "#", true));
    }

    private async Task<TableData<AgentLogEntity>> LoadDataAsync(TableState state)
    {
        try
        {
            var filter = Builders<AgentLogEntity>.Filter.Eq(x => x.Agent, AgentId);

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

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

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

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

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

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


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

    public 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;

                if (Container is not null)
                {
                    _ = 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;

                if (Container is not null)
                {
                    _ = 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;

                if (Container is not null)
                {
                    _ = Container.RefreshAsync();
                }

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

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

    //private async Task OnDelete()
    //{
    //    await Database.AgentsLogs().DeleteManyAsync(Builders<AgentLogEntity>.Filter.Lt(p => p.Timestamp, DateTime.Now.AddDays(-3)));
    //    //var test = await Database.AgentsLogs().CountDocumentsAsync(Builders<AgentLogEntity>.Filter.Lt(p => p.Timestamp, DateTime.Now.AddDays(-3)));

    //    //Console.WriteLine(test);
    //}
}