using C4IT.FASD.Base;
using FasdDesktopUi.Basics.Services.RelationService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using static C4IT.Logging.cLogManager;

namespace FasdDesktopUi.Basics.Services.SupportCase
{
    public class SupportCase : ISupportCase
    {
        private readonly Dictionary<enumFasdInformationClass, IList<cF4sdApiSearchResultRelation>> _caseRelations = new Dictionary<enumFasdInformationClass, IList<cF4sdApiSearchResultRelation>>();
        //private readonly Lookup<IdentitySet, cF4SDHealthCardRawData.cHealthCardTable> _supportCaseDataCache;

        internal readonly Guid Id;
        private readonly IRelationService _relationService;
        public cSupportCaseDataProvider SupportCaseDataProviderArtifact { get; }

        internal SupportCase(Guid id, IRelationService relationService, cSupportCaseDataProvider supportCaseDataProvider)
        {
            Id = id;
            _relationService = relationService;
            SupportCaseDataProviderArtifact = supportCaseDataProvider;

            AddCaseRelations(_relationService?.GetLoadedRelations());
        }

        ~SupportCase()
        {
            if (_relationService != null)
                _relationService.RelationsFound -= HandleRelationsFound;
        }

        public void Initialize()
        {
            if (_relationService != null)
                _relationService.RelationsFound += HandleRelationsFound;
        }

        public ILookup<enumFasdInformationClass, cF4sdApiSearchResultRelation> GetCaseRelations()
        {
            try
            {
                IEnumerable<(enumFasdInformationClass InformationClass, cF4sdApiSearchResultRelation Relation)> flatList
                    = _caseRelations.SelectMany(i => i.Value.Select(v => (i.Key, v)));

                return flatList.ToLookup(v => v.InformationClass, v => v.Relation);
            }
            catch (Exception ex)
            {
                LogException(ex);
            }

            return null;
        }

        public void AddCaseRelations(ILookup<enumFasdInformationClass, cF4sdApiSearchResultRelation> relations)
        {
            try
            {
                if (relations is null)
                    return;

                foreach (var relationType in relations)
                {
                    if (_caseRelations.TryGetValue(relationType.Key, out var caseRelation))
                        caseRelation = caseRelation.Union(relationType, new SearchResultRelationEqualityComparer()).ToList();
                    else
                        _caseRelations.Add(relationType.Key, relationType.ToList());

                    if (SupportCaseDataProviderArtifact?.CaseRelations?.TryGetValue(relationType.Key, out var caseRelations) ?? false)
                        caseRelations = caseRelations.Union(relationType, new SearchResultRelationEqualityComparer()).ToList();
                    else
                        SupportCaseDataProviderArtifact?.CaseRelations?.Add(relationType.Key, relationType.ToList());
                }

                CaseRelationsAdded?.Invoke(this, new RelationEventArgs() { Relations = relations });
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
        }

        public void UpdateSupportCaseDataCache()
        {
            throw new NotImplementedException();
        }

        public IEnumerable<cF4SDHealthCardRawData.cHealthCardTable> GetSupportCaseHealthcardData(object identities, object valueAddress)
        {
            throw new NotImplementedException();
        }

        private void HandleRelationsFound(object sender, StagedSearchResultRelationsEventArgs e)
        {
            AddCaseRelations(e.StagedResultRelations.Relations);

            if (e.StagedResultRelations.IsComplete)
                _relationService.RelationsFound -= HandleRelationsFound;
        }

        private void AddCaseRelations(IEnumerable<cF4sdApiSearchResultRelation> relations)
            => AddCaseRelations(relations?.ToLookup(r => cF4sdIdentityEntry.GetFromSearchResult(r.Type), r => r));

        public event EventHandler<RelationEventArgs> CaseRelationsAdded;
        public event EventHandler<object> SupportCaseDataCacheHasChanged; // Lookup for IdentitySet and tables which has been updated

        private class SearchResultRelationEqualityComparer : IEqualityComparer<cF4sdApiSearchResultRelation>
        {
            public bool Equals(cF4sdApiSearchResultRelation x, cF4sdApiSearchResultRelation y)
            {
                return x.isEqual(y);
            }

            public int GetHashCode(cF4sdApiSearchResultRelation obj)
            {
                return obj.GetHashCode();
            }
        }
    }
}
