using Application.Abstractions.Messaging;
using Application.Abstractions.Data;
using Application.Abstractions.Cache;
using SharedKernel.Results;
using Microsoft.EntityFrameworkCore;
using BoardMetaResponse = Application.Features.Api.Forum.BoardMeta.Get.Response;

namespace Application.Features.Api.Forum.Board.Get;

public sealed class Handler(IAppDbContext db, ICacheService cache) : IQueryHandler<Query, Result<Response>>
{
    public async Task<Result<Response>> Handle(Query request, CancellationToken ct)
    {
        var item = await db.Board
            .AsNoTracking()
            .Include(x => x.BoardGroup)
            .Include(x => x.BoardPrefix.Where(p => p.IsActive).OrderBy(p => p.Order))
            .Include(x => x.BoardManager)
            .ThenInclude(m => m.Member)
            .FirstOrDefaultAsync(x => x.Code == request.Code, ct);

        if (item is null)
        {
            return Result.Failure<Response>(Error.NotFound("Board.NotFound", "게시판을 찾을 수 없습니다."));
        }

        // BoardMeta 조회 (캐시 우선)
        BoardMetaResponse? boardMeta = null;
        var cacheKey = CacheKeys.BoardMeta(item.ID);
        var cached = await cache.GetAsync<BoardMetaResponse>(cacheKey, ct);

        if (cached is not null)
        {
            boardMeta = cached;
        }
        else
        {
            var meta = await db.BoardMeta.FirstOrDefaultAsync(x => x.BoardID == item.ID, ct);
            if (meta is null)
            {
                meta = new Domain.Entities.Forum.Boards.BoardMeta { 
                    BoardID = item.ID 
                };

                await db.BoardMeta.AddAsync(meta, ct);
                await db.SaveChangesAsync(ct);
            }

            boardMeta = new BoardMetaResponse(
                meta.ID,
                meta.BoardID,
                item.Code,
                item.Name,
                meta.List,
                meta.View,
                meta.Write,
                meta.Comment,
                meta.General,
                meta.Permission,
                meta.Notify,
                meta.NotifyTemplate,
                meta.Exp);

            await cache.SetAsync(cacheKey, boardMeta, ct);
        }

        return new Response(
            item.ID,
            item.BoardGroupID,
            item.Code,
            item.Name,
            item.IsSearch,
            item.IsActive,
            item.Posts,
            new BoardGroupDto(
                item.BoardGroup.ID,
                item.BoardGroup.Code,
                item.BoardGroup.Name
            ),
            [..item.BoardPrefix.Select(p => new BoardPrefixDto(
                p.ID,
                p.BoardID,
                p.Name,
                p.Color,
                p.Posts
            ))],
            [..item.BoardManager.Select(m => new BoardManagerDto(
                m.ID,
                m.BoardID,
                new BoardManagerUserDto(m.MemberID, m.Member.Email),
                m.CanEdit,
                m.CanDelete,
                m.UpdatedAt,
                m.CreatedAt
            ))],
            boardMeta
        );
    }
}
