using Microsoft.Extensions.DependencyInjection;
using SolutionErp.Application.PurchaseEvaluations;
using SolutionErp.Domain.ApprovalWorkflowsV2;
using SolutionErp.Domain.Identity;
using SolutionErp.Domain.Master;
using SolutionErp.Domain.PurchaseEvaluations;
using SolutionErp.Infrastructure.Tests.Common;

namespace SolutionErp.Infrastructure.Tests.Application;

// [S89 anh Kiệt FDC] Phiếu NHÁP (DangSoanThao) = RIÊNG TƯ người tạo (+ Admin thấy hết).
// Trước đây "chỗ thao tác" màn hình CEO hiện nháp của người khác qua 2 đường:
//   cond #2 role-eligible (Drafter/DeptManager → DangSoanThao) — mọi Drafter thấy nháp nhau;
//   cond #3 V2-approver — CEO là approver trên workflow → thấy MỌI nháp (workflow pin lúc
//     TẠO phiếu, chưa gửi duyệt) = leak chính trên màn hình CEO.
// Fix: nháp chỉ thấy/mở qua DrafterUserId ownership (+ Admin bypass). Phiếu ĐÃ gửi duyệt
// giữ nguyên (approver vẫn thấy). Test-before security guard (rules §7 — critical authz).
// Dùng IdentityFixture: ApproverUserId/DrafterUserId là FK → cần User rows thật.
public class PeDraftVisibilityTests
{
    private static (Guid projectId, Guid wfId) SeedProjectAndWorkflow(
        TestApplicationDbContext db, Guid approverUserId)
    {
        var project = new Project { Id = Guid.NewGuid(), Code = "VISP", Name = "Dự án Visibility" };
        db.Projects.Add(project);

        var wf = new ApprovalWorkflow
        {
            Code = "QT-VIS-V2",
            Version = 1,
            ApplicableType = ApprovalWorkflowApplicableType.DuyetNcc,
            Name = "QT visibility test",
            IsActive = true,
            IsUserSelectable = true,
        };
        var step = new ApprovalWorkflowStep { ApprovalWorkflowId = wf.Id, Order = 1, Name = "Bước 1" };
        step.Levels.Add(new ApprovalWorkflowLevel
        {
            ApprovalWorkflowStepId = step.Id,
            Order = 1,
            Name = "Cấp 1",
            ApproverUserId = approverUserId,   // CEO-like: approver trên workflow này
        });
        wf.Steps.Add(step);
        db.ApprovalWorkflows.Add(wf);
        return (project.Id, wf.Id);
    }

    private static Guid SeedPe(
        TestApplicationDbContext db, Guid projectId, Guid wfId, Guid drafterId,
        PurchaseEvaluationPhase phase, string code)
    {
        var id = Guid.NewGuid();
        db.PurchaseEvaluations.Add(new PurchaseEvaluation
        {
            Id = id,
            MaPhieu = code,
            Type = PurchaseEvaluationType.DuyetNcc,
            Phase = phase,
            TenGoiThau = $"Gói {code}",
            ProjectId = projectId,
            DrafterUserId = drafterId,
            ApprovalWorkflowId = wfId,   // workflow pin lúc tạo (kể cả nháp) — Features.cs:149
        });
        return id;
    }

    private static async Task<List<Guid>> ListVisibleIds(
        TestApplicationDbContext db, Guid? userId, params string[] roles)
    {
        var cu = new TestCurrentUser { UserId = userId, Roles = roles };
        var handler = new ListPurchaseEvaluationsQueryHandler(db, cu);
        var res = await handler.Handle(
            new ListPurchaseEvaluationsQuery { PageSize = 100 }, CancellationToken.None);
        return res.Items.Select(x => x.Id).ToList();
    }

    [Fact]
    public async Task Draft_VisibleToOwnerOnly_NotOtherDrafter_NotApprover_AdminSeesAll()
    {
        using var fix = new IdentityFixture();
        var db = fix.Services.GetRequiredService<TestApplicationDbContext>();

        var drafterA = await fix.CreateUserAsync("draftera@test.local", "Drafter A", null, new[] { AppRoles.Drafter });
        var drafterB = await fix.CreateUserAsync("drafterb@test.local", "Drafter B", null, new[] { AppRoles.Drafter });
        var ceo = await fix.CreateUserAsync("ceo@test.local", "CEO Director", null, new[] { AppRoles.Director });

        var (projectId, wfId) = SeedProjectAndWorkflow(db, approverUserId: ceo.Id);
        var draft = SeedPe(db, projectId, wfId, drafterA.Id,
            PurchaseEvaluationPhase.DangSoanThao, "PE-DRAFT");
        await db.SaveChangesAsync(CancellationToken.None);

        // Owner thấy nháp của CHÍNH MÌNH (cond #1 ownership).
        (await ListVisibleIds(db, drafterA.Id, AppRoles.Drafter)).Should().Contain(draft);
        // Drafter KHÁC (cùng role) KHÔNG thấy nháp của A (cond #2 leak ĐÃ vá).
        (await ListVisibleIds(db, drafterB.Id, AppRoles.Drafter)).Should().NotContain(draft);
        // V2-approver (CEO trên workflow) KHÔNG thấy nháp (cond #3 leak ĐÃ vá — đúng màn hình CEO).
        (await ListVisibleIds(db, ceo.Id, AppRoles.Director)).Should().NotContain(draft);
        // Admin thấy hết (anh Kiệt: "full admin với thấy hết").
        (await ListVisibleIds(db, Guid.NewGuid(), AppRoles.Admin)).Should().Contain(draft);
    }

    [Fact]
    public async Task SubmittedPhieu_StillVisibleToApprover_NotRegressed()
    {
        using var fix = new IdentityFixture();
        var db = fix.Services.GetRequiredService<TestApplicationDbContext>();

        var drafterA = await fix.CreateUserAsync("draftera2@test.local", "Drafter A2", null, new[] { AppRoles.Drafter });
        var ceo = await fix.CreateUserAsync("ceo2@test.local", "CEO2 Director", null, new[] { AppRoles.Director });

        var (projectId, wfId) = SeedProjectAndWorkflow(db, approverUserId: ceo.Id);
        // Phiếu ĐÃ gửi duyệt (ChoDuyet) — approver PHẢI vẫn thấy (regression guard: chỉ
        // chặn lúc CÒN nháp, không chặn sau khi đã gửi duyệt).
        var submitted = SeedPe(db, projectId, wfId, drafterA.Id,
            PurchaseEvaluationPhase.ChoDuyet, "PE-SUB");
        await db.SaveChangesAsync(CancellationToken.None);

        (await ListVisibleIds(db, ceo.Id, AppRoles.Director)).Should().Contain(submitted);
    }
}
