using JSMR.Application.Common.Search;
using JSMR.Application.Tags.Queries.Search.Contracts;
using JSMR.Application.Tags.Queries.Search.Ports;
using JSMR.Infrastructure.Common.Queries;
using System.Linq.Expressions;

namespace JSMR.Infrastructure.Data.Repositories.Tags;

public class TagSearchProvider(AppDbContext context) : SearchProvider<TagSearchItem, TagSearchCriteria, TagSortField, TagSearchItem>, ITagSearchProvider
{
    protected override bool UseSelectIdQuery => false;

    protected override IQueryable<TagSearchItem> GetBaseQuery()
    {
        return
            from tag in context.Tags
            join englishTag in context.EnglishTags on tag.TagId equals englishTag.TagId into test
            from subEnglishTag in test.DefaultIfEmpty()
            join voiceWorkTags in context.VoiceWorkTags on tag.TagId equals voiceWorkTags.TagId into vwts
            select new TagSearchItem
            {
                TagId = tag.TagId,
                Name = tag.Name,
                EnglishName = subEnglishTag.Name,
                Favorite = tag.Favorite,
                Blacklisted = tag.Blacklisted,
                VoiceWorkCount = vwts.Count()
            };
    }

    protected override IQueryable<TagSearchItem> ApplyFilters(IQueryable<TagSearchItem> query, TagSearchCriteria criteria)
    {
        IQueryable<TagSearchItem> filteredQuery = query;

        if (string.IsNullOrEmpty(criteria.Name) == false)
        {
            string name = criteria.Name.Trim();

            filteredQuery = filteredQuery.Where(x =>
                x.Name.Contains(name) || (x.EnglishName != null && x.EnglishName.Contains(name)));
        }

        return filteredQuery;
    }

    protected override Expression<Func<TagSearchItem, object?>> GetSortExpression(TagSortField field)
    {
        Expression<Func<TagSearchItem, object?>> selector = field switch
        {
            TagSortField.EnglishName => x => x.EnglishName ?? "",
            TagSortField.VoiceWorkCount => x => x.VoiceWorkCount,
            TagSortField.Favorite => x => x.Favorite,
            TagSortField.Blacklisted => x => x.Blacklisted,
            _ => x => x.Name
        };

        return selector;
    }

    protected override IEnumerable<(Expression<Func<TagSearchItem, object>> Selector, SortDirection Dir)> GetDefaultSortChain()
    {
        yield return (x => x.Name, SortDirection.Ascending);
    }

    protected override IOrderedQueryable<TagSearchItem> GetSelectQuery(TagSearchCriteria criteria, IOrderedQueryable<TagSearchItem> query)
    {
        return query;
    }

    protected override IQueryable<int> GetSelectIdQuery(IOrderedQueryable<TagSearchItem> query)
    {
        throw new NotImplementedException();
    }

    protected override Task<Dictionary<int, TagSearchItem>> GetItems(TagSearchCriteria criteria, int[] ids)
    {
        return Task.FromResult(new Dictionary<int, TagSearchItem>());
    }
}