using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Api.Models.StreamingDtos;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Querying;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Jellyfin.Api.Controllers
{
    /// 
    /// The videos controller.
    /// 
    public class VideosController : BaseJellyfinApiController
    {
        private readonly ILibraryManager _libraryManager;
        private readonly IUserManager _userManager;
        private readonly IDtoService _dtoService;
        private readonly IDlnaManager _dlnaManager;
        private readonly IAuthorizationContext _authContext;
        private readonly IMediaSourceManager _mediaSourceManager;
        private readonly IServerConfigurationManager _serverConfigurationManager;
        private readonly IMediaEncoder _mediaEncoder;
        private readonly IDeviceManager _deviceManager;
        private readonly TranscodingJobHelper _transcodingJobHelper;
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly EncodingHelper _encodingHelper;
        private readonly TranscodingJobType _transcodingJobType = TranscodingJobType.Progressive;
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// Instance of the  interface.
        /// Instance of the  interface.
        /// Instance of the  interface.
        /// Instance of the  interface.
        /// Instance of the  interface.
        /// Instance of the  interface.
        /// Instance of the  interface.
        /// Instance of the  interface.
        /// Instance of the  interface.
        /// Instance of the  class.
        /// Instance of the  interface.
        /// Instance of .
        public VideosController(
            ILibraryManager libraryManager,
            IUserManager userManager,
            IDtoService dtoService,
            IDlnaManager dlnaManager,
            IAuthorizationContext authContext,
            IMediaSourceManager mediaSourceManager,
            IServerConfigurationManager serverConfigurationManager,
            IMediaEncoder mediaEncoder,
            IDeviceManager deviceManager,
            TranscodingJobHelper transcodingJobHelper,
            IHttpClientFactory httpClientFactory,
            EncodingHelper encodingHelper)
        {
            _libraryManager = libraryManager;
            _userManager = userManager;
            _dtoService = dtoService;
            _dlnaManager = dlnaManager;
            _authContext = authContext;
            _mediaSourceManager = mediaSourceManager;
            _serverConfigurationManager = serverConfigurationManager;
            _mediaEncoder = mediaEncoder;
            _deviceManager = deviceManager;
            _transcodingJobHelper = transcodingJobHelper;
            _httpClientFactory = httpClientFactory;
            _encodingHelper = encodingHelper;
        }
        /// 
        /// Gets additional parts for a video.
        /// 
        /// The item id.
        /// Optional. Filter by user id, and attach user data.
        /// Additional parts returned.
        /// A  with the parts.
        [HttpGet("{itemId}/AdditionalParts")]
        [Authorize(Policy = Policies.DefaultAuthorization)]
        [ProducesResponseType(StatusCodes.Status200OK)]
        public ActionResult> GetAdditionalPart([FromRoute, Required] Guid itemId, [FromQuery] Guid? userId)
        {
            var user = userId is null || userId.Value.Equals(default)
                ? null
                : _userManager.GetUserById(userId.Value);
            var item = itemId.Equals(default)
                ? (userId is null || userId.Value.Equals(default)
                    ? _libraryManager.RootFolder
                    : _libraryManager.GetUserRootFolder())
                : _libraryManager.GetItemById(itemId);
            var dtoOptions = new DtoOptions();
            dtoOptions = dtoOptions.AddClientFields(Request);
            BaseItemDto[] items;
            if (item is Video video)
            {
                items = video.GetAdditionalParts()
                    .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, video))
                    .ToArray();
            }
            else
            {
                items = Array.Empty();
            }
            var result = new QueryResult(items);
            return result;
        }
        /// 
        /// Removes alternate video sources.
        /// 
        /// The item id.
        /// Alternate sources deleted.
        /// Video not found.
        /// A  indicating success, or a  if the video doesn't exist.
        [HttpDelete("{itemId}/AlternateSources")]
        [Authorize(Policy = Policies.RequiresElevation)]
        [ProducesResponseType(StatusCodes.Status204NoContent)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task DeleteAlternateSources([FromRoute, Required] Guid itemId)
        {
            var video = (Video)_libraryManager.GetItemById(itemId);
            if (video == null)
            {
                return NotFound("The video either does not exist or the id does not belong to a video.");
            }
            if (video.LinkedAlternateVersions.Length == 0)
            {
                video = (Video)_libraryManager.GetItemById(video.PrimaryVersionId);
            }
            foreach (var link in video.GetLinkedAlternateVersions())
            {
                link.SetPrimaryVersionId(null);
                link.LinkedAlternateVersions = Array.Empty();
                await link.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
            }
            video.LinkedAlternateVersions = Array.Empty();
            video.SetPrimaryVersionId(null);
            await video.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
            return NoContent();
        }
        /// 
        /// Merges videos into a single record.
        /// 
        /// Item id list. This allows multiple, comma delimited.
        /// Videos merged.
        /// Supply at least 2 video ids.
        /// A  indicating success, or a  if less than two ids were supplied.
        [HttpPost("MergeVersions")]
        [Authorize(Policy = Policies.RequiresElevation)]
        [ProducesResponseType(StatusCodes.Status204NoContent)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task MergeVersions([FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids)
        {
            var items = ids
                .Select(i => _libraryManager.GetItemById(i))
                .OfType