using C4IT.FASD.Base;
using C4IT.FASD.Cockpit.Communication;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using static C4IT.Logging.cLogManager;

[assembly: InternalsVisibleTo("F4SD.Cockpit.Client.Test")]

namespace FasdDesktopUi.Basics.Services.RelationService
{
    internal class RelationService : IRelationService
    {
        private IEnumerable<cF4sdApiSearchResultRelation> _relations = new List<cF4sdApiSearchResultRelation>();

        /// <summary>
        /// Asynchronously loads relations for the specified search results.
        /// </summary>
        /// <remarks>This method initiates a task to gather relations for the provided search results and
        /// periodically checks for the completion of the task. Once relations are retrieved, an event <see cref="RelationsFound"/> 
        /// is raised to notify listeners of the progress.</remarks>
        /// <returns>Task id and pending information classes</returns>
        public async Task<cF4sdStagedSearchResultRelationTaskId> LoadRelationsAsync(IEnumerable<cFasdApiSearchResultEntry> relatedTo, CancellationToken token = default)
        {
            try
            {
                _relations = relatedTo?.Select(searchResult => new cF4sdApiSearchResultRelation(searchResult)).ToList() ?? new List<cF4sdApiSearchResultRelation>();
                cF4sdStagedSearchResultRelationTaskId gatherRelationTask = await cFasdCockpitCommunicationBase.Instance.StartGatheringRelations(relatedTo, token);

                _ = Task.Run(async () =>
                {
                    const int maxRetryCount = 10;
                    for (int i = 0; i < maxRetryCount; i++)
                    {
                        cF4sdStagedSearchResultRelations stagedRelations = await cFasdCockpitCommunicationBase.Instance.GetStagedRelations(gatherRelationTask.Id, token);
                        stagedRelations.MergeAsRelationInfosWith(relatedTo);

                        _relations = _relations.Union(stagedRelations.Relations);
                        RelationsFound?.Invoke(this, new StagedSearchResultRelationsEventArgs() { RelatedTo = relatedTo, StagedResultRelations = stagedRelations, RelationService = this });

                        if (stagedRelations?.IsComplete ?? false)
                            break;
                    }
                });

                return gatherRelationTask;
            }
            catch (Exception ex)
            {
                LogException(ex);
            }

            return null;
        }

        public IEnumerable<cF4sdApiSearchResultRelation> GetLoadedRelations() => _relations;

        public IRelationService Clone()
        {
            RelationService copy = (RelationService)MemberwiseClone();
            copy._relations = _relations.Select(r => r).ToList();
            return copy;
        }

        public event EventHandler<StagedSearchResultRelationsEventArgs> RelationsFound;
    }
}
