using Microsoft.AspNetCore.Mvc;

namespace DeepDrftPublic.Controllers;

/// <summary>
/// Proxies the public release read surface (Phase 9) to DeepDrftAPI so the browser never
/// makes a cross-origin request. Mirrors <see cref="TrackProxyController"/>: the WASM client
/// issues relative <c>api/release/*</c> requests against this host, which forwards them
/// upstream. SSR prerender calls DeepDrftAPI directly via the same named client — no proxy
/// hop on the server side. All forwarded routes are unauthenticated reads.
/// </summary>
[ApiController]
[Route("api/release")]
public class ReleaseProxyController : ControllerBase
{
    private readonly HttpClient _upstream;
    private readonly ILogger<ReleaseProxyController> _logger;

    public ReleaseProxyController(IHttpClientFactory httpClientFactory, ILogger<ReleaseProxyController> logger)
    {
        _upstream = httpClientFactory.CreateClient("DeepDrft.API");
        _logger = logger;
    }

    /// <summary>Proxies the paged release list, forwarding the optional medium, search (q), genre, and sort params.</summary>
    [HttpGet]
    public async Task<ActionResult> GetReleases(
        [FromQuery] string? medium = null,
        [FromQuery] string? q = null,
        [FromQuery] string? genre = null,
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 20,
        [FromQuery] string? sortColumn = null,
        [FromQuery] bool sortDescending = false,
        CancellationToken ct = default)
    {
        var query = $"api/release?page={page}&pageSize={pageSize}&sortDescending={sortDescending}";
        if (!string.IsNullOrWhiteSpace(medium))
            query += $"&medium={Uri.EscapeDataString(medium)}";
        if (!string.IsNullOrWhiteSpace(q))
            query += $"&q={Uri.EscapeDataString(q)}";
        if (!string.IsNullOrWhiteSpace(genre))
            query += $"&genre={Uri.EscapeDataString(genre)}";
        if (!string.IsNullOrWhiteSpace(sortColumn))
            query += $"&sortColumn={Uri.EscapeDataString(sortColumn)}";

        return await RelayJson(query, "release list");
    }

    /// <summary>Proxies a single release, addressed by its opaque EntryKey. A 404 (no such release) passes through verbatim.</summary>
    [HttpGet("{entryKey}")]
    public async Task<ActionResult> GetReleaseByEntryKey(string entryKey, CancellationToken ct = default)
        => await RelayJson($"api/release/{Uri.EscapeDataString(entryKey)}", $"release {entryKey}", ct);

    // Small JSON payloads, buffered and relayed. Non-success statuses (notably 404) pass through
    // so the client renders them as valid states rather than collapsing to a 502.
    private async Task<ActionResult> RelayJson(string upstreamPath, string description, CancellationToken ct = default)
    {
        HttpResponseMessage upstream;
        try
        {
            upstream = await _upstream.GetAsync(upstreamPath, HttpCompletionOption.ResponseHeadersRead, ct);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Upstream call to DeepDrftAPI {Description} failed", description);
            return StatusCode(502, "Upstream unavailable");
        }

        using (upstream)
        {
            if (!upstream.IsSuccessStatusCode)
            {
                _logger.LogWarning("DeepDrftAPI {Description} returned {Status}", description, (int)upstream.StatusCode);
                return StatusCode((int)upstream.StatusCode);
            }

            var json = await upstream.Content.ReadAsStringAsync(ct);
            return Content(json, "application/json");
        }
    }
}
