using Application.Abstractions.Messaging;
using Application.Abstractions.Data;
using Microsoft.EntityFrameworkCore;

namespace Application.Features.Admin.Forum.BoardGroup.Save
{
    public sealed class Handler(IAppDbContext db) : ICommandHandler<Command, Response>
    {
        public async Task<Response> Handle(Command request, CancellationToken ct)
        {
            var items = request.Items;

            var dbRows = await db.BoardGroup.ToListAsync(ct);
            var dbByID = dbRows.ToDictionary(c => c.ID);

            var requestIDs = items.Where(c => c.ID.HasValue && c.ID.Value > 0).Select(c => c.ID!.Value).ToHashSet();

            // 삭제 대상 조회
            var deleteTargets = dbRows.Where(x => !requestIDs.Contains(x.ID)).ToList();

            if (deleteTargets.Count > 0)
            {
                var deleteIDs = deleteTargets.Select(c => c.ID).ToList();
                var hasBoards = await db.Board.AsNoTracking().AnyAsync(c => deleteIDs.Contains(c.BoardGroupID), ct);

                if (hasBoards)
                {
                    throw new InvalidOperationException("게시판이 등록된 분류는 삭제할 수 없습니다. 먼저 해당 게시판을 삭제하세요.");
                }

                db.BoardGroup.RemoveRange(deleteTargets);
            }

            ushort inserted = 0;
            ushort updated = 0;
            ushort deleted = 0;

            foreach (var row in items)
            {
                // 신규 추가
                if (!row.ID.HasValue || row.ID.Value <= 0)
                {
                    if (await db.BoardGroup.AnyAsync(c => c.Code == row.Code, ct))
                    {
                        throw new InvalidOperationException($"`{row.Code}`는 이미 등록되었습니다.");
                    }

                    db.BoardGroup.Add(new Domain.Entities.Forum.Boards.BoardGroup
                    {
                        Code = row.Code,
                        Name = row.Name,
                        Order = row.Order
                    });

                    inserted++;
                    continue;
                }

                // 수정
                if (!dbByID.TryGetValue(row.ID.Value, out var existing))
                {
                    throw new InvalidOperationException($"존재하지 않는 ID: {row.ID.Value}");
                }

                if (existing.Code != row.Code && await db.BoardGroup.AnyAsync(c => c.Code == row.Code, ct))
                {
                    throw new InvalidOperationException($"`{row.Code}`는 이미 등록되었습니다.");
                }

                existing.Code = row.Code;
                existing.Name = row.Name;
                existing.Order = row.Order;
                existing.UpdatedAt = DateTime.UtcNow;
                updated++;
            }

            deleted = (ushort)deleteTargets.Count;

            await db.SaveChangesAsync(ct);

            return new Response(inserted, updated, deleted);
        }
    }
}