using LiteCqrs;
using TeleWave.Api.Common;
using TeleWave.Application.Library.Genres;
using TeleWave.Application.Library.Genres.CreateGenre;
using TeleWave.Application.Library.Genres.DeleteGenre;
using TeleWave.Application.Library.Genres.ListGenres;
using TeleWave.Application.Library.Genres.UpdateGenre;
using TeleWave.Infrastructure.Identity;

namespace TeleWave.Api.Endpoints;

public static class GenreEndpoints
{
    public static IEndpointRouteBuilder MapGenreEndpoints(this IEndpointRouteBuilder app)
    {
        var admin = app.MapGroup("/api/admin/genres")
            .WithTags("Admin.Genres")
            .RequireAuthorization(policy => policy.RequireRole(RoleNames.Admin));

        admin.MapGet("", ListGenres).Produces<IReadOnlyList<GenreDto>>();
        admin.MapPost("", CreateGenre).Produces<CreatedIdResponse>(StatusCodes.Status201Created);
        admin.MapPut("/{id:guid}", UpdateGenre).Produces(StatusCodes.Status204NoContent);
        admin.MapDelete("/{id:guid}", DeleteGenre).Produces(StatusCodes.Status204NoContent);

        return app;
    }

    private static async Task<IResult> ListGenres(
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var result = await sender.Send(new ListGenresQuery(), cancellationToken);
        return Results.Ok(result);
    }

    private static async Task<IResult> CreateGenre(
        CreateGenreCommand command,
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var result = await sender.Send(command, cancellationToken);
        return result.IsSuccess
            ? Results.Created(
                $"/api/admin/genres/{result.Value}",
                new CreatedIdResponse(result.Value)
            )
            : result.ToHttpResult();
    }

    private static async Task<IResult> UpdateGenre(
        Guid id,
        UpdateGenreBody body,
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var result = await sender.Send(
            new UpdateGenreCommand(id, body.Name, body.SortOrder, body.Aliases),
            cancellationToken
        );
        return result.ToHttpResult();
    }

    private static async Task<IResult> DeleteGenre(
        Guid id,
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var result = await sender.Send(new DeleteGenreCommand(id), cancellationToken);
        return result.ToHttpResult();
    }
}

public sealed record UpdateGenreBody(string Name, int SortOrder, IReadOnlyList<string>? Aliases);
