using System.Linq.Expressions;
using e_suite.API.Common;
using e_suite.API.Common.models;
using e_suite.API.Common.repository;
using e_suite.Database.Core.Tables.Diagnostics;
using e_suite.Utilities.Pagination;

namespace e_suite.Modules.PerformanceManager;

public class PerformanceManager : IPerformanceManager
{
    private readonly IPerformanceManagerRepository _performanceManagerRepository;

    public PerformanceManager(IPerformanceManagerRepository performanceManagerRepository)
    {
        _performanceManagerRepository = performanceManagerRepository;
    }

    public async Task<PaginatedData<ReadPerformanceReportSummary>> GetPerformanceSummaryAsync(Paging paging, CancellationToken cancellationToken)
    {
        var performanceReportSummary = _performanceManagerRepository.GetPerformanceReportSummary();


        var paginatedData = await PaginatedData.Paginate(performanceReportSummary, paging,
            KeySelector, FilterSelector, cancellationToken);

        var paginatedResult = new PaginatedData<ReadPerformanceReportSummary>
        {
            Count = paginatedData.Count,
            Page = paginatedData.Page,
            PageSize = paginatedData.PageSize,
            Data = paginatedData.Data.Select(ToReadPerformanceReportSummary)

        };

        return paginatedResult;
    }

    private ReadPerformanceReportSummary ToReadPerformanceReportSummary(PerformanceReportSummary performanceReportSummary)
    {
        return new ReadPerformanceReportSummary(performanceReportSummary)
        {
            Host = performanceReportSummary.Host,
            ControllerName = performanceReportSummary.ControllerName,
            ActionName = performanceReportSummary.ActionName
        };
    }

    private Expression<Func<PerformanceReportSummary, bool>> FilterSelector(string? key, string value)
    {
        return key?.ToLowerInvariant() switch
        {
            "host" => x => x.Host.Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "controllername" => x => x.ControllerName.Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "actionname" => x => x.ActionName.Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "requestType" => x => x.RequestType.Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "count" => x => x.Count.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "mintotaltimems" => x => x.MinTotalTimeMs.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "maxtotaltimemS" => x => x.MaxTotalTimeMs.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "avgtotaltimems" => x => x.AvgTotalTimeMs.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "sumtotaltimems" => x => x.SumTotalTimeMs.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase),
            _ => x => x.SumTotalTimeMs.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase),
        };
    }

    private Expression<Func<PerformanceReportSummary, object>> KeySelector(string? sortKey)
    {
        return sortKey?.ToLowerInvariant() switch
        {
            "host" => x => x.Host,
            "controllername" => x => x.ControllerName,
            "actionname" => x => x.ActionName,
            "requestType" => x => x.RequestType,
            "count" => x => x.Count,
            "mintotaltimems" => x => x.MinTotalTimeMs,
            "maxtotaltimemS" => x => x.MaxTotalTimeMs,
            "avgtotaltimems" => x => x.AvgTotalTimeMs,
            "sumtotaltimems" => x => x.SumTotalTimeMs,
            _ => x => x.SumTotalTimeMs
        };
    }

    public async Task<PaginatedData<ReadPerformanceReport>> GetPerformanceDetailsAsync(
        string hostName,
        string controllerName,
        string actionName,
        string requestType,
        Paging paging,
        CancellationToken cancellationToken
    )
    {
        var performanceReportSummary = _performanceManagerRepository.GetPerformanceReports(hostName, controllerName, actionName, requestType);
        
        var paginatedData = await PaginatedData.Paginate(performanceReportSummary, paging,
            PerformanceReportKeySelector, PerformanceReportFilterSelector, cancellationToken);

        var paginatedResult = new PaginatedData<ReadPerformanceReport>
        {
            Count = paginatedData.Count,
            Page = paginatedData.Page,
            PageSize = paginatedData.PageSize,
            Data = paginatedData.Data.Select(ToReadPerformanceReport)

        };

        return paginatedResult;
    }

    private ReadPerformanceReport ToReadPerformanceReport(PerformanceReport report)
    {
        return new ReadPerformanceReport(report)
        {
            Host = report.Host,
            ControllerName = report.ControllerName,
            ActionName = report.ActionName
        };
    }

    private Expression<Func<PerformanceReport, object>> PerformanceReportKeySelector(string? sortKey)
    {
        return sortKey?.ToLowerInvariant() switch
        {
            "host" => x => x.Host,
            "controllername" => x => x.ControllerName,
            "actionname" => x => x.ActionName,
            "requestType" => x => x.RequestType,
            "id" => x => x.Id,
            "actionparameters" => x => x.ActionParameters,
            "startdateyime" => x => x.StartDateTime,
            "timings" => x => x.Timings,
            "totaltimems" => x => x.TotalTimeMS,
            _ => x => x.StartDateTime
        };
    }

    private Expression<Func<PerformanceReport, bool>> PerformanceReportFilterSelector(string? key, string value)
    {
        return key?.ToLowerInvariant() switch
        {
            "host" => x => x.Host.Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "controllername" => x => x.ControllerName.Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "actionname" => x => x.ActionName.Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "requestType" => x => x.RequestType.Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "id" => x => x.Id.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "actionparameters" => x =>
                x.ActionParameters.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "startdateyime" => x =>
                x.StartDateTime.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "timings" => x => x.Timings.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase),
            "totaltimems" => x => x.TotalTimeMS.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase),
            _ => x => x.StartDateTime.ToString().Contains(value, StringComparison.CurrentCultureIgnoreCase)
        };
    }
}