using Microsoft.EntityFrameworkCore;
using Modules.Library.Database.Database.Models;
using Modules.Library.Database.Database.Models.CommonProperties;
using System.Diagnostics.CodeAnalysis;

namespace Modules.Library.Database.Repositories;

internal static class CommonPropertiesHelper
{
    internal static void SyncCommonProperties(CommonProperties db, CommonProperties newCommonProperties)
    {
        db.Preview = newCommonProperties.Preview;
        db.AnnouncementDate = newCommonProperties.AnnouncementDate;
        db.EstimatedReleaseDate = newCommonProperties.EstimatedReleaseDate;
        db.ReleaseDate = newCommonProperties.ReleaseDate;
        //sync names
        var deleteNames = db.Names.Except(newCommonProperties.Names, new NameComparer()).ToList();
        var addNames = newCommonProperties.Names.Except(db.Names, new NameComparer());
        if (deleteNames.Any())
        {
            foreach (var name in deleteNames)
            {
                db.Names.Remove(db.Names.First(q => q.Id == name.Id));
            }
        }
        if (addNames.Any())
        {
            db.Names.AddRange(addNames);
        }
        //if (updateNames.Any())
        //{
        //    foreach (var name in updateNames)
        //    {
        //        var existingName = db.Names.First(q => q.Id == name.Id);
        //        existingName.Value = name.Value;
        //        existingName.Type = name.Type;
        //        existingName.LanguageId = name.LanguageId;
        //    }
        //}

        //sync descriptions
        var deleteDescriptions = db.Descriptions.Except(newCommonProperties.Descriptions, new DescriptionComparer()).ToList();
        var addDescriptions = newCommonProperties.Descriptions.Except(db.Descriptions, new DescriptionComparer());
        //var updateDescriptions = db.Descriptions.Except(deleteDescriptions.Union(addDescriptions));
        if (deleteDescriptions.Any())
        {
            foreach (var description in deleteDescriptions)
            {
                db.Descriptions.Remove(db.Descriptions.First(q => q.Id == description.Id));
            }
        }
        if (addDescriptions.Any())
        {
            db.Descriptions.AddRange(addDescriptions);
        }
        //if (updateDescriptions.Any())
        //{
        //    foreach (var description in updateDescriptions)
        //    {
        //        var existingDescription = db.Descriptions.First(q => q.Id == description.Id);
        //        existingDescription.LanguageId = description.LanguageId;
        //        existingDescription.IsOriginal = description.IsOriginal;
        //        existingDescription.Value = description.Value;
        //    }
        //}

        //sync genres
        var deleteGenres = db.Genres.Except(newCommonProperties.Genres, new GenreComparer()).ToList();
        var addGenres = newCommonProperties.Genres.Except(db.Genres, new GenreComparer());
        var updateGenres = newCommonProperties.Genres.Where(q => db.Genres.Any(x => x.GenreId == q.GenreId && x.Proportion != q.Proportion));
        if (deleteGenres.Any())
        {
            foreach (var genre in deleteGenres)
            {
                db.Genres.Remove(db.Genres.First(q => q.Id == genre.Id));
            }
        }
        if (addGenres.Any())
        {
            db.Genres.AddRange(addGenres);
        }
        if (updateGenres.Any())
        {
            foreach (var genre in updateGenres)
            {
                var dbGenre = db.Genres.First(q => q.GenreId == genre.GenreId);
                dbGenre.Proportion = genre.Proportion;
            }
        }

        //sync related content
        var deleteRelatedContent = db.RelatedContent.Except(newCommonProperties.RelatedContent, new MediaInfoComparer()).ToList();
        var addRelatedContent = newCommonProperties.RelatedContent.Except(db.RelatedContent, new MediaInfoComparer());
        //var updateRelatedContent = db.RelatedContent.Except(deleteRelatedContent.Union(addRelatedContent));
        if (deleteRelatedContent.Any())
        {
            foreach (var relatedContent in deleteRelatedContent)
            {
                db.RelatedContent.Remove(db.RelatedContent.First(q => q.Id == relatedContent.Id));
            }
        }
        if (addRelatedContent.Any())
        {
            db.RelatedContent.AddRange(addRelatedContent);
        }
        //if (updateRelatedContent.Any())
        //{
        //    foreach (var relatedContent in updateRelatedContent)
        //    {
        //        var existingRelatedContent = db.RelatedContent.First(q => q.Id == relatedContent.Id);
        //        existingRelatedContent.Url = relatedContent.Url;
        //        existingRelatedContent.Type = relatedContent.Type;
        //        existingRelatedContent.ContentType = relatedContent.ContentType;
        //    }
        //}
    }

    private class NameComparer : IEqualityComparer<NameItem>
    {
        public bool Equals(NameItem? x, NameItem? y)
        {
            return x != null && y != null && x.LanguageId == y.LanguageId && x.Type == y.Type && x.Value == y.Value;
        }

        public int GetHashCode([DisallowNull] NameItem obj)
        {
            return HashCode.Combine(obj.LanguageId.GetHashCode(), obj.Type.GetHashCode(), obj.Value.GetHashCode());
        }
    }

    private class DescriptionComparer : IEqualityComparer<DescriptionItem>
    {
        public bool Equals(DescriptionItem? x, DescriptionItem? y)
        {
            return x != null && y != null && x.LanguageId == y.LanguageId && x.IsOriginal == y.IsOriginal && x.Value == y.Value;
        }

        public int GetHashCode([DisallowNull] DescriptionItem obj)
        {
            return HashCode.Combine(obj.LanguageId.GetHashCode(), obj.IsOriginal.GetHashCode(), obj.Value.GetHashCode());
        }
    }

    private class GenreComparer : IEqualityComparer<GenreProportionItem>
    {
        public bool Equals(GenreProportionItem? x, GenreProportionItem? y)
        {
            return x != null && y != null && x.GenreId == y.GenreId;
        }

        public int GetHashCode([DisallowNull] GenreProportionItem obj)
        {
            return obj.GenreId.GetHashCode();
        }
    }

    private class MediaInfoComparer : IEqualityComparer<MediaInfo>
    {
        public bool Equals(MediaInfo? x, MediaInfo? y)
        {
            return x != null && y != null && x.ObjectId == y.ObjectId && x.Type == y.Type && x.ContentType == y.ContentType;
        }

        public int GetHashCode([DisallowNull] MediaInfo obj)
        {
            return HashCode.Combine(obj.ObjectId.GetHashCode(), obj.Type.GetHashCode(), obj.ContentType.GetHashCode());
        }
    }
}