using MediatR;
using Microsoft.EntityFrameworkCore;
using SolutionErp.Application.Common.Interfaces;
using SolutionErp.Domain.Common;

namespace SolutionErp.Application.Budgets;

// 2-stage department approval list cho Budget (Phase 9 — Migration 16).
// Mirror PE/Contract — query để FE Workflow Panel render timeline progress.
//
// Insertion + Block logic ở TransitionBudgetCommandHandler (BudgetFeatures.cs).

public record ListBudgetDepartmentApprovalsQuery(Guid BudgetId)
    : IRequest<List<BudgetDepartmentApprovalDto>>;

public record BudgetDepartmentApprovalDto(
    Guid Id,
    int PhaseAtApproval,
    Guid DepartmentId,
    string? DepartmentName,
    ApprovalStage Stage,
    Guid ApproverUserId,
    string? ApproverName,
    string? ApproverRoleSnapshot,
    string? Comment,
    DateTime ApprovedAt,
    bool IsBypassed);

public class ListBudgetDepartmentApprovalsQueryHandler(IApplicationDbContext db)
    : IRequestHandler<ListBudgetDepartmentApprovalsQuery, List<BudgetDepartmentApprovalDto>>
{
    public async Task<List<BudgetDepartmentApprovalDto>> Handle(
        ListBudgetDepartmentApprovalsQuery request, CancellationToken ct)
    {
        var rows = await (
            from a in db.BudgetDepartmentApprovals.AsNoTracking()
            join d in db.Departments.AsNoTracking() on a.DepartmentId equals d.Id into deptJoin
            from d in deptJoin.DefaultIfEmpty()
            where a.BudgetId == request.BudgetId
            orderby a.PhaseAtApproval, a.Stage, a.ApprovedAt
            select new
            {
                a.Id,
                a.PhaseAtApproval,
                a.DepartmentId,
                DepartmentName = d != null ? d.Name : null,
                a.Stage,
                a.ApproverUserId,
                a.ApproverRoleSnapshot,
                a.Comment,
                a.ApprovedAt,
                a.IsBypassed,
            }).ToListAsync(ct);

        var userIds = rows.Select(r => r.ApproverUserId).Distinct().ToList();
        var users = await db.Users.AsNoTracking()
            .Where(u => userIds.Contains(u.Id))
            .Select(u => new { u.Id, Name = u.FullName ?? u.Email ?? "" })
            .ToDictionaryAsync(u => u.Id, u => u.Name, ct);

        return rows.Select(r => new BudgetDepartmentApprovalDto(
            r.Id,
            r.PhaseAtApproval,
            r.DepartmentId,
            r.DepartmentName,
            r.Stage,
            r.ApproverUserId,
            users.TryGetValue(r.ApproverUserId, out var n) ? n : null,
            r.ApproverRoleSnapshot,
            r.Comment,
            r.ApprovedAt,
            r.IsBypassed)).ToList();
    }
}
