using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Plugin.SRFPlay.Api.Models;
using Jellyfin.Plugin.SRFPlay.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace Jellyfin.Plugin.SRFPlay.Controllers;

/// <summary>
/// Controller for managing sport livestream recordings.
/// </summary>
[ApiController]
[Route("Plugins/SRFPlay/Recording")]
[Authorize]
public class RecordingController : ControllerBase
{
    private readonly ILogger<RecordingController> _logger;
    private readonly IRecordingService _recordingService;

    /// <summary>
    /// Initializes a new instance of the <see cref="RecordingController"/> class.
    /// </summary>
    /// <param name="logger">The logger.</param>
    /// <param name="recordingService">The recording service.</param>
    public RecordingController(
        ILogger<RecordingController> logger,
        IRecordingService recordingService)
    {
        _logger = logger;
        _recordingService = recordingService;
    }

    /// <summary>
    /// Serves the recording manager page accessible to any authenticated user.
    /// </summary>
    /// <returns>The recording manager HTML page.</returns>
    [HttpGet("Page")]
    [AllowAnonymous]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public IActionResult GetRecordingPage()
    {
        var assembly = Assembly.GetExecutingAssembly();
        var resourceStream = assembly.GetManifestResourceStream("Jellyfin.Plugin.SRFPlay.Configuration.recordingPage.html");

        if (resourceStream == null)
        {
            return NotFound("Recording page not found");
        }

        return File(resourceStream, "text/html");
    }

    /// <summary>
    /// Gets upcoming sport livestreams available for recording.
    /// </summary>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns>List of upcoming livestreams.</returns>
    [HttpGet("Schedule")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public async Task<IActionResult> GetSchedule(CancellationToken cancellationToken)
    {
        var schedule = await _recordingService.GetUpcomingScheduleAsync(cancellationToken).ConfigureAwait(false);
        return Ok(schedule);
    }

    /// <summary>
    /// Schedules a livestream for recording by URN.
    /// </summary>
    /// <param name="urn">The SRF URN.</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns>The created recording entry.</returns>
    [HttpPost("Schedule/{urn}")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> ScheduleRecording(
        [FromRoute] string urn,
        CancellationToken cancellationToken)
    {
        if (string.IsNullOrEmpty(urn))
        {
            return BadRequest("URN is required");
        }

        // URN comes URL-encoded with colons, decode it
        urn = System.Net.WebUtility.UrlDecode(urn);

        _logger.LogInformation("Scheduling recording for URN: {Urn}", urn);
        var entry = await _recordingService.ScheduleRecordingAsync(urn, cancellationToken).ConfigureAwait(false);
        return Ok(entry);
    }

    /// <summary>
    /// Cancels a scheduled recording.
    /// </summary>
    /// <param name="id">The recording ID.</param>
    /// <returns>OK or NotFound.</returns>
    [HttpDelete("Schedule/{id}")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public IActionResult CancelRecording([FromRoute] string id)
    {
        return _recordingService.CancelRecording(id) ? Ok() : NotFound();
    }

    /// <summary>
    /// Gets currently active recordings.
    /// </summary>
    /// <returns>List of active recordings.</returns>
    [HttpGet("Active")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public IActionResult GetActiveRecordings()
    {
        var active = _recordingService.GetRecordings(RecordingState.Recording);
        return Ok(active);
    }

    /// <summary>
    /// Stops an active recording.
    /// </summary>
    /// <param name="id">The recording ID.</param>
    /// <returns>OK or NotFound.</returns>
    [HttpPost("Active/{id}/Stop")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public IActionResult StopRecording([FromRoute] string id)
    {
        return _recordingService.StopRecording(id) ? Ok() : NotFound();
    }

    /// <summary>
    /// Gets completed recordings.
    /// </summary>
    /// <returns>List of completed recordings.</returns>
    [HttpGet("Completed")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public IActionResult GetCompletedRecordings()
    {
        var completed = _recordingService.GetRecordings(RecordingState.Completed);
        return Ok(completed);
    }

    /// <summary>
    /// Gets all recordings (all states).
    /// </summary>
    /// <returns>List of all recordings.</returns>
    [HttpGet("All")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public IActionResult GetAllRecordings()
    {
        var all = _recordingService.GetRecordings();
        return Ok(all);
    }

    /// <summary>
    /// Deletes a completed recording and its file.
    /// </summary>
    /// <param name="id">The recording ID.</param>
    /// <param name="deleteFile">Whether to delete the file too.</param>
    /// <returns>OK or NotFound.</returns>
    [HttpDelete("Completed/{id}")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public IActionResult DeleteRecording(
        [FromRoute] string id,
        [FromQuery] bool deleteFile = true)
    {
        return _recordingService.DeleteRecording(id, deleteFile) ? Ok() : NotFound();
    }
}
