using System.Transactions;

namespace Modules.Library.Core.Domain.MediaContent.CommonProperties;

public class CommonProperties : Entity
{
    private List<NameItem> _names = [];
    public IReadOnlyCollection<NameItem> Names => _names.AsReadOnly();
    public MediaInfo? Preview { get; private set; }

    private List<DescriptionItem> _descriptions = [];
    public IReadOnlyCollection<DescriptionItem> Descriptions => _descriptions.AsReadOnly();

    public List<Genre_Percentage> _genres = [];
    public IReadOnlyCollection<Genre_Percentage> Genres => _genres.AsReadOnly();

    public List<MediaInfo> _relatedContent = [];
    public IReadOnlyCollection<MediaInfo> RelatedContent => _relatedContent.AsReadOnly();

    public DateTimeOffset? AnnouncementDate { get; private set; }
    public DateTimeOffset? EstimatedReleaseDate { get; private set; }
    public DateTimeOffset? ReleaseDate { get; private set; }

    #region Names
    public void AddNameOriginal(Guid language)
    {
        if (_names.Any(q => q.Type == NameType.Original)) throw new Exception("Original name is already exist.");
        _names.Add(new NameItem { LanguageId = language, Type = NameType.Original });
    }
    public void AddNameOriginalInAnotherLanguage(Guid language, string value)
    {
        if (language == _names.Single(q => q.Type == NameType.Original).LanguageId)
            throw new Exception("Language must not match original name language");

        if (_names.Any(q => q.Type == NameType.OriginalInAnotherLanguage && q.LanguageId == language))
            throw new Exception("Name in following language is already exist.");

        _names.Add(new NameItem { LanguageId = language, Type = NameType.OriginalInAnotherLanguage });
    }
    public void AddNameTranslation(Guid language, string value)
    {
        _names.Add(new NameItem { LanguageId = language, Type = NameType.Translation });
    }
    public void AddNameAbbreviation(Guid language, string value)
    {
        _names.Add(new NameItem { LanguageId = language, Type = NameType.Abbreviation });
    }

    public void RemoveName(Guid nameId)
    {
        var name = GetName(nameId);
        if (name.Type == NameType.Original) throw new Exception($"Unable to remove original name");
        _names.Remove(name);
    }
    
    public void SetNameValue(Guid nameId, string value)
    {
        var name = GetName(nameId);
        name.SetValue(value);
    }

    private NameItem GetName(Guid nameId)
    {
        return _names.FirstOrDefault(q => q.Id == nameId) ?? throw new Exception($"Name with id [{nameId}] is not found");
    }
    #endregion

    public void SetPreview(string url)
    {
        Preview ??= new MediaInfo { Type = MediaInfoType.Image };
        Preview.SetUrl(url);
    }
    public void DeletePreview()
    {
        Preview = null;
    }

    #region Descriptions
    public void AddDescription(Guid language, bool isOriginal)
    {
        if (_descriptions.Any(q => q.IsOriginal) && isOriginal) throw new Exception("Could not add one more original description");
        _descriptions.Add(new DescriptionItem { LanguageId = language, IsOriginal = isOriginal});
    }

    public void RemoveDescription(Guid descriptionId)
    {
        var description = GetDescription(descriptionId);
        //if (description.IsOriginal) throw new Exception($"Unable to remove original description");
        _descriptions.Remove(description);
    }

    public void SetDescriptionValue(Guid descriptionId, string value)
    {
        var description = GetDescription(descriptionId);
        description.SetValue(value);
    }

    private DescriptionItem GetDescription(Guid descriptionId)
    {
        return _descriptions.FirstOrDefault(q => q.Id == descriptionId) ?? throw new Exception($"Description with id [{descriptionId}] is not found");
    }
    #endregion

    #region Genres
    public void AddGenre(Guid genreId)
    {
        _genres.Add(new Genre_Percentage { GenreId = genreId });
    }

    public void RemoveGenre(Guid genreItemId)
    {
        var genre = GetGenreItem(genreItemId);
        _genres.Remove(genre);
    }

    public void AddGenreValue(Guid genreItemId, decimal value)
    {
        var genre = GetGenreItem(genreItemId);
        genre.SetValue(value);
    }
    private Genre_Percentage GetGenreItem(Guid genreItemId)
    {
        return _genres.FirstOrDefault(q => q.Id == genreItemId) ?? throw new Exception($"Genre item with id [{genreItemId}] is not found");
    }
    #endregion

    #region RelatedContents
    public void AddRelatedContent(MediaInfoType type)
    {
        _relatedContent.Add(new MediaInfo { Type = type });
    }

    public void RemoveRelatedContent(Guid relatedContentId)
    {
        var relatedContent = GetRelatedContent(relatedContentId);
        _relatedContent.Remove(relatedContent);

    }

    public void AddRelatedContent(Guid relatedContentId, string url)
    {
        var relatedContent = GetRelatedContent(relatedContentId);
        relatedContent.SetUrl(url);
    }

    public MediaInfo GetRelatedContent(Guid relatedContentId)
    {
        return _relatedContent.FirstOrDefault(q => q.Id == relatedContentId) ?? throw new Exception($"Related content with id [{relatedContentId}] is not found");
    }
    #endregion

    public void SetAnnouncementDate(DateTimeOffset value)
    {
        AnnouncementDate = value;
    }
    public void SetEstimatedReleaseDate(DateTimeOffset value)
    {
        EstimatedReleaseDate = value;
    }
    public void SetReleaseDate(DateTimeOffset value)
    {
        ReleaseDate = value;
    }
}
