using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Dacryptero.DB;
using Dacryptero.Search.Sorting;

namespace Dacryptero.Search.AST
{
    public class Group : AstCollectionBase
    {
        public List<OptionBase> Options { get; } = new List<OptionBase>();

        public override SearchProgress Check(SearchContext context)
        {
            var result = new List<Collections.TreeCollection<ResultFound>>(Items.Count + Options.Count);
            var score = 0.0;
            foreach (var opt in Options)
            {
                if (opt is SortOption sortOption)
                    continue;
                var prog = opt.Check(context);
                if (!prog.IsSuccess)
                    return new SearchProgress();
                result.Add(prog.Previews);
                score = Math.Max(score, prog.Score);
            }
            foreach (var item in Items)
            {
                var prog = item.Check(context);
                if (!prog.IsSuccess)
                    continue;
                result.Add(prog.Previews);
                score += prog.Score;
            }
            return new SearchProgress(score, new Collections.TreeCollection<ResultFound>(result));
        }

        protected override AstCollectionBase CloneCollection()
        {
            var @new = new Group();
            @new.Options.Capacity = Options.Capacity;
            @new.Options.AddRange(Options);
            return @new;
        }

        public override async Task<SearchIndex> GetSearchIndexAsync(DBSingleController db,
            Data.IndexSource source, CancellationToken cancellationToken
        )
        {
            var index = Items.Count == 0 ? SearchIndex.All : SearchIndex.Empty;
            // var index = SearchIndex.Empty;
            foreach (var item in Items)
            {
                var entry = await item.GetSearchIndexAsync(db, source, cancellationToken)
                    .ConfigureAwait(false);
                index.UnionWith(entry);
            }
            foreach (var option in Options)
            {
                var entry = await option.GetSearchIndexAsync(db, source, cancellationToken)
                    .ConfigureAwait(false);
                index.IntersectWith(entry);
            }
            return index;
        }

        public override SortConfig GetSortConfig()
        {
            var config = base.GetSortConfig();
            foreach (var opt in Options)
            {
                if (opt is SortOption sort)
                    config.Options.Add(sort);
            }
            return config;
        }
    }
}