using System.Diagnostics.CodeAnalysis;
using ErsatzTV.Core;
using ErsatzTV.Core.Errors;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace ErsatzTV.Extensions;
///
/// REST status-code mapping helpers for the JSON write/read API (slice #2a).
/// These are additive and must not change the behavior of the existing
/// / helpers,
/// which IptvController and other read endpoints depend on.
///
[SuppressMessage("ReSharper", "VSTHRD003")]
public static class ApiResults
{
///
/// Maps a failure to 404 when it is a , 412 when it is a
/// (optimistic-concurrency mismatch, issue #253),
/// otherwise 422.
///
public static IActionResult ToErrorResult(this BaseError error) =>
error switch
{
NotFoundError =>
new NotFoundObjectResult(CreateProblemDetails(404, "Resource not found", error.Value)),
PreconditionFailedError =>
new ObjectResult(CreateProblemDetails(412, "Precondition Failed", error.Value))
{
StatusCode = StatusCodes.Status412PreconditionFailed
},
_ =>
new UnprocessableEntityObjectResult(CreateProblemDetails(422, "Validation failed", error.Value))
};
/// Right: 201 Created with a Location header and body; Left: 404 (NotFound) or 422.
public static IActionResult ToCreatedResult
(
this Either either,
Func location,
Func
body) =>
either.Match(
Left: error => error.ToErrorResult(),
Right: value => new CreatedResult(location(value), body(value)));
/// Right: 200 with body; Left: 404 (NotFound) or 422.
public static IActionResult ToUpdatedResult
(this Either either) =>
either.Match(
Left: error => error.ToErrorResult(),
Right: value => (IActionResult)new OkObjectResult(value));
/// Right(Unit): 204 No Content; Left: 404 (NotFound) or 422.
public static IActionResult ToDeletedResult(this Either either) =>
either.Match(
Left: error => error.ToErrorResult(),
Right: _ => (IActionResult)new NoContentResult());
/// Some: 200 with body; None: 404.
public static IActionResult ToGetResult(this Option option) =>
option.Match(
Some: value => (IActionResult)new OkObjectResult(value),
None: () => NotFoundProblem());
public static IActionResult NotFoundProblem(string detail = "Resource not found") =>
new NotFoundObjectResult(CreateProblemDetails(404, "Resource not found", detail));
///
/// 409 directly — for a mutation that races a background operation
/// holding a lock (e.g. a playout build in flight). Mirrors .
///
public static IActionResult ConflictProblem(string title, string detail) =>
new ConflictObjectResult(CreateProblemDetails(409, title, detail));
private static ProblemDetails CreateProblemDetails(int status, string title, string detail) =>
new()
{
Status = status,
Title = title,
Detail = detail
};
}