using SolutionErp.Domain.Contracts;    // WorkflowApproverKind
using SolutionErp.Domain.Identity;

namespace SolutionErp.Domain.PurchaseEvaluations;

// Policy record cho phiếu Duyệt NCC — mirror WorkflowPolicy của HĐ nhưng
// dùng PurchaseEvaluationPhase enum. 2 default policy hardcoded (A/B)
// phục vụ seed + fallback khi admin chưa author định nghĩa DB.
public sealed record PurchaseEvaluationPolicy(
    string Name,
    string Description,
    IReadOnlyDictionary<(PurchaseEvaluationPhase From, PurchaseEvaluationPhase To), string[]> Transitions,
    IReadOnlyDictionary<PurchaseEvaluationPhase, TimeSpan?> PhaseSla,
    IReadOnlyList<PurchaseEvaluationPhase> ActivePhases,
    IReadOnlyDictionary<(PurchaseEvaluationPhase From, PurchaseEvaluationPhase To), string[]>? UserTransitions = null)
{
    public bool HasPhase(PurchaseEvaluationPhase phase) => ActivePhases.Contains(phase);

    public bool IsTransitionAllowed(
        PurchaseEvaluationPhase from, PurchaseEvaluationPhase to,
        IReadOnlyList<string> actorRoles, Guid? actorUserId = null)
    {
        if (!Transitions.TryGetValue((from, to), out var roles)) return false;
        if (actorRoles.Any(r => roles.Contains(r))) return true;

        if (actorUserId is null) return false;
        if (UserTransitions is null) return false;
        if (!UserTransitions.TryGetValue((from, to), out var userIds)) return false;
        return userIds.Contains(actorUserId.Value.ToString());
    }

    public IReadOnlyList<PurchaseEvaluationPhase> NextPhasesFrom(PurchaseEvaluationPhase from) =>
        Transitions.Keys.Where(k => k.From == from).Select(k => k.To).Distinct().ToList();
}

public static class PurchaseEvaluationPolicies
{
    private static readonly Dictionary<PurchaseEvaluationPhase, TimeSpan?> DefaultSla = new()
    {
        [PurchaseEvaluationPhase.DangSoanThao] = TimeSpan.FromDays(3),
        [PurchaseEvaluationPhase.TraLai] = TimeSpan.FromDays(3),
        [PurchaseEvaluationPhase.ChoPurchasing] = TimeSpan.FromDays(2),
        [PurchaseEvaluationPhase.ChoDuAn] = TimeSpan.FromDays(2),
        [PurchaseEvaluationPhase.ChoCCM] = TimeSpan.FromDays(2),
        [PurchaseEvaluationPhase.ChoCEODuyetPA] = TimeSpan.FromDays(1),
        [PurchaseEvaluationPhase.ChoCEODuyetNCC] = TimeSpan.FromDays(1),
        [PurchaseEvaluationPhase.DaDuyet] = null,
        [PurchaseEvaluationPhase.TuChoi] = null,
    };

    // A — DuyetNcc (3 step thực + Drafter soạn): Drafter → Purchasing → CCM → CEO
    // Session 17 spec: Reject = về TraLai (Phase riêng, không revert DangSoanThao).
    // Drafter từ TraLai gửi lại = entry point thứ 2 (mirror DangSoanThao → ChoPurchasing).
    public static readonly PurchaseEvaluationPolicy NccOnly = new(
        Name: "NccOnly",
        Description: "Duyệt NCC — 3 step (Purchasing → CCM → CEO). Không cần duyệt phương án.",
        Transitions: new Dictionary<(PurchaseEvaluationPhase, PurchaseEvaluationPhase), string[]>
        {
            // Drafter trình từ Nháp HOẶC gửi lại từ Trả lại — cùng entry point.
            [(PurchaseEvaluationPhase.DangSoanThao, PurchaseEvaluationPhase.ChoPurchasing)] = [AppRoles.Drafter, AppRoles.DeptManager],
            [(PurchaseEvaluationPhase.TraLai, PurchaseEvaluationPhase.ChoPurchasing)] = [AppRoles.Drafter, AppRoles.DeptManager],

            // Phase trung gian: 2 hành động — Duyệt forward / Trả lại (TraLai Phase riêng).
            // UAT S60: TuChoi gỡ khỏi quy trình ("Duyệt hoặc Trả về thôi").
            [(PurchaseEvaluationPhase.ChoPurchasing, PurchaseEvaluationPhase.ChoCCM)] = [AppRoles.Procurement],
            [(PurchaseEvaluationPhase.ChoPurchasing, PurchaseEvaluationPhase.TraLai)] = [AppRoles.Procurement],

            [(PurchaseEvaluationPhase.ChoCCM, PurchaseEvaluationPhase.ChoCEODuyetNCC)] = [AppRoles.CostControl],
            [(PurchaseEvaluationPhase.ChoCCM, PurchaseEvaluationPhase.TraLai)] = [AppRoles.CostControl],

            [(PurchaseEvaluationPhase.ChoCEODuyetNCC, PurchaseEvaluationPhase.DaDuyet)] = [AppRoles.Director, AppRoles.AuthorizedSigner],
            [(PurchaseEvaluationPhase.ChoCEODuyetNCC, PurchaseEvaluationPhase.TraLai)] = [AppRoles.Director, AppRoles.AuthorizedSigner],
        },
        PhaseSla: DefaultSla,
        ActivePhases:
        [
            PurchaseEvaluationPhase.DangSoanThao,
            PurchaseEvaluationPhase.TraLai,
            PurchaseEvaluationPhase.ChoPurchasing,
            PurchaseEvaluationPhase.ChoCCM,
            PurchaseEvaluationPhase.ChoCEODuyetNCC,
            PurchaseEvaluationPhase.DaDuyet,
            PurchaseEvaluationPhase.TuChoi,
        ]);

    // B — DuyetNccPhuongAn (5 step thực + Drafter): Drafter → Purchasing → Dự án → CCM → CEO(PA) → CEO(NCC)
    public static readonly PurchaseEvaluationPolicy NccWithPlan = new(
        Name: "NccWithPlan",
        Description: "Duyệt NCC và Giải pháp — 5 step (Purchasing → Dự án → CCM → CEO duyệt Giải pháp → CEO duyệt NCC).",
        Transitions: new Dictionary<(PurchaseEvaluationPhase, PurchaseEvaluationPhase), string[]>
        {
            [(PurchaseEvaluationPhase.DangSoanThao, PurchaseEvaluationPhase.ChoPurchasing)] = [AppRoles.Drafter, AppRoles.DeptManager],
            [(PurchaseEvaluationPhase.TraLai, PurchaseEvaluationPhase.ChoPurchasing)] = [AppRoles.Drafter, AppRoles.DeptManager],

            // Phase trung gian: 2 hành động — Duyệt forward / Trả lại (TraLai). UAT S60: TuChoi gỡ.
            [(PurchaseEvaluationPhase.ChoPurchasing, PurchaseEvaluationPhase.ChoDuAn)] = [AppRoles.Procurement],
            [(PurchaseEvaluationPhase.ChoPurchasing, PurchaseEvaluationPhase.TraLai)] = [AppRoles.Procurement],

            [(PurchaseEvaluationPhase.ChoDuAn, PurchaseEvaluationPhase.ChoCCM)] = [AppRoles.ProjectManager],
            [(PurchaseEvaluationPhase.ChoDuAn, PurchaseEvaluationPhase.TraLai)] = [AppRoles.ProjectManager],

            [(PurchaseEvaluationPhase.ChoCCM, PurchaseEvaluationPhase.ChoCEODuyetPA)] = [AppRoles.CostControl],
            [(PurchaseEvaluationPhase.ChoCCM, PurchaseEvaluationPhase.TraLai)] = [AppRoles.CostControl],

            [(PurchaseEvaluationPhase.ChoCEODuyetPA, PurchaseEvaluationPhase.ChoCEODuyetNCC)] = [AppRoles.Director, AppRoles.AuthorizedSigner],
            [(PurchaseEvaluationPhase.ChoCEODuyetPA, PurchaseEvaluationPhase.TraLai)] = [AppRoles.Director, AppRoles.AuthorizedSigner],

            [(PurchaseEvaluationPhase.ChoCEODuyetNCC, PurchaseEvaluationPhase.DaDuyet)] = [AppRoles.Director, AppRoles.AuthorizedSigner],
            [(PurchaseEvaluationPhase.ChoCEODuyetNCC, PurchaseEvaluationPhase.TraLai)] = [AppRoles.Director, AppRoles.AuthorizedSigner],
        },
        PhaseSla: DefaultSla,
        ActivePhases:
        [
            PurchaseEvaluationPhase.DangSoanThao,
            PurchaseEvaluationPhase.TraLai,
            PurchaseEvaluationPhase.ChoPurchasing,
            PurchaseEvaluationPhase.ChoDuAn,
            PurchaseEvaluationPhase.ChoCCM,
            PurchaseEvaluationPhase.ChoCEODuyetPA,
            PurchaseEvaluationPhase.ChoCEODuyetNCC,
            PurchaseEvaluationPhase.DaDuyet,
            PurchaseEvaluationPhase.TuChoi,
        ]);
}

public static class PurchaseEvaluationPolicyRegistry
{
    public static readonly string[] AvailablePolicyNames = ["NccOnly", "NccWithPlan"];

    public static PurchaseEvaluationPolicy ByName(string name) => name switch
    {
        "NccWithPlan" => PurchaseEvaluationPolicies.NccWithPlan,
        _ => PurchaseEvaluationPolicies.NccOnly,
    };

    public static string DefaultPolicyNameFor(PurchaseEvaluationType type) => type switch
    {
        PurchaseEvaluationType.DuyetNccPhuongAn => "NccWithPlan",
        _ => "NccOnly",
    };

    public static PurchaseEvaluationPolicy For(PurchaseEvaluationType type) =>
        ByName(DefaultPolicyNameFor(type));

    public static PurchaseEvaluationPolicy ForEvaluation(PurchaseEvaluation ev) =>
        For(ev.Type);

    // Session 17 — synthetic policy cho phiếu pin schema V2 (ApprovalWorkflowsV2).
    // Workflow chạy theo state machine 5 trạng thái + iterate Steps/Levels —
    // Phase enum chỉ dùng (DangSoanThao/TraLai/ChoDuyet/DaDuyet/TuChoi). Service
    // tự handle advance level/step bên trong ChoDuyet, FE chỉ cần biết:
    //   DangSoanThao/TraLai → ChoDuyet (trình)
    //   ChoDuyet            → ChoDuyet (advance) | TraLai (trả lại)
    // UAT S60 (anh Kiệt): TuChoi GỠ khỏi quy trình ("Duyệt hoặc Trả về thôi") —
    // enum + display phiếu TuChoi cũ GIỮ, chỉ hết đường transition tới.
    public static PurchaseEvaluationPolicy ForV2Schema()
    {
        var transitions = new Dictionary<(PurchaseEvaluationPhase, PurchaseEvaluationPhase), string[]>
        {
            // Drafter trình từ Nháp HOẶC gửi lại từ Trả lại — cùng entry point
            [(PurchaseEvaluationPhase.DangSoanThao, PurchaseEvaluationPhase.ChoDuyet)] = [AppRoles.Drafter, AppRoles.DeptManager],
            [(PurchaseEvaluationPhase.TraLai, PurchaseEvaluationPhase.ChoDuyet)] = [AppRoles.Drafter, AppRoles.DeptManager],

            // ChoDuyet — Service guard match approver ApproverUserId, Policy chỉ
            // expose 3 nút cho FE (Duyệt forward / Trả lại / Từ chối). Roles "*"
            // để guard không block; Service tự enforce ApproverUserId match.
            [(PurchaseEvaluationPhase.ChoDuyet, PurchaseEvaluationPhase.ChoDuyet)] = ["*"],
            [(PurchaseEvaluationPhase.ChoDuyet, PurchaseEvaluationPhase.TraLai)] = ["*"],
        };
        var sla = new Dictionary<PurchaseEvaluationPhase, TimeSpan?>
        {
            [PurchaseEvaluationPhase.DangSoanThao] = TimeSpan.FromDays(3),
            [PurchaseEvaluationPhase.TraLai] = TimeSpan.FromDays(3),
            [PurchaseEvaluationPhase.ChoDuyet] = TimeSpan.FromDays(7),
            [PurchaseEvaluationPhase.DaDuyet] = null,
            [PurchaseEvaluationPhase.TuChoi] = null,
        };
        return new PurchaseEvaluationPolicy(
            Name: "V2-Schema",
            Description: "Schema mới ApprovalWorkflowsV2 — Service iterate Steps/Levels theo workflow pin.",
            Transitions: transitions,
            PhaseSla: sla,
            ActivePhases:
            [
                PurchaseEvaluationPhase.DangSoanThao,
                PurchaseEvaluationPhase.TraLai,
                PurchaseEvaluationPhase.ChoDuyet,
                PurchaseEvaluationPhase.DaDuyet,
                PurchaseEvaluationPhase.TuChoi,
            ]);
    }

    // Build policy from persisted admin-authored definition (mirror
    // WorkflowPolicyRegistry.FromDefinition for HĐ).
    public static PurchaseEvaluationPolicy FromDefinition(PurchaseEvaluationWorkflowDefinition def)
    {
        var steps = def.Steps.OrderBy(s => s.Order).ToList();
        var transitions = new Dictionary<(PurchaseEvaluationPhase From, PurchaseEvaluationPhase To), string[]>();
        var userTransitions = new Dictionary<(PurchaseEvaluationPhase From, PurchaseEvaluationPhase To), string[]>();
        var sla = new Dictionary<PurchaseEvaluationPhase, TimeSpan?>();
        var activePhases = new List<PurchaseEvaluationPhase>();

        PurchaseEvaluationPhase? prev = null;
        foreach (var s in steps)
        {
            activePhases.Add(s.Phase);
            sla[s.Phase] = s.SlaDays is int d ? TimeSpan.FromDays(d) : null;

            var roles = s.Approvers
                .Where(a => a.Kind == WorkflowApproverKind.Role)
                .Select(a => a.AssignmentValue)
                .Distinct()
                .ToArray();
            var hasUserKind = s.Approvers.Any(a => a.Kind == WorkflowApproverKind.User);
            if (roles.Length == 0 && !hasUserKind) roles = [AppRoles.DeptManager];

            var userIds = s.Approvers
                .Where(a => a.Kind == WorkflowApproverKind.User)
                .Select(a => a.AssignmentValue)
                .Distinct()
                .ToArray();

            if (prev is not null)
            {
                transitions[(prev.Value, s.Phase)] = roles;
                if (userIds.Length > 0) userTransitions[(prev.Value, s.Phase)] = userIds;

                // Mirror: TraLai → s.Phase cho cả Drafter (resubmit từ Trả lại = entry point thứ 2)
                if (prev.Value == PurchaseEvaluationPhase.DangSoanThao)
                {
                    transitions.TryAdd((PurchaseEvaluationPhase.TraLai, s.Phase), roles);
                    if (userIds.Length > 0)
                        userTransitions.TryAdd((PurchaseEvaluationPhase.TraLai, s.Phase), userIds);
                }

                // 2 hành động phase trung gian — Duyệt forward + Trả lại (TraLai).
                // UAT S60 (anh Kiệt 14:14): "bỏ luôn nút Từ chối — Duyệt hoặc Trả
                // về thôi" → TuChoi GỠ khỏi mọi transition map (enum + phase
                // display + data cũ GIỮ; service có guard mirror chặn API direct).
                if (prev.Value != PurchaseEvaluationPhase.DangSoanThao && s.Phase != PurchaseEvaluationPhase.DangSoanThao)
                {
                    transitions.TryAdd((s.Phase, PurchaseEvaluationPhase.TraLai), roles);
                    if (userIds.Length > 0)
                    {
                        userTransitions.TryAdd((s.Phase, PurchaseEvaluationPhase.TraLai), userIds);
                    }
                }
            }
            prev = s.Phase;
        }

        // Terminal states always available + TraLai phase
        if (!activePhases.Contains(PurchaseEvaluationPhase.TuChoi))
            activePhases.Add(PurchaseEvaluationPhase.TuChoi);
        if (!activePhases.Contains(PurchaseEvaluationPhase.DaDuyet))
            activePhases.Add(PurchaseEvaluationPhase.DaDuyet);
        if (!activePhases.Contains(PurchaseEvaluationPhase.TraLai))
            activePhases.Add(PurchaseEvaluationPhase.TraLai);

        return new PurchaseEvaluationPolicy(
            Name: $"{def.Code}-v{def.Version:D2}",
            Description: def.Description ?? def.Name,
            Transitions: transitions,
            PhaseSla: sla,
            ActivePhases: activePhases,
            UserTransitions: userTransitions.Count > 0 ? userTransitions : null);
    }
}
