using FluentValidation;
using MediatR;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using SolutionErp.Application.Common.Exceptions;
using SolutionErp.Application.Common.Interfaces;
using SolutionErp.Application.Notifications;
using SolutionErp.Domain.Identity;
using SolutionErp.Domain.Notifications;

namespace SolutionErp.Application.PurchaseEvaluations;

// [S69 2026-06-17] Cờ gấp (urgent) phiếu Duyệt NCC — anh Kiệt FDC. PRO (role
// Procurement) bật/tắt cờ ĐỎ (IsUrgentByPro), CCM (role CostControl) bật/tắt cờ XANH
// (IsUrgentByCcm), Admin set CẢ 2. Khi MỚI bật (false→true) → notify CEO (role Director)
// để "biết gấp + xử lý sớm". Q3 chốt: VISIBILITY-ONLY — KHÔNG đổi luồng duyệt (ai duyệt
// vẫn theo ngưỡng giá trị). Mirror cấu trúc command PE hiện có (AdjustBudget/UpsertOpinion).
public record SetPurchaseEvaluationUrgentCommand(Guid Id, bool IsUrgent) : IRequest;

public class SetPurchaseEvaluationUrgentCommandValidator : AbstractValidator<SetPurchaseEvaluationUrgentCommand>
{
    public SetPurchaseEvaluationUrgentCommandValidator()
    {
        RuleFor(x => x.Id).NotEmpty();
    }
}

public class SetPurchaseEvaluationUrgentCommandHandler(
    IApplicationDbContext db,
    ICurrentUser currentUser,
    UserManager<User> userManager,
    INotificationService notifications) : IRequestHandler<SetPurchaseEvaluationUrgentCommand>
{
    public async Task Handle(SetPurchaseEvaluationUrgentCommand request, CancellationToken ct)
    {
        var entity = await db.PurchaseEvaluations.FirstOrDefaultAsync(x => x.Id == request.Id, ct)
            ?? throw new NotFoundException("PurchaseEvaluation", request.Id);

        var roles = currentUser.Roles;
        var isAdmin = roles.Contains(AppRoles.Admin);
        var isDeptManager = roles.Contains(AppRoles.DeptManager);
        var hasPro = roles.Contains(AppRoles.Procurement);
        var hasCcm = roles.Contains(AppRoles.CostControl);

        // [S77 Tra Sol/anh Kiệt] GẮN bất đối xứng + [S85 anh Kiệt] NGƯỜI KHAI tự gỡ cờ của mình:
        //  • GẮN (true): NV chức năng PRO/CCM (hoặc Admin) tự đánh dấu cờ của vai mình.
        //  • GỠ (false): Admin / Trưởng phòng (role chức năng + DeptManager) / chính người KHAI phiếu
        //    (DrafterUserId). Drafter/Admin gỡ CẢ 2 cờ (un-urgent phiếu); TP-vai chỉ gỡ cờ của vai mình.
        var isDrafter = currentUser.UserId is Guid actorUid && actorUid == entity.DrafterUserId;

        // Snapshot để phát hiện chuyển false→true (MỚI bật gấp) → notify CEO 1 lần.
        var wasUrgent = entity.IsUrgentByPro || entity.IsUrgentByCcm;

        if (request.IsUrgent)
        {
            // GẮN — chỉ role chức năng / Admin. Role quyết cờ: PRO → ĐỎ, CCM → XANH, Admin → CẢ 2.
            if (!isAdmin && !hasPro && !hasCcm)
                throw new ForbiddenException("Chỉ PRO (Cung ứng) / CCM (Kiểm soát chi phí) / Admin được đánh dấu phiếu gấp.");
            if (isAdmin) { entity.IsUrgentByPro = true; entity.IsUrgentByCcm = true; }
            else if (hasPro) entity.IsUrgentByPro = true;
            else entity.IsUrgentByCcm = true; // hasCcm
        }
        else
        {
            // GỠ — Admin / TP-vai / người khai phiếu. Drafter+Admin gỡ cả 2; TP-vai gỡ cờ vai mình.
            var isProTp = hasPro && isDeptManager;
            var isCcmTp = hasCcm && isDeptManager;
            if (!isAdmin && !isProTp && !isCcmTp && !isDrafter)
                throw new ForbiddenException("Chỉ Admin / Trưởng phòng Cung ứng–Kiểm soát chi phí / người khai phiếu được GỠ cờ gấp.");
            if (isAdmin || isDrafter) { entity.IsUrgentByPro = false; entity.IsUrgentByCcm = false; }
            else if (isProTp) entity.IsUrgentByPro = false;
            else entity.IsUrgentByCcm = false; // isCcmTp
        }

        await db.SaveChangesAsync(ct);

        // Notify CEO (Director) khi MỚI bật gấp (false→true). Best-effort — KHÔNG fail
        // toggle nếu notify lỗi (Q3 visibility-only, cờ đã lưu thành công).
        var nowUrgent = entity.IsUrgentByPro || entity.IsUrgentByCcm;
        if (request.IsUrgent && nowUrgent && !wasUrgent)
        {
            try
            {
                var directors = await userManager.GetUsersInRoleAsync(AppRoles.Director);
                var directorIds = directors.Select(u => u.Id).ToList();
                if (directorIds.Count > 0)
                {
                    await notifications.NotifyManyAsync(
                        directorIds,
                        NotificationType.Generic,
                        $"Phiếu Duyệt NCC {entity.MaPhieu ?? entity.TenGoiThau} được đánh dấu GẤP",
                        "Phiếu cần được xử lý sớm.",
                        $"/purchase-evaluations/{entity.Id}",
                        entity.Id,
                        ct);
                    // [S88 fix] NotifyManyAsync CHỈ Add (caller tự flush) → toggle đã flush
                    // ở :75 TRƯỚC block này nên chuông Director chưa từng được lưu (rớt âm
                    // thầm + KHÔNG trigger SignalR push). SaveChanges RIÊNG ở đây để chuông
                    // CEO/Director thực sự lưu. Trong try → vẫn best-effort (lỗi nuốt, cờ đã ổn).
                    await db.SaveChangesAsync(ct);
                }
            }
            catch
            {
                // best-effort — nuốt lỗi notify, toggle cờ gấp đã lưu thành công.
            }
        }
    }
}
