using LiteCqrs;
using TeleWave.Api.Common;
using TeleWave.Application.Admin.Roles.ChangeUserRole;
using TeleWave.Application.Admin.Roles.CreateRole;
using TeleWave.Application.Admin.Roles.DeleteRole;
using TeleWave.Application.Admin.Roles.ListRoles;
using TeleWave.Application.Admin.Roles.UpdateRole;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Infrastructure.Identity;

namespace TeleWave.Api.Endpoints;

public static class RoleEndpoints
{
    public static IEndpointRouteBuilder MapRoleEndpoints(this IEndpointRouteBuilder app)
    {
        var admin = app.MapGroup("/api/admin")
            .WithTags("Admin.Roles")
            .RequireAuthorization(policy => policy.RequireRole(RoleNames.Admin));

        admin.MapGet("/roles", ListRoles).Produces<IReadOnlyList<RoleDto>>();
        admin.MapPost("/roles", CreateRole).Produces<RoleDto>();
        admin.MapPut("/roles/{id:guid}", UpdateRole).Produces<RoleDto>();
        admin.MapDelete("/roles/{id:guid}", DeleteRole).Produces(StatusCodes.Status204NoContent);
        admin
            .MapPatch("/users/{id:guid}/role", ChangeUserRole)
            .Produces(StatusCodes.Status204NoContent);

        return app;
    }

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

    private static async Task<IResult> CreateRole(
        CreateRoleCommand command,
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var result = await sender.Send(command, cancellationToken);
        return result.ToHttpResult();
    }

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

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

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

public sealed record UpdateRoleBody(string Name);

public sealed record ChangeUserRoleBody(Guid RoleId);
