using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using SolutionErp.Application.Common.Exceptions;
using SolutionErp.Application.Common.Interfaces;
using SolutionErp.Application.Contracts;
using SolutionErp.Domain.ApprovalWorkflowsV2;
using SolutionErp.Domain.Common;
using SolutionErp.Domain.Contracts;
using SolutionErp.Domain.Identity;
using SolutionErp.Domain.Master;
using SolutionErp.Infrastructure.Services;
using SolutionErp.Infrastructure.Tests.Common;

namespace SolutionErp.Infrastructure.Tests.Application;

// Plan C B-Wrap BW5 (S33) — CreateContractCommand validate ApprovalWorkflowId V2.
// Defense-in-depth guard: FE Workspace dropdown server-side filter ApplicableType=Contract(3),
// nhưng BE guard chặn attacker forge POST với PE workflow ID (ApplicableType=DuyetNcc=1
// hoặc DuyetNccPhuongAn=2).
//
// Code path: ContractFeatures.cs line 78-86 — throw ConflictException (NOT
// ValidationException như spec mention; FluentValidation chỉ rule MaximumLength
// + GreaterThanOrEqualTo, KHÔNG có rule cross-table check ApplicableType).
public class CreateContractCommandApplicableTypeTests
{
    [Fact]
    public async Task Create_PinApprovalWorkflowId_ApplicableType_DuyetNcc_Throws()
    {
        using var fix = new IdentityFixture();
        var db = fix.Services.GetRequiredService<TestApplicationDbContext>();

        var drafter = await fix.CreateUserAsync("drafter-bw5@test.local", "Drafter BW5",
            departmentId: null, roles: new[] { AppRoles.Drafter });

        // Seed Supplier + Project (handler validate existence)
        var sup = new Supplier { Id = Guid.NewGuid(), Code = "ABC", Name = "NCC ABC", Type = SupplierType.NhaThauPhu };
        var proj = new Project { Id = Guid.NewGuid(), Code = "PROJ01", Name = "Dự án 01" };
        db.Suppliers.Add(sup);
        db.Projects.Add(proj);

        // Seed PE-only workflow (ApplicableType=DuyetNcc) — attacker payload
        var peOnlyWf = new ApprovalWorkflow
        {
            Id = Guid.NewGuid(),
            Code = "QT-PE-ONLY",
            Version = 1,
            Name = "PE-only workflow",
            ApplicableType = ApprovalWorkflowApplicableType.DuyetNcc,
            IsActive = true,
            IsUserSelectable = true,
        };
        db.ApprovalWorkflows.Add(peOnlyWf);
        await db.SaveChangesAsync(CancellationToken.None);

        // Wire handler 5 deps mirror prod (ContractFeatures.cs:53-58)
        var um = fix.Services.GetRequiredService<UserManager<User>>();
        var dt = new FixedDateTime(new DateTime(2026, 5, 26, 0, 0, 0, DateTimeKind.Utc));
        var notify = new NoOpNotificationServiceApp();
        var currentUser = new TestCurrentUser { UserId = drafter.Id, Roles = new[] { AppRoles.Drafter } };
        var changelog = new ChangelogService(db, currentUser, um);
        var codeGen = new ContractCodeGenerator(db, dt);
        var workflowSvc = new ContractWorkflowService(db, codeGen, dt, notify, changelog, um);
        var handler = new CreateContractCommandHandler(db, currentUser, workflowSvc, codeGen, changelog);

        var cmd = new CreateContractCommand(
            Type: ContractType.HopDongThauPhu,
            SupplierId: sup.Id,
            ProjectId: proj.Id,
            DepartmentId: null,
            TemplateId: null,
            GiaTri: 100_000_000m,
            TenHopDong: "Forge attempt — PE workflow",
            NoiDung: null,
            BypassProcurementAndCCM: false,
            DraftData: null,
            BudgetManualName: null,
            BudgetManualAmount: null,
            ApprovalWorkflowId: peOnlyWf.Id);

        var act = async () => await handler.Handle(cmd, CancellationToken.None);

        // Note: spec BW5 mention ValidationException — thực tế ContractFeatures.cs
        // line 84 throw ConflictException ("Quy trình {Code} áp dụng cho {ApplicableType},
        // không khớp với HĐ (cần ApplicableType=Contract)."). FluentValidation
        // (line 38-50) chỉ rule field-level (MaximumLength, GreaterThanOrEqualTo),
        // KHÔNG có rule cross-table.
        await act.Should().ThrowAsync<ConflictException>()
            .WithMessage("*ApplicableType=Contract*");
    }
}

// NoOp ICurrentUser-NOT-NEEDED notif — ContractWorkflowService DI dùng INotificationService
// (gửi noti drafter khi terminal). Bare-bone stub.
internal sealed class NoOpNotificationServiceApp : SolutionErp.Application.Notifications.INotificationService
{
    public Task NotifyAsync(
        Guid userId,
        SolutionErp.Domain.Notifications.NotificationType type,
        string title,
        string? description = null,
        string? href = null,
        Guid? refId = null,
        CancellationToken ct = default) => Task.CompletedTask;

    public Task NotifyManyAsync(
        IEnumerable<Guid> userIds,
        SolutionErp.Domain.Notifications.NotificationType type,
        string title,
        string? description = null,
        string? href = null,
        Guid? refId = null,
        CancellationToken ct = default) => Task.CompletedTask;
}
