using System;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading.Tasks;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Helpers;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Jellyfin.Api.Controllers;
/// 
/// The hls segment controller.
/// 
[Route("")]
public class HlsSegmentController : BaseJellyfinApiController
{
    private readonly IFileSystem _fileSystem;
    private readonly IServerConfigurationManager _serverConfigurationManager;
    private readonly ITranscodeManager _transcodeManager;
    /// 
    /// Initializes a new instance of the  class.
    /// 
    /// Instance of the  interface.
    /// Instance of the  interface.
    /// Instance of the  interface.
    public HlsSegmentController(
        IFileSystem fileSystem,
        IServerConfigurationManager serverConfigurationManager,
        ITranscodeManager transcodeManager)
    {
        _fileSystem = fileSystem;
        _serverConfigurationManager = serverConfigurationManager;
        _transcodeManager = transcodeManager;
    }
    /// 
    /// Gets the specified audio segment for an audio item.
    /// 
    /// The item id.
    /// The segment id.
    /// Hls audio segment returned.
    /// A  containing the audio stream.
    // Can't require authentication just yet due to seeing some requests come from Chrome without full query string
    // [Authenticated]
    [HttpGet("Audio/{itemId}/hls/{segmentId}/stream.mp3", Name = "GetHlsAudioSegmentLegacyMp3")]
    [HttpGet("Audio/{itemId}/hls/{segmentId}/stream.aac", Name = "GetHlsAudioSegmentLegacyAac")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesAudioFile]
    [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")]
    public ActionResult GetHlsAudioSegmentLegacy([FromRoute, Required] string itemId, [FromRoute, Required] string segmentId)
    {
        // TODO: Deprecate with new iOS app
        var file = string.Concat(segmentId, Path.GetExtension(Request.Path.Value.AsSpan()));
        var transcodePath = _serverConfigurationManager.GetTranscodePath();
        file = Path.GetFullPath(Path.Combine(transcodePath, file));
        var fileDir = Path.GetDirectoryName(file);
        if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodePath, StringComparison.InvariantCulture))
        {
            return BadRequest("Invalid segment.");
        }
        return FileStreamResponseHelpers.GetStaticFileResult(file, MimeTypes.GetMimeType(file));
    }
    /// 
    /// Gets a hls video playlist.
    /// 
    /// The video id.
    /// The playlist id.
    /// Hls video playlist returned.
    /// A  containing the playlist.
    [HttpGet("Videos/{itemId}/hls/{playlistId}/stream.m3u8")]
    [Authorize]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesPlaylistFile]
    [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")]
    public ActionResult GetHlsPlaylistLegacy([FromRoute, Required] string itemId, [FromRoute, Required] string playlistId)
    {
        var file = string.Concat(playlistId, Path.GetExtension(Request.Path.Value.AsSpan()));
        var transcodePath = _serverConfigurationManager.GetTranscodePath();
        file = Path.GetFullPath(Path.Combine(transcodePath, file));
        var fileDir = Path.GetDirectoryName(file);
        if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodePath, StringComparison.InvariantCulture)
            || Path.GetExtension(file.AsSpan()).Equals(".m3u8", StringComparison.OrdinalIgnoreCase))
        {
            return BadRequest("Invalid segment.");
        }
        return GetFileResult(file, file);
    }
    /// 
    /// Stops an active encoding.
    /// 
    /// The device id of the client requesting. Used to stop encoding processes when needed.
    /// The play session id.
    /// Encoding stopped successfully.
    /// A  indicating success.
    [HttpDelete("Videos/ActiveEncodings")]
    [Authorize]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    public ActionResult StopEncodingProcess(
        [FromQuery, Required] string deviceId,
        [FromQuery, Required] string playSessionId)
    {
        _transcodeManager.KillTranscodingJobs(deviceId, playSessionId, _ => true);
        return NoContent();
    }
    /// 
    /// Gets a hls video segment.
    /// 
    /// The item id.
    /// The playlist id.
    /// The segment id.
    /// The segment container.
    /// Hls video segment returned.
    /// Hls segment not found.
    /// A  containing the video segment.
    // Can't require authentication just yet due to seeing some requests come from Chrome without full query string
    // [Authenticated]
    [HttpGet("Videos/{itemId}/hls/{playlistId}/{segmentId}.{segmentContainer}")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesVideoFile]
    [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")]
    public ActionResult GetHlsVideoSegmentLegacy(
        [FromRoute, Required] string itemId,
        [FromRoute, Required] string playlistId,
        [FromRoute, Required] string segmentId,
        [FromRoute, Required] string segmentContainer)
    {
        var file = string.Concat(segmentId, Path.GetExtension(Request.Path.Value.AsSpan()));
        var transcodeFolderPath = _serverConfigurationManager.GetTranscodePath();
        file = Path.GetFullPath(Path.Combine(transcodeFolderPath, file));
        var fileDir = Path.GetDirectoryName(file);
        if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodeFolderPath, StringComparison.InvariantCulture))
        {
            return BadRequest("Invalid segment.");
        }
        var normalizedPlaylistId = playlistId;
        var filePaths = _fileSystem.GetFilePaths(transcodeFolderPath);
        // Add . to start of segment container for future use.
        segmentContainer = segmentContainer.Insert(0, ".");
        string? playlistPath = null;
        foreach (var path in filePaths)
        {
            var pathExtension = Path.GetExtension(path);
            if ((string.Equals(pathExtension, segmentContainer, StringComparison.OrdinalIgnoreCase)
                 || string.Equals(pathExtension, ".m3u8", StringComparison.OrdinalIgnoreCase))
                && path.Contains(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase))
            {
                playlistPath = path;
                break;
            }
        }
        return playlistPath is null
            ? NotFound("Hls segment not found.")
            : GetFileResult(file, playlistPath);
    }
    private ActionResult GetFileResult(string path, string playlistPath)
    {
        var transcodingJob = _transcodeManager.OnTranscodeBeginRequest(playlistPath, TranscodingJobType.Hls);
        Response.OnCompleted(() =>
        {
            if (transcodingJob is not null)
            {
                _transcodeManager.OnTranscodeEndRequest(transcodingJob);
            }
            return Task.CompletedTask;
        });
        return FileStreamResponseHelpers.GetStaticFileResult(path, MimeTypes.GetMimeType(path));
    }
}