using FluentValidation;
using MediatR;
using Microsoft.EntityFrameworkCore;
using SolutionErp.Application.Common.Exceptions;
using SolutionErp.Application.Common.Interfaces;
using SolutionErp.Domain.Contracts;
using SolutionErp.Domain.PurchaseEvaluations;

namespace SolutionErp.Application.PurchaseEvaluations;

// Add NCC vào phiếu đánh giá (section II + E của form) — admin/drafter làm
// ở phase soạn thảo.
public record AddPurchaseEvaluationSupplierCommand(
    Guid PurchaseEvaluationId,
    Guid SupplierId,
    string? DisplayName,
    string? ContactName,
    string? ContactEmail,
    string? ContactPhone,
    string? PaymentTermText,
    string? Note) : IRequest<Guid>;

public class AddPurchaseEvaluationSupplierCommandValidator : AbstractValidator<AddPurchaseEvaluationSupplierCommand>
{
    public AddPurchaseEvaluationSupplierCommandValidator()
    {
        RuleFor(x => x.PurchaseEvaluationId).NotEmpty();
        RuleFor(x => x.SupplierId).NotEmpty();
        RuleFor(x => x.DisplayName).MaximumLength(200);
        RuleFor(x => x.ContactName).MaximumLength(200);
        RuleFor(x => x.ContactEmail).MaximumLength(200);
        RuleFor(x => x.ContactPhone).MaximumLength(50);
        RuleFor(x => x.PaymentTermText).MaximumLength(200);
        RuleFor(x => x.Note).MaximumLength(500);
    }
}

public class AddPurchaseEvaluationSupplierCommandHandler(
    IApplicationDbContext db,
    ICurrentUser currentUser) : IRequestHandler<AddPurchaseEvaluationSupplierCommand, Guid>
{
    public async Task<Guid> Handle(AddPurchaseEvaluationSupplierCommand request, CancellationToken ct)
    {
        // Mig 28 (S21 t4 F3) — Section 2 edit guard: Drafter (DangSoanThao/TraLai)
        // OR Approver (ChoDuyet + workflow.AllowApproverEditDetails + actor match).
        var evaluation = await PurchaseEvaluationDraftGuard.EnsureEditableForDetailsAsync(
            db, request.PurchaseEvaluationId, currentUser, ct);

        _ = await db.Suppliers.FirstOrDefaultAsync(s => s.Id == request.SupplierId, ct)
            ?? throw new NotFoundException("Supplier", request.SupplierId);

        var dup = await db.PurchaseEvaluationSuppliers
            .AnyAsync(s => s.PurchaseEvaluationId == request.PurchaseEvaluationId && s.SupplierId == request.SupplierId, ct);
        if (dup) throw new ConflictException("NCC đã được thêm vào phiếu.");

        var maxOrder = await db.PurchaseEvaluationSuppliers
            .Where(s => s.PurchaseEvaluationId == request.PurchaseEvaluationId)
            .Select(s => (int?)s.Order)
            .MaxAsync(ct);

        var entity = new PurchaseEvaluationSupplier
        {
            PurchaseEvaluationId = request.PurchaseEvaluationId,
            SupplierId = request.SupplierId,
            DisplayName = request.DisplayName,
            ContactName = request.ContactName,
            ContactEmail = request.ContactEmail,
            ContactPhone = request.ContactPhone,
            PaymentTermText = request.PaymentTermText,
            Note = request.Note,
            Order = (maxOrder ?? 0) + 1,
        };
        db.PurchaseEvaluationSuppliers.Add(entity);

        db.PurchaseEvaluationChangelogs.Add(new PurchaseEvaluationChangelog
        {
            PurchaseEvaluationId = request.PurchaseEvaluationId,
            EntityType = PurchaseEvaluationEntityType.Supplier,
            EntityId = entity.Id,
            Action = ChangelogAction.Insert,
            PhaseAtChange = evaluation.Phase,
            UserId = currentUser.UserId,
            Summary = $"Thêm NCC {request.DisplayName ?? "#" + request.SupplierId.ToString()[..8]}",
        });

        await db.SaveChangesAsync(ct);
        return entity.Id;
    }
}

public record UpdatePurchaseEvaluationSupplierCommand(
    Guid PurchaseEvaluationId,
    Guid SupplierRowId,
    string? DisplayName,
    string? ContactName,
    string? ContactEmail,
    string? ContactPhone,
    string? PaymentTermText,
    string? Note) : IRequest;

public class UpdatePurchaseEvaluationSupplierCommandHandler(
    IApplicationDbContext db,
    ICurrentUser currentUser) : IRequestHandler<UpdatePurchaseEvaluationSupplierCommand>
{
    public async Task Handle(UpdatePurchaseEvaluationSupplierCommand request, CancellationToken ct)
    {
        // Mig 28 (S21 t4 F3) — Section 2 edit guard.
        var evaluation = await PurchaseEvaluationDraftGuard.EnsureEditableForDetailsAsync(
            db, request.PurchaseEvaluationId, currentUser, ct);
        var row = await db.PurchaseEvaluationSuppliers
            .FirstOrDefaultAsync(s => s.Id == request.SupplierRowId && s.PurchaseEvaluationId == request.PurchaseEvaluationId, ct)
            ?? throw new NotFoundException("PurchaseEvaluationSupplier", request.SupplierRowId);

        row.DisplayName = request.DisplayName;
        row.ContactName = request.ContactName;
        row.ContactEmail = request.ContactEmail;
        row.ContactPhone = request.ContactPhone;
        row.PaymentTermText = request.PaymentTermText;
        row.Note = request.Note;

        var approverNote = evaluation.Phase == PurchaseEvaluationPhase.ChoDuyet
            ? " [Approver edit khi đang duyệt]" : string.Empty;
        db.PurchaseEvaluationChangelogs.Add(new PurchaseEvaluationChangelog
        {
            PurchaseEvaluationId = request.PurchaseEvaluationId,
            EntityType = PurchaseEvaluationEntityType.Supplier,
            EntityId = row.Id,
            Action = ChangelogAction.Update,
            PhaseAtChange = evaluation.Phase,
            UserId = currentUser.UserId,
            Summary = $"Cập nhật NCC {request.DisplayName ?? "#" + row.SupplierId.ToString()[..8]}{approverNote}",
        });

        await db.SaveChangesAsync(ct);
    }
}

public record RemovePurchaseEvaluationSupplierCommand(Guid PurchaseEvaluationId, Guid SupplierRowId) : IRequest;

public class RemovePurchaseEvaluationSupplierCommandHandler(
    IApplicationDbContext db,
    ICurrentUser currentUser) : IRequestHandler<RemovePurchaseEvaluationSupplierCommand>
{
    public async Task Handle(RemovePurchaseEvaluationSupplierCommand request, CancellationToken ct)
    {
        // Mig 28 (S21 t4 F3) — Section 2 edit guard.
        var evaluation = await PurchaseEvaluationDraftGuard.EnsureEditableForDetailsAsync(
            db, request.PurchaseEvaluationId, currentUser, ct);
        var row = await db.PurchaseEvaluationSuppliers
            .FirstOrDefaultAsync(s => s.Id == request.SupplierRowId && s.PurchaseEvaluationId == request.PurchaseEvaluationId, ct)
            ?? throw new NotFoundException("PurchaseEvaluationSupplier", request.SupplierRowId);

        // Block nếu có Quote row reference (FK Restrict) — user phải xóa quote trước
        var hasQuotes = await db.PurchaseEvaluationQuotes.AnyAsync(q => q.PurchaseEvaluationSupplierId == row.Id, ct);
        if (hasQuotes) throw new ConflictException("Không thể xóa NCC khi còn báo giá. Xóa báo giá trước.");

        var approverNote = evaluation.Phase == PurchaseEvaluationPhase.ChoDuyet
            ? " [Approver edit khi đang duyệt]" : string.Empty;
        db.PurchaseEvaluationChangelogs.Add(new PurchaseEvaluationChangelog
        {
            PurchaseEvaluationId = request.PurchaseEvaluationId,
            EntityType = PurchaseEvaluationEntityType.Supplier,
            EntityId = row.Id,
            Action = ChangelogAction.Delete,
            PhaseAtChange = evaluation.Phase,
            UserId = currentUser.UserId,
            Summary = $"Xóa NCC {row.DisplayName ?? "#" + row.SupplierId.ToString()[..8]}{approverNote}",
        });

        db.PurchaseEvaluationSuppliers.Remove(row);
        await db.SaveChangesAsync(ct);
    }
}
