using System;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.PlaybackDtos;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Dlna;
namespace Jellyfin.Api.Models.StreamingDtos
{
    /// 
    /// The stream state dto.
    /// 
    public class StreamState : EncodingJobInfo, IDisposable
    {
        private readonly IMediaSourceManager _mediaSourceManager;
        private readonly TranscodingJobHelper _transcodingJobHelper;
        private bool _disposed;
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// Instance of the  interface.
        /// The .
        /// The  singleton.
        public StreamState(IMediaSourceManager mediaSourceManager, TranscodingJobType transcodingType, TranscodingJobHelper transcodingJobHelper)
            : base(transcodingType)
        {
            _mediaSourceManager = mediaSourceManager;
            _transcodingJobHelper = transcodingJobHelper;
        }
        /// 
        /// Gets or sets the requested url.
        /// 
        public string? RequestedUrl { get; set; }
        /// 
        /// Gets or sets the request.
        /// 
        public StreamingRequestDto Request
        {
            get => (StreamingRequestDto)BaseRequest;
            set
            {
                BaseRequest = value;
                IsVideoRequest = VideoRequest != null;
            }
        }
        /// 
        /// Gets the video request.
        /// 
        public VideoRequestDto? VideoRequest => Request as VideoRequestDto;
        /// 
        /// Gets or sets the direct stream provicer.
        /// 
        /// 
        /// Deprecated.
        /// 
        public IDirectStreamProvider? DirectStreamProvider { get; set; }
        /// 
        /// Gets or sets the path to wait for.
        /// 
        public string? WaitForPath { get; set; }
        /// 
        /// Gets a value indicating whether the request outputs video.
        /// 
        public bool IsOutputVideo => Request is VideoRequestDto;
        /// 
        /// Gets the segment length.
        /// 
        public int SegmentLength
        {
            get
            {
                if (Request.SegmentLength.HasValue)
                {
                    return Request.SegmentLength.Value;
                }
                if (EncodingHelper.IsCopyCodec(OutputVideoCodec))
                {
                    var userAgent = UserAgent ?? string.Empty;
                    if (userAgent.IndexOf("AppleTV", StringComparison.OrdinalIgnoreCase) != -1
                        || userAgent.IndexOf("cfnetwork", StringComparison.OrdinalIgnoreCase) != -1
                        || userAgent.IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1
                        || userAgent.IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1
                        || userAgent.IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1)
                    {
                        return 6;
                    }
                    if (IsSegmentedLiveStream)
                    {
                        return 3;
                    }
                    return 6;
                }
                return 3;
            }
        }
        /// 
        /// Gets the minimum number of segments.
        /// 
        public int MinSegments
        {
            get
            {
                if (Request.MinSegments.HasValue)
                {
                    return Request.MinSegments.Value;
                }
                return SegmentLength >= 10 ? 2 : 3;
            }
        }
        /// 
        /// Gets or sets the user agent.
        /// 
        public string? UserAgent { get; set; }
        /// 
        /// Gets or sets a value indicating whether to estimate the content length.
        /// 
        public bool EstimateContentLength { get; set; }
        /// 
        /// Gets or sets the transcode seek info.
        /// 
        public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
        /// 
        /// Gets or sets a value indicating whether to enable dlna headers.
        /// 
        public bool EnableDlnaHeaders { get; set; }
        /// 
        /// Gets or sets the device profile.
        /// 
        public DeviceProfile? DeviceProfile { get; set; }
        /// 
        /// Gets or sets the transcoding job.
        /// 
        public TranscodingJobDto? TranscodingJob { get; set; }
        /// 
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        /// 
        public override void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
        {
            _transcodingJobHelper.ReportTranscodingProgress(TranscodingJob!, this, transcodingPosition, framerate, percentComplete, bytesTranscoded, bitRate);
        }
        /// 
        /// Disposes the stream state.
        /// 
        /// Whether the object is currently being disposed.
        protected virtual void Dispose(bool disposing)
        {
            if (_disposed)
            {
                return;
            }
            if (disposing)
            {
                // REVIEW: Is this the right place for this?
                if (MediaSource.RequiresClosing
                    && string.IsNullOrWhiteSpace(Request.LiveStreamId)
                    && !string.IsNullOrWhiteSpace(MediaSource.LiveStreamId))
                {
                    _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).GetAwaiter().GetResult();
                }
            }
            TranscodingJob = null;
            _disposed = true;
        }
    }
}