using JSMR.Application.Circles.Queries.Search;
using JSMR.Application.Common.Search;
using JSMR.Application.Creators.Queries.Search.Contracts;
using JSMR.Application.Tags.Queries.Search.Contracts;
using JSMR.Application.VoiceWorks.Queries.Search;

namespace JSMR.Application.Logging;

public static class LoggingExtensions
{
    public static object ToLogObject<TCriteria, TSortField>(this SearchOptions<TCriteria, TSortField> searchOptions)
        where TCriteria : new()
        where TSortField : struct, Enum
    {
        return new LogObjectBuilder()
            .Add("PageNumber", searchOptions.PageNumber)
            .Add("PageSize", searchOptions.PageSize)
            .Add("Criteria", MapCriteriaToLogObject(searchOptions.Criteria))
            //.AddIfNotEmpty("Sort", searchOptions.SortOptions.ToLogObject())
            .Build();
    }

    private static object MapCriteriaToLogObject<TCriteria>(TCriteria criteria) => criteria switch
    {
        VoiceWorkSearchCriteria voiceWorkSearchCriteria => voiceWorkSearchCriteria.ToLogObject(),
        CircleSearchCriteria circleSearchCriteria => circleSearchCriteria.ToLogObject(),
        TagSearchCriteria tagSearchCriteria => tagSearchCriteria.ToLogObject(),
        CreatorSearchCriteria creatorSearchCriteria => creatorSearchCriteria.ToLogObject(),
        _ => criteria!
    };

    public record SortLog(int Index, string Field, string Direction);

    public static object ToLogObject<TSortField>(this IEnumerable<SortOption<TSortField>> sort)
       where TSortField : struct, Enum
    {
        return sort.Select((sortOption, index) =>
            new {
                Index = index,
                Field = sortOption.Field.ToString(),
                Direction = sortOption.Direction.ToString()
            }
        ).ToList();
    }

    public static object ToLogObject(this VoiceWorkSearchCriteria criteria)
    {
        return new LogObjectBuilder()
           .AddIfNotEmpty("Keywords", criteria.Keywords)
           .AddIfNotEmpty("Title", criteria.Title)
           .AddIfNotEmpty("Circle", criteria.Circle)
           .Add("Locale", criteria.Locale)
           .AddIfNotEmpty("SaleStatus", criteria.SaleStatus.ToString())
           .AddIfNotEmpty("CircleStatus", criteria.CircleStatus.ToString())
           .AddIfNotEmpty("TagStatus", criteria.TagStatus.ToString())
           .AddIfNotEmpty("CreatorStatus", criteria.CreatorStatus.ToString())
           .AddIfNotEmpty("AgeRatings", criteria.AgeRatings)
           .AddIfNotEmpty("Languages", criteria.SupportedLanguages)
           .AddIfNotEmpty("TagIds", criteria.TagIds, preview: 5)
           .AddIfNotEmpty("CreatorIds", criteria.CreatorIds, preview: 5)
           .Add("IncludeAllTags", criteria.IncludeAllTags ? true : null)
           .Add("IncludeAllCreators", criteria.IncludeAllCreators ? true : null)
           .Add("MinDownloads", criteria.MinDownloads)
           .Add("MaxDownloads", criteria.MaxDownloads)
           .Add("ReleaseDateStart", criteria.ReleaseDateStart)
           .Add("ReleaseDateEnd", criteria.ReleaseDateEnd)
           .Build();
    }

    public static object ToLogObject(this CircleSearchCriteria criteria)
    {
        return new LogObjectBuilder()
           .AddIfNotEmpty("Name", criteria.Name)
           .AddIfNotEmpty("Status", criteria.Status?.ToString())
           .Build();
    }

    public static object ToLogObject(this TagSearchCriteria criteria)
    {
        return new LogObjectBuilder()
           .AddIfNotEmpty("Name", criteria.Name)
           .Build();
    }

    public static object ToLogObject(this CreatorSearchCriteria criteria)
    {
        return new LogObjectBuilder()
           .AddIfNotEmpty("Name", criteria.Name)
           .Build();
    }
}