#nullable disable
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Controller.Entities
{
    /// 
    /// Class Video.
    /// 
    public class Video : BaseItem,
        IHasAspectRatio,
        ISupportsPlaceHolders,
        IHasMediaSources
    {
        public Video()
        {
            AdditionalParts = Array.Empty();
            LocalAlternateVersions = Array.Empty();
            SubtitleFiles = Array.Empty();
            AudioFiles = Array.Empty();
            LinkedAlternateVersions = Array.Empty();
        }
        [JsonIgnore]
        public string PrimaryVersionId { get; set; }
        public string[] AdditionalParts { get; set; }
        public string[] LocalAlternateVersions { get; set; }
        public LinkedChild[] LinkedAlternateVersions { get; set; }
        [JsonIgnore]
        public override bool SupportsPlayedStatus => true;
        [JsonIgnore]
        public override bool SupportsPeople => true;
        [JsonIgnore]
        public override bool SupportsInheritedParentImages => true;
        [JsonIgnore]
        public override bool SupportsPositionTicksResume
        {
            get
            {
                var extraType = ExtraType;
                if (extraType.HasValue)
                {
                    if (extraType.Value == Model.Entities.ExtraType.Sample)
                    {
                        return false;
                    }
                    if (extraType.Value == Model.Entities.ExtraType.ThemeVideo)
                    {
                        return false;
                    }
                    if (extraType.Value == Model.Entities.ExtraType.Trailer)
                    {
                        return false;
                    }
                }
                return true;
            }
        }
        [JsonIgnore]
        public override bool SupportsThemeMedia => true;
        /// 
        /// Gets or sets the timestamp.
        /// 
        /// The timestamp.
        public TransportStreamTimestamp? Timestamp { get; set; }
        /// 
        /// Gets or sets the subtitle paths.
        /// 
        /// The subtitle paths.
        public string[] SubtitleFiles { get; set; }
        /// 
        /// Gets or sets the audio paths.
        /// 
        /// The audio paths.
        public string[] AudioFiles { get; set; }
        /// 
        /// Gets or sets a value indicating whether this instance has subtitles.
        /// 
        /// true if this instance has subtitles; otherwise, false.
        public bool HasSubtitles { get; set; }
        public bool IsPlaceHolder { get; set; }
        /// 
        /// Gets or sets the default index of the video stream.
        /// 
        /// The default index of the video stream.
        public int? DefaultVideoStreamIndex { get; set; }
        /// 
        /// Gets or sets the type of the video.
        /// 
        /// The type of the video.
        public VideoType VideoType { get; set; }
        /// 
        /// Gets or sets the type of the iso.
        /// 
        /// The type of the iso.
        public IsoType? IsoType { get; set; }
        /// 
        /// Gets or sets the video3 D format.
        /// 
        /// The video3 D format.
        public Video3DFormat? Video3DFormat { get; set; }
        /// 
        /// Gets or sets the aspect ratio.
        /// 
        /// The aspect ratio.
        public string AspectRatio { get; set; }
        [JsonIgnore]
        public override bool SupportsAddingToPlaylist => true;
        [JsonIgnore]
        public int MediaSourceCount
        {
            get
            {
                return GetMediaSourceCount();
            }
        }
        [JsonIgnore]
        public bool IsStacked => AdditionalParts.Length > 0;
        [JsonIgnore]
        public override bool HasLocalAlternateVersions => LocalAlternateVersions.Length > 0;
        public static IRecordingsManager RecordingsManager { get; set; }
        [JsonIgnore]
        public override SourceType SourceType
        {
            get
            {
                if (IsActiveRecording())
                {
                    return SourceType.LiveTV;
                }
                return base.SourceType;
            }
        }
        [JsonIgnore]
        public bool IsCompleteMedia
        {
            get
            {
                if (SourceType == SourceType.Channel)
                {
                    return !Tags.Contains("livestream", StringComparison.OrdinalIgnoreCase);
                }
                return !IsActiveRecording();
            }
        }
        [JsonIgnore]
        protected virtual bool EnableDefaultVideoUserDataKeys => true;
        [JsonIgnore]
        public override string ContainingFolderPath
        {
            get
            {
                if (IsStacked)
                {
                    return System.IO.Path.GetDirectoryName(Path);
                }
                if (!IsPlaceHolder)
                {
                    if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd)
                    {
                        return Path;
                    }
                }
                return base.ContainingFolderPath;
            }
        }
        [JsonIgnore]
        public override string FileNameWithoutExtension
        {
            get
            {
                if (IsFileProtocol)
                {
                    if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd)
                    {
                        return System.IO.Path.GetFileName(Path);
                    }
                    return System.IO.Path.GetFileNameWithoutExtension(Path);
                }
                return null;
            }
        }
        /// 
        /// Gets a value indicating whether [is3 D].
        /// 
        /// true if [is3 D]; otherwise, false.
        [JsonIgnore]
        public bool Is3D => Video3DFormat.HasValue;
        /// 
        /// Gets the type of the media.
        /// 
        /// The type of the media.
        [JsonIgnore]
        public override MediaType MediaType => MediaType.Video;
        private int GetMediaSourceCount(HashSet callstack = null)
        {
            callstack ??= new();
            if (!string.IsNullOrEmpty(PrimaryVersionId))
            {
                var item = LibraryManager.GetItemById(PrimaryVersionId);
                if (item is Video video)
                {
                    if (callstack.Contains(video.Id))
                    {
                        return video.LinkedAlternateVersions.Length + video.LocalAlternateVersions.Length + 1;
                    }
                    callstack.Add(video.Id);
                    return video.GetMediaSourceCount(callstack);
                }
            }
            return LinkedAlternateVersions.Length + LocalAlternateVersions.Length + 1;
        }
        public override List GetUserDataKeys()
        {
            var list = base.GetUserDataKeys();
            if (EnableDefaultVideoUserDataKeys)
            {
                if (ExtraType.HasValue)
                {
                    var key = this.GetProviderId(MetadataProvider.Tmdb);
                    if (!string.IsNullOrEmpty(key))
                    {
                        list.Insert(0, GetUserDataKey(key));
                    }
                    key = this.GetProviderId(MetadataProvider.Imdb);
                    if (!string.IsNullOrEmpty(key))
                    {
                        list.Insert(0, GetUserDataKey(key));
                    }
                }
                else
                {
                    var key = this.GetProviderId(MetadataProvider.Imdb);
                    if (!string.IsNullOrEmpty(key))
                    {
                        list.Insert(0, key);
                    }
                    key = this.GetProviderId(MetadataProvider.Tmdb);
                    if (!string.IsNullOrEmpty(key))
                    {
                        list.Insert(0, key);
                    }
                }
            }
            return list;
        }
        public void SetPrimaryVersionId(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                PrimaryVersionId = null;
            }
            else
            {
                PrimaryVersionId = id;
            }
            PresentationUniqueKey = CreatePresentationUniqueKey();
        }
        public override string CreatePresentationUniqueKey()
        {
            if (!string.IsNullOrEmpty(PrimaryVersionId))
            {
                return PrimaryVersionId;
            }
            return base.CreatePresentationUniqueKey();
        }
        public override bool CanDownload()
        {
            if (VideoType == VideoType.Dvd || VideoType == VideoType.BluRay)
            {
                return false;
            }
            return IsFileProtocol;
        }
        protected override bool IsActiveRecording()
        {
            return RecordingsManager.GetActiveRecordingInfo(Path) is not null;
        }
        public override bool CanDelete()
        {
            if (IsActiveRecording())
            {
                return false;
            }
            return base.CanDelete();
        }
        public IEnumerable GetAdditionalPartIds()
        {
            return AdditionalParts.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
        }
        public IEnumerable GetLocalAlternateVersionIds()
        {
            return LocalAlternateVersions.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
        }
        private string GetUserDataKey(string providerId)
        {
            var key = providerId + "-" + ExtraType.ToString().ToLowerInvariant();
            // Make sure different trailers have their own data.
            if (RunTimeTicks.HasValue)
            {
                key += "-" + RunTimeTicks.Value.ToString(CultureInfo.InvariantCulture);
            }
            return key;
        }
        public IEnumerable