using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Jellyfin.Api.Controllers
{
    /// 
    /// Channels Controller.
    /// 
    [Authorize(Policy = Policies.DefaultAuthorization)]
    public class ChannelsController : BaseJellyfinApiController
    {
        private readonly IChannelManager _channelManager;
        private readonly IUserManager _userManager;
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// Instance of the  interface.
        /// Instance of the  interface.
        public ChannelsController(IChannelManager channelManager, IUserManager userManager)
        {
            _channelManager = channelManager;
            _userManager = userManager;
        }
        /// 
        /// Gets available channels.
        /// 
        /// User Id to filter by. Use  to not filter by user.
        /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
        /// Optional. The maximum number of records to return.
        /// Optional. Filter by channels that support getting latest items.
        /// Optional. Filter by channels that support media deletion.
        /// Optional. Filter by channels that are favorite.
        /// Channels returned.
        /// An  containing the channels.
        [HttpGet]
        [ProducesResponseType(StatusCodes.Status200OK)]
        public ActionResult> GetChannels(
            [FromQuery] Guid? userId,
            [FromQuery] int? startIndex,
            [FromQuery] int? limit,
            [FromQuery] bool? supportsLatestItems,
            [FromQuery] bool? supportsMediaDeletion,
            [FromQuery] bool? isFavorite)
        {
            return _channelManager.GetChannels(new ChannelQuery
            {
                Limit = limit,
                StartIndex = startIndex,
                UserId = userId ?? Guid.Empty,
                SupportsLatestItems = supportsLatestItems,
                SupportsMediaDeletion = supportsMediaDeletion,
                IsFavorite = isFavorite
            });
        }
        /// 
        /// Get all channel features.
        /// 
        /// All channel features returned.
        /// An  containing the channel features.
        [HttpGet("Features")]
        [ProducesResponseType(StatusCodes.Status200OK)]
        public ActionResult> GetAllChannelFeatures()
        {
            return _channelManager.GetAllChannelFeatures();
        }
        /// 
        /// Get channel features.
        /// 
        /// Channel id.
        /// Channel features returned.
        /// An  containing the channel features.
        [HttpGet("{channelId}/Features")]
        public ActionResult GetChannelFeatures([FromRoute, Required] Guid channelId)
        {
            return _channelManager.GetChannelFeatures(channelId);
        }
        /// 
        /// Get channel items.
        /// 
        /// Channel Id.
        /// Optional. Folder Id.
        /// Optional. User Id.
        /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
        /// Optional. The maximum number of records to return.
        /// Optional. Sort Order - Ascending,Descending.
        /// Optional. Specify additional filters to apply.
        /// Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime.
        /// Optional. Specify additional fields of information to return in the output.
        /// Channel items returned.
        /// 
        /// A  representing the request to get the channel items.
        /// The task result contains an  containing the channel items.
        /// 
        [HttpGet("{channelId}/Items")]
        public async Task>> GetChannelItems(
            [FromRoute, Required] Guid channelId,
            [FromQuery] Guid? folderId,
            [FromQuery] Guid? userId,
            [FromQuery] int? startIndex,
            [FromQuery] int? limit,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields)
        {
            var user = userId.HasValue && !userId.Equals(Guid.Empty)
                ? _userManager.GetUserById(userId.Value)
                : null;
            var query = new InternalItemsQuery(user)
            {
                Limit = limit,
                StartIndex = startIndex,
                ChannelIds = new[] { channelId },
                ParentId = folderId ?? Guid.Empty,
                OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder),
                DtoOptions = new DtoOptions { Fields = fields }
            };
            foreach (var filter in filters)
            {
                switch (filter)
                {
                    case ItemFilter.IsFolder:
                        query.IsFolder = true;
                        break;
                    case ItemFilter.IsNotFolder:
                        query.IsFolder = false;
                        break;
                    case ItemFilter.IsUnplayed:
                        query.IsPlayed = false;
                        break;
                    case ItemFilter.IsPlayed:
                        query.IsPlayed = true;
                        break;
                    case ItemFilter.IsFavorite:
                        query.IsFavorite = true;
                        break;
                    case ItemFilter.IsResumable:
                        query.IsResumable = true;
                        break;
                    case ItemFilter.Likes:
                        query.IsLiked = true;
                        break;
                    case ItemFilter.Dislikes:
                        query.IsLiked = false;
                        break;
                    case ItemFilter.IsFavoriteOrLikes:
                        query.IsFavoriteOrLiked = true;
                        break;
                }
            }
            return await _channelManager.GetChannelItems(query, CancellationToken.None).ConfigureAwait(false);
        }
        /// 
        /// Gets latest channel items.
        /// 
        /// Optional. User Id.
        /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
        /// Optional. The maximum number of records to return.
        /// Optional. Specify additional filters to apply.
        /// Optional. Specify additional fields of information to return in the output.
        /// Optional. Specify one or more channel id's, comma delimited.
        /// Latest channel items returned.
        /// 
        /// A  representing the request to get the latest channel items.
        /// The task result contains an  containing the latest channel items.
        /// 
        [HttpGet("Items/Latest")]
        public async Task>> GetLatestChannelItems(
            [FromQuery] Guid? userId,
            [FromQuery] int? startIndex,
            [FromQuery] int? limit,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] channelIds)
        {
            var user = userId.HasValue && !userId.Equals(Guid.Empty)
                ? _userManager.GetUserById(userId.Value)
                : null;
            var query = new InternalItemsQuery(user)
            {
                Limit = limit,
                StartIndex = startIndex,
                ChannelIds = channelIds,
                DtoOptions = new DtoOptions { Fields = fields }
            };
            foreach (var filter in filters)
            {
                switch (filter)
                {
                    case ItemFilter.IsFolder:
                        query.IsFolder = true;
                        break;
                    case ItemFilter.IsNotFolder:
                        query.IsFolder = false;
                        break;
                    case ItemFilter.IsUnplayed:
                        query.IsPlayed = false;
                        break;
                    case ItemFilter.IsPlayed:
                        query.IsPlayed = true;
                        break;
                    case ItemFilter.IsFavorite:
                        query.IsFavorite = true;
                        break;
                    case ItemFilter.IsResumable:
                        query.IsResumable = true;
                        break;
                    case ItemFilter.Likes:
                        query.IsLiked = true;
                        break;
                    case ItemFilter.Dislikes:
                        query.IsLiked = false;
                        break;
                    case ItemFilter.IsFavoriteOrLikes:
                        query.IsFavoriteOrLiked = true;
                        break;
                }
            }
            return await _channelManager.GetLatestChannelItems(query, CancellationToken.None).ConfigureAwait(false);
        }
    }
}