using Femto.Api.Controllers.Posts.Dto;
using Femto.Common;
using Femto.Modules.Blog.Application;
using Femto.Modules.Blog.Application.Commands.AddPostComment;
using Femto.Modules.Blog.Application.Commands.AddPostReaction;
using Femto.Modules.Blog.Application.Commands.ClearPostReaction;
using Femto.Modules.Blog.Application.Commands.CreatePost;
using Femto.Modules.Blog.Application.Commands.DeletePost;
using Femto.Modules.Blog.Application.Queries.GetPosts;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Femto.Api.Controllers.Posts;

[ApiController]
[Route("posts")]
public class PostsController(IBlogModule blogModule, ICurrentUserContext currentUserContext, IAuthorizationService auth)
    : ControllerBase
{
    [HttpGet]
    public async Task<ActionResult<LoadPostsResponse>> LoadPosts(
        [FromQuery] GetPublicPostsSearchParams searchParams,
        CancellationToken cancellationToken
    )
    {
        var res = await blogModule.Query(
            new GetPostsQuery(currentUserContext.CurrentUser?.Id)
            {
                After = searchParams.After,
                Amount = searchParams.Amount ?? 20,
                AuthorId = searchParams.AuthorId,
                Author = searchParams.Author,
            },
            cancellationToken
        );

        return new LoadPostsResponse(res.Posts.Select(PostDto.FromModel));
    }

    [HttpPost]
    [Authorize]
    public async Task<ActionResult<CreatePostResponse>> CreatePost(
        [FromBody] CreatePostRequest req,
        CancellationToken cancellationToken
    )
    {
        var post = await blogModule.Command(
            new CreatePostCommand(
                req.AuthorId,
                req.Content,
                req.Media.Select(
                    (media, idx) =>
                        new CreatePostMedia(
                            media.MediaId,
                            media.Url,
                            media.Type,
                            idx,
                            media.Width,
                            media.Height
                        )
                ),
                req.IsPublic,
                currentUserContext.CurrentUser!
            ),
            cancellationToken
        );

        return new CreatePostResponse(PostDto.FromModel(post));
    }

    [HttpGet("{postId}")]
    public async Task<ActionResult<GetPostResponse>> GetPost(
        Guid postId,
        CancellationToken cancellationToken
    )
    {
        var result = await blogModule.Query(
            new GetPostsQuery(postId, currentUserContext.CurrentUser?.Id),
            cancellationToken
        );

        var post = result.Posts.SingleOrDefault();

        if (post is null)
            return NotFound();

        return new GetPostResponse(PostDto.FromModel(post));
    }

    [HttpDelete("{postId}")]
    [Authorize]
    public async Task DeletePost(Guid postId, CancellationToken cancellationToken)
    {
        await blogModule.Command(
            new DeletePostCommand(postId, currentUserContext.CurrentUser!.Id),
            cancellationToken
        );
    }

    [HttpPost("{postId}/reactions")]
    [Authorize]
    public async Task<ActionResult> AddPostReaction(
        Guid postId,
        [FromBody] AddPostReactionRequest request,
        CancellationToken cancellationToken
    )
    {
        var currentUser = currentUserContext.CurrentUser!;

        await blogModule.Command(
            new AddPostReactionCommand(postId, request.Emoji, currentUser.Id),
            cancellationToken
        );

        return this.Ok();
    }

    [HttpDelete("{postId}/reactions")]
    [Authorize]
    public async Task<ActionResult> DeletePostReaction(
        Guid postId,
        [FromBody] DeletePostReactionRequest request,
        CancellationToken cancellationToken
    )
    {
        var currentUser = currentUserContext.CurrentUser!;

        await blogModule.Command(
            new ClearPostReactionCommand(postId, request.Emoji, currentUser.Id),
            cancellationToken
        );

        return this.Ok();
    }

    [HttpPost("{postId}/comments")]
    [Authorize]
    public async Task<ActionResult> AddPostComment(
        Guid postId,
        [FromBody] AddPostCommentRequest request,
        CancellationToken cancellationToken
    )
    {
        if (currentUserContext.CurrentUser?.Id != request.AuthorId)
            return this.BadRequest();
        
        await blogModule.Command(
            new AddPostCommentCommand(postId, request.AuthorId, request.Content),
            cancellationToken
        );

        return this.Ok();
    }
}
