using System.Net;
using adas_core.Authentication.Attributes;
using adas_core.Domain.Enums;
using adas_core.module.ProxyDevices.Services;
using Microsoft.AspNetCore.Mvc;

namespace adas_core.Controllers;

[Route("proxy-devices")]
[ApiController]
public class ProxyDeviceController(IProxyDeviceService proxyDeviceService) : ControllerBase
{
    /// <summary>
    /// Retrieves a media stream for the specified device by delegating the request to the proxy device service.
    /// When the proxy call is not successful, the upstream status code is returned as-is; otherwise the response
    /// stream is forwarded with the original content type, falling back to "multipart/x-mixed-replace" when no
    /// content type is provided, and the response content length is set when known.
    /// </summary>
    /// <param name="deviceId">The unique identifier of the device whose stream should be retrieved.</param>
    /// <returns>A <see cref="FileStreamResult"/> containing the proxied device stream, or a <see cref="StatusCodeResult"/> reflecting the upstream HTTP status when the proxy call fails.</returns>
    [HttpGet("{deviceId}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    public async Task<IActionResult> GetStreamById(string deviceId)
    {
        var response = await proxyDeviceService.Process(deviceId);
        if (!response.IsSuccessStatusCode) return new StatusCodeResult((int)response.StatusCode);
        var stream = await response.Content.ReadAsStreamAsync();
        if (response.Content.Headers.ContentLength > 0) Response.ContentLength = response.Content.Headers.ContentLength;
        return new FileStreamResult(stream,
            response.Content.Headers.ContentType?.ToString() ?? "multipart/x-mixed-replace"); // Set MIME type as needed
    }

    /// <summary>
    /// Retrieves the content associated with the specified device by proxying the request through the device service.
    /// Forwards the upstream content length and content type headers to the response when available, and returns the resulting content as a stream.
    /// </summary>
    /// <param name="deviceId">The unique identifier of the device whose content is being requested.</param>
    /// <returns>An <see cref="IActionResult"/> containing the proxied content stream for the specified device.</returns>
    [HttpGet("{deviceId}/content")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    public async Task<IActionResult> GetContentById(string deviceId)
    {
        var response = await proxyDeviceService.Process(deviceId);
        var content = await response.Content.ReadAsStreamAsync();
        if (response.Content.Headers.ContentLength > 0) Response.ContentLength = response.Content.Headers.ContentLength;
        if (response.Content.Headers.ContentType != null)
            Response.ContentType = response.Content.Headers.ContentType?.ToString() ?? "";
        return Ok(content);
    }

    /// <summary>
    /// Streams MJPEG video from the specified device by proxying the request through an external service and writing the response body to the client.
    /// Forwards the upstream status code when the proxy call is not successful, defaults the response content type to <c>multipart/x-mixed-replace</c> when none is provided, and returns 404 (or the original status code) if the upstream request fails.
    /// </summary>
    /// <param name="deviceId">The identifier of the device whose MJPEG stream should be retrieved and forwarded to the caller.</param>
    [HttpGet("{deviceId}/mjpeg-stream")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    public async Task GetAsMpegStreamById(string deviceId)
    {
        try
        {

            using var cts = CancellationTokenSource.CreateLinkedTokenSource(HttpContext.RequestAborted);
            //cts.CancelAfter(TimeSpan.FromMinutes(5));

            var response = await proxyDeviceService.Stream(deviceId);

            if (!response.IsSuccessStatusCode)
            {
                Response.StatusCode = (int)response.StatusCode;
                return;
            }

            if (response.Content.Headers.ContentType != null)
                Response.ContentType = response.Content.Headers.ContentType?.ToString() ??
                                       "multipart/x-mixed-replace;boundary=my-boundary";
            await using var stream = await response.Content.ReadAsStreamAsync(cts.Token);
            // Buffer for reading the stream
            var buffer = new byte[4096];
            int bytesRead;


            while (!cts.Token.IsCancellationRequested && (bytesRead = await stream.ReadAsync(buffer, cts.Token)) > 0)
            {
                await Response.Body.WriteAsync(buffer.AsMemory(0, bytesRead), cts.Token);
                await Response.Body.FlushAsync(cts.Token);
            }
        }
        catch (HttpRequestException e)
        {
            Response.StatusCode = (int)(e.StatusCode ?? HttpStatusCode.NotFound);
        }
    }
}