using System.ComponentModel.DataAnnotations;
using ErsatzTV.Application.Resolutions;
using ErsatzTV.Controllers.Api.Requests;
using ErsatzTV.Core;
using ErsatzTV.Core.Api.Settings;
using ErsatzTV.Extensions;
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace ErsatzTV.Controllers.Api;

[ApiController]
[EndpointGroupName("general")]
public class ResolutionController(IMediator mediator) : ControllerBase
{
    [HttpGet("/api/v1/ffmpeg/resolution/by-name/{name}", Name = "GetResolutionByName")]
    [Tags("Settings")]
    [EndpointSummary("Get a resolution by name")]
    [ProducesResponseType(typeof(ResolutionResponseModel), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
    public async Task<ActionResult<ResolutionResponseModel>> GetResolutionByName(
        string name,
        CancellationToken cancellationToken)
    {
        Option<ResolutionViewModel> result = await mediator.Send(new GetResolutionByName(name), cancellationToken);
        return result.Match<ActionResult<ResolutionResponseModel>>(
            i => Ok(ProjectToResponseModel(i)),
            () => NotFound());
    }

    [HttpGet("/api/v1/settings/resolutions", Name = "GetResolutions")]
    [Tags("Settings")]
    [EndpointSummary("Get all resolutions, including custom resolutions")]
    [ProducesResponseType(typeof(List<ResolutionResponseModel>), StatusCodes.Status200OK)]
    public async Task<List<ResolutionResponseModel>> GetAll(CancellationToken cancellationToken)
    {
        List<ResolutionViewModel> resolutions = await mediator.Send(new GetAllResolutions(), cancellationToken);
        return resolutions.Map(ProjectToResponseModel).ToList();
    }

    [HttpPost("/api/v1/settings/resolutions", Name = "CreateResolution")]
    [Tags("Settings")]
    [EndpointSummary("Create a custom resolution")]
    [ProducesResponseType(typeof(ResolutionResponseModel), StatusCodes.Status201Created)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)]
    public async Task<IActionResult> Create(
        [Required] [FromBody]
        CreateResolutionRequest request,
        CancellationToken cancellationToken)
    {
        Option<BaseError> result = await mediator.Send(request.ToCommand(), cancellationToken);
        return await result.Match(
            Some: error => Task.FromResult(error.ToErrorResult()),
            None: async () =>
            {
                string name = $"{request.Width}x{request.Height}";
                Option<ResolutionViewModel> resolution =
                    await mediator.Send(new GetResolutionByName(name), cancellationToken);
                return resolution.Match(
                    Some: vm => (IActionResult)new CreatedResult(
                        $"/api/v1/settings/resolutions/{vm.Id}",
                        ProjectToResponseModel(vm)),
                    None: () => ApiResults.NotFoundProblem());
            });
    }

    [HttpDelete("/api/v1/settings/resolutions/{id:int}", Name = "DeleteResolution")]
    [Tags("Settings")]
    [EndpointSummary("Delete a custom resolution")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)]
    public async Task<IActionResult> Delete(int id, CancellationToken cancellationToken)
    {
        Option<BaseError> result = await mediator.Send(new DeleteCustomResolution(id), cancellationToken);
        return result.Match<IActionResult>(
            Some: error => error.ToErrorResult(),
            None: () => new NoContentResult());
    }

    private static ResolutionResponseModel ProjectToResponseModel(ResolutionViewModel vm) =>
        new(vm.Id, vm.Name, vm.Width, vm.Height, vm.IsCustom);
}

