using Microsoft.EntityFrameworkCore;
using SolutionErp.Application.Common.Interfaces;
using SolutionErp.Application.PurchaseEvaluations.Dtos;
using SolutionErp.Domain.PurchaseEvaluations;

namespace SolutionErp.Application.PurchaseEvaluations;

// [S133 pe-budget-freeze] Lũy kế ngân sách "phiếu TRƯỚC cùng cặp (ProjectId, WorkItemId)"
// + "giá trị kỳ này" (own quotes IsSelected). Extract BEHAVIOR-PRESERVING từ
// GetPurchaseEvaluationQuery :917-951 để DÙNG CHUNG cho:
//   (1) live display (GetPurchaseEvaluationQuery nhánh chưa-duyệt — giữ nguyên số),
//   (2) snapshot khi finalize (ApplyBudgetSnapshotOnFinalizeAsync — chốt 4 số lũy kế).
//
// Semantics GIỮ NGUYÊN (single source of truth = query handler cũ):
//   peers = PurchaseEvaluations cùng (ProjectId, WorkItemId), Id != this, CreatedAt < this
//           (HasQueryFilter !IsDeleted tự loại phiếu xoá mềm).
//   - PrevSubmitted*  : peers Phase ∈ (ChoDuyet, DaDuyet) → Count + SUM(BudgetPeriodAmount ?? 0).
//   - PrevSelected*   : peers Phase = DaDuyet AND có ≥1 Supplier IsWinner (existence);
//                       total = SUM ThanhTien quote IsSelected của các peer đó.
//   - CurrentProposalTotal : SUM ThanhTien quote IsSelected của CHÍNH phiếu này (own supplier rows).
public readonly record struct PeBudgetAccumulation(
    decimal PrevSubmittedTotal,
    int PrevSubmittedCount,
    decimal PrevSelectedTotal,
    int PrevSelectedCount,
    decimal CurrentProposalTotal);

// [S134 pe-luyke-tam-tinh] Lũy kế TẠM TÍNH — phiếu TRƯỚC cùng cặp (ProjectId, WorkItemId)
// đã trình/đã chọn NHƯNG CHƯA duyệt xong. Bổ sung display "tạm tính" — KHÔNG đổi số CHÍNH XÁC
// (PeBudgetAccumulation qua ComputeAsync bất động).
public readonly record struct PePendingAccumulation(
    decimal PendingSubmittedTotal,
    int PendingSubmittedCount,
    decimal PendingSelectedTotal,
    int PendingSelectedCount,
    IReadOnlyList<PePendingPriorPeDto> PriorPes);

public static class PeBudgetAccumulator
{
    public static async Task<PeBudgetAccumulation> ComputeAsync(
        IApplicationDbContext db,
        Guid projectId,
        Guid workItemId,
        Guid peId,
        DateTime peCreatedAt,
        IReadOnlyList<Guid> currentSupplierRowIds,
        CancellationToken ct)
    {
        var peers = db.PurchaseEvaluations.AsNoTracking()
            .Where(p => p.ProjectId == projectId && p.WorkItemId == workItemId
                && p.Id != peId && p.CreatedAt < peCreatedAt);

        var submitted = await peers
            .Where(p => p.Phase == PurchaseEvaluationPhase.ChoDuyet
                || p.Phase == PurchaseEvaluationPhase.DaDuyet)
            .Select(p => p.BudgetPeriodAmount)
            .ToListAsync(ct);
        var prevSubmittedCount = submitted.Count;
        var prevSubmittedTotal = submitted.Sum(v => v ?? 0m);

        var selectedPeers = peers.Where(p => p.Phase == PurchaseEvaluationPhase.DaDuyet
            && p.Suppliers.Any(s => s.IsWinner));
        var prevSelectedCount = await selectedPeers.CountAsync(ct);
        var prevSelectedTotal = await (
            from p in selectedPeers
            join s in db.PurchaseEvaluationSuppliers.AsNoTracking()
                on p.Id equals s.PurchaseEvaluationId
            join q in db.PurchaseEvaluationQuotes.AsNoTracking()
                on s.Id equals q.PurchaseEvaluationSupplierId
            where q.IsSelected
            select (decimal?)q.ThanhTien).SumAsync(ct) ?? 0m;

        var currentProposalTotal = currentSupplierRowIds.Count == 0 ? 0m
            : await db.PurchaseEvaluationQuotes.AsNoTracking()
                .Where(q => currentSupplierRowIds.Contains(q.PurchaseEvaluationSupplierId) && q.IsSelected)
                .SumAsync(q => (decimal?)q.ThanhTien, ct) ?? 0m;

        return new PeBudgetAccumulation(
            prevSubmittedTotal, prevSubmittedCount,
            prevSelectedTotal, prevSelectedCount,
            currentProposalTotal);
    }

    // [S134] Lũy kế TẠM TÍNH — CHỈ ĐỌC, KHÔNG mutate. peers = window Y HỆT ComputeAsync (:38-40).
    //   PendingSubmitted* = peers Phase ∉ {DangSoanThao, DaDuyet, ChoDuyet, TuChoi} = {TraLai + legacy 2-6}
    //                       → Count + SUM(BudgetPeriodAmount ?? 0). ChoDuyet/DaDuyet ĐÃ nằm trong
    //                       ComputeAsync PrevSubmitted (chính xác) → loại-trừ tránh double-count.
    //   PendingSelected*  = peers Phase ∉ {DangSoanThao, DaDuyet, TuChoi} AND ≥1 Supplier IsWinner
    //                       (GỒM ChoDuyet-có-winner = gap chính đề bài) → Count + SUM(ThanhTien IsSelected).
    //                       Mirror shape ComputeAsync :50-60 (join Suppliers→Quotes).
    //   PriorPes          = peers CHƯA terminal (Phase ∉ {DaDuyet, TuChoi}) → list render, order CreatedAt.
    public static async Task<PePendingAccumulation> ComputePendingAsync(
        IApplicationDbContext db,
        Guid projectId,
        Guid workItemId,
        Guid peId,
        DateTime peCreatedAt,
        CancellationToken ct)
    {
        var peers = db.PurchaseEvaluations.AsNoTracking()
            .Where(p => p.ProjectId == projectId && p.WorkItemId == workItemId
                && p.Id != peId && p.CreatedAt < peCreatedAt);

        var pendingSubmitted = await peers
            .Where(p => p.Phase != PurchaseEvaluationPhase.DangSoanThao
                && p.Phase != PurchaseEvaluationPhase.DaDuyet
                && p.Phase != PurchaseEvaluationPhase.ChoDuyet
                && p.Phase != PurchaseEvaluationPhase.TuChoi)
            .Select(p => p.BudgetPeriodAmount)
            .ToListAsync(ct);
        var pendingSubmittedCount = pendingSubmitted.Count;
        var pendingSubmittedTotal = pendingSubmitted.Sum(v => v ?? 0m);

        var pendingSelectedPeers = peers.Where(p => p.Phase != PurchaseEvaluationPhase.DangSoanThao
            && p.Phase != PurchaseEvaluationPhase.DaDuyet
            && p.Phase != PurchaseEvaluationPhase.TuChoi
            && p.Suppliers.Any(s => s.IsWinner));
        var pendingSelectedCount = await pendingSelectedPeers.CountAsync(ct);
        var pendingSelectedTotal = await (
            from p in pendingSelectedPeers
            join s in db.PurchaseEvaluationSuppliers.AsNoTracking()
                on p.Id equals s.PurchaseEvaluationId
            join q in db.PurchaseEvaluationQuotes.AsNoTracking()
                on s.Id equals q.PurchaseEvaluationSupplierId
            where q.IsSelected
            select (decimal?)q.ThanhTien).SumAsync(ct) ?? 0m;

        var priorPes = await peers
            .Where(p => p.Phase != PurchaseEvaluationPhase.DaDuyet
                && p.Phase != PurchaseEvaluationPhase.TuChoi)
            .OrderBy(p => p.CreatedAt)
            .Select(p => new PePendingPriorPeDto(p.Id, p.MaPhieu, (int)p.Phase))
            .ToListAsync(ct);

        return new PePendingAccumulation(
            pendingSubmittedTotal, pendingSubmittedCount,
            pendingSelectedTotal, pendingSelectedCount,
            priorPes);
    }
}
