using Application.Abstractions.Messaging;
using Application.Abstractions.Data;
using Domain.Entities.Forum.ValueObject;
using SharedKernel.Results;
using Microsoft.EntityFrameworkCore;

namespace Application.Features.Api.Forum.PostReaction.Toggle;

public sealed class Handler(IAppDbContext db) : ICommandHandler<Command, Result>
{
    public async Task<Result> Handle(Command request, CancellationToken ct)
    {
        var post = await db.Post.FirstOrDefaultAsync(x => x.ID == request.PostID, ct);
        if (post is null)
        {
            return Result.Failure(Error.NotFound("PostReaction.PostNotFound", "게시글을 찾을 수 없습니다."));
        }

        var existing = await db.PostReaction.FirstOrDefaultAsync(x => x.PostID == request.PostID && x.MemberID == request.MemberID, ct);

        // MemberStats 조회 (Like만 카운트) — 1회 쿼리로 giver/receiver 동시 로드
        var memberIDs = post.MemberID.HasValue && post.MemberID.Value != request.MemberID
            ? new[] { request.MemberID, post.MemberID.Value }
            : new[] { request.MemberID };

        var statsList = await db.MemberStats
            .Where(x => memberIDs.Contains(x.MemberID))
            .ToListAsync(ct);

        var giverStats = statsList.FirstOrDefault(x => x.MemberID == request.MemberID);
        var receiverStats = post.MemberID.HasValue && post.MemberID.Value != request.MemberID
            ? statsList.FirstOrDefault(x => x.MemberID == post.MemberID.Value)
            : null;

        if (existing is not null)
        {
            // 같은 반응이면 취소
            if (existing.Reaction == request.Reaction)
            {
                if (existing.Reaction == Reaction.Like)
                {
                    post.Likes--;

                    if (giverStats is not null) { giverStats.LikeGivenCount--; }
                    if (receiverStats is not null) { receiverStats.LikeReceivedCount--; }
                }
                else
                {
                    post.Dislikes--;
                }

                db.PostReaction.Remove(existing);
            }
            else
            {
                // 다른 반응이면 전환
                if (existing.Reaction == Reaction.Like)
                {
                    post.Likes--;
                    post.Dislikes++;

                    // Like → Dislike: Like 카운트 감소
                    if (giverStats is not null) { giverStats.LikeGivenCount--; }
                    if (receiverStats is not null) { receiverStats.LikeReceivedCount--; }
                }
                else
                {
                    post.Dislikes--;
                    post.Likes++;

                    // Dislike → Like: Like 카운트 증가
                    if (giverStats is not null) { giverStats.LikeGivenCount++; }
                    if (receiverStats is not null) { receiverStats.LikeReceivedCount++; }
                }

                existing.Reaction = request.Reaction;
                existing.UpdatedAt = DateTime.UtcNow;
            }
        }
        else
        {
            // 새 반응
            var reaction = new Domain.Entities.Forum.Posts.PostReaction
            {
                BoardID = post.BoardID,
                PostID = request.PostID,
                MemberID = request.MemberID,
                Reaction = request.Reaction
            };

            await db.PostReaction.AddAsync(reaction, ct);

            if (request.Reaction == Reaction.Like)
            {
                post.Likes++;

                if (giverStats is not null) { giverStats.LikeGivenCount++; }
                if (receiverStats is not null) { receiverStats.LikeReceivedCount++; }
            }
            else
            {
                post.Dislikes++;
            }
        }

        await db.SaveChangesAsync(ct);

        return Result.Success();
    }
}