using SolutionErp.Domain.Contracts;
using SolutionErp.Domain.PurchaseEvaluations;

namespace SolutionErp.Application.PurchaseEvaluations.Dtos;

public record PurchaseEvaluationListItemDto(
    Guid Id,
    string? MaPhieu,
    string TenGoiThau,
    PurchaseEvaluationType Type,
    PurchaseEvaluationPhase Phase,
    Guid ProjectId,
    string ProjectName,
    // [S93 anh Kiệt FDC] Mã dự án — tree node 📁 Dự án hiện CODE (ngắn) thay tên dài.
    string ProjectCode,
    // [Mig 49 S57bis] Hạng mục công việc — loose-Guid resolve LEFT join WorkItems
    // (mirror ProjectName). Nullable cho 4 phiếu cũ chưa gắn hạng mục.
    Guid? WorkItemId,
    string? WorkItemName,
    string? WorkItemCode,
    Guid? SelectedSupplierId,
    string? SelectedSupplierName,
    Guid? ContractId,
    DateTime? SlaDeadline,
    DateTime CreatedAt,
    // S23 t2 UAT: bro UI polish PE list — display "Ngày giờ tạo" thay SLA countdown,
    // sort theo "phiếu vừa update" (Tạo / Gửi duyệt / Trả lại). UpdatedAt được
    // AuditingInterceptor auto-set mỗi SaveChanges → covers cả 3 event tự nhiên.
    DateTime? UpdatedAt,
    // Plan AG4 (2026-05-21): bro UAT yêu cầu bổ sung Người tạo + Phòng ban tạo
    // vào PE card list. JOIN Users + Departments (LEFT join — cả 2 nullable theo
    // PE entity). FullName resolve từ Users.FullName, Department.Name từ Departments.
    Guid? DrafterUserId,
    string? DrafterName,
    Guid? DepartmentId,
    string? DepartmentName,
    // [S61 Mig 50] 2 cột ngân sách mới (mirror detail — FE list chưa render, giữ
    // parity type PeListItem).
    decimal? BudgetPeriodAmount,
    decimal? ExpectedRemainingAmount,
    // [S69 2026-06-17] Cờ gấp per-vai — FE render badge ĐỎ (PRO) / XANH (CCM) trên
    // card list + ưu tiên hiển thị. 2 cờ độc lập.
    bool IsUrgentByPro,
    bool IsUrgentByCcm,
    // [Mig 58 multi-winner] Tên các đơn vị IsWinner (FE list card join ", "; ≥2 = liên-danh).
    // Thay nhãn từ SelectedSupplierName (null khi ≥2 cùng trúng → card trống). [] khi chưa chọn.
    List<string> WinnerSupplierNames,
    // [S89 Mig 58 anh Kiệt FDC] Quy trình pin có Cấp "Duyệt là KẾT THÚC (không trình
    // CEO)" → FE render chip/note trên card list + sidebar. "first-reachable finalize"
    // theo Step.Order tăng → Level.Order tăng. V1 (ApprovalWorkflowId==null) → false/null.
    bool EndsBeforeCeo,
    string? FinalizeStepName,
    string? FinalizeLevelName);

public record PurchaseEvaluationSupplierDto(
    Guid Id,
    Guid SupplierId,
    string SupplierName,
    string? DisplayName,
    string? ContactName,
    string? ContactEmail,
    string? ContactPhone,
    string? PaymentTermText,
    string? Note,
    int Order,
    bool IsWinner);                                         // [Mig 58] đơn vị này có thuộc tập winner không (multi)

public record PurchaseEvaluationQuoteDto(
    Guid Id,
    Guid PurchaseEvaluationDetailId,
    Guid PurchaseEvaluationSupplierId,
    decimal BgVat,
    decimal ChuaVat,
    decimal ThanhTien,
    bool IsSelected,
    string? Note);

public record PurchaseEvaluationDetailDto(
    Guid Id,
    string GroupCode,
    string GroupName,
    string? ItemCode,
    string NoiDung,
    string? DonViTinh,
    decimal KhoiLuongNganSach,
    decimal KhoiLuongThiCong,
    decimal DonGiaNganSach,
    decimal ThanhTienNganSach,
    int Order,
    string? GhiChu,
    List<PurchaseEvaluationQuoteDto> Quotes);

public record PurchaseEvaluationApprovalDto(
    Guid Id,
    PurchaseEvaluationPhase FromPhase,
    PurchaseEvaluationPhase ToPhase,
    Guid? ApproverUserId,
    string? ApproverName,
    ApprovalDecision Decision,
    string? Comment,
    DateTime ApprovedAt);

public record PurchaseEvaluationChangelogDto(
    Guid Id,
    PurchaseEvaluationEntityType EntityType,
    Guid? EntityId,
    ChangelogAction Action,
    PurchaseEvaluationPhase? PhaseAtChange,
    Guid? UserId,
    string? UserName,
    string? Summary,
    string? FieldChangesJson,
    string? ContextNote,
    DateTime CreatedAt);

// Mig 29 (S21 t5) — Approver options của slot Level hiện tại (per-NV).
// FE eOffice filter Trả lại dropdown + Edit Section 2 enabled theo flag của
// Cấp hiện tại NV đang duyệt. Null nếu phiếu V1 legacy hoặc không ChoDuyet.
// Mig 30 (S22+5) — F4 +AllowApproverEditBudget cho Section "Điều chỉnh ngân sách".
// Mig 31 (S23 t1) — F2 refactor sang Approver scope ChoDuyet: +AllowApproverSkipToFinal
// cho phép Approver duyệt thẳng Cấp cuối (admin opt-in per slot). Storage cũ
// trên Users table đã drop, semantic Drafter-from-Nháp deprecated.
public record ApprovalWorkflowOptionsDto(
    bool AllowReturnOneLevel,
    bool AllowReturnOneStep,
    bool AllowReturnToAssignee,
    bool AllowReturnToDrafter,
    bool AllowApproverEditDetails,
    bool AllowApproverEditBudget,
    bool AllowApproverSkipToFinal,
    bool AllowApproverFinalize,                             // [Mig 58] slot này Approve = KẾT THÚC (không trình CEO)
    // [S155 đợt 2] F6 — slot này được XÓA phiếu khi đang duyệt. 🔴 FE gate nút Xóa bằng
    // ĐÚNG field này (`PeWorkflowPanel.tsx` `levelOptions?.allowApproverDelete === true`,
    // so `=== true` fail-closed). Thiếu field ⇒ vế đó LUÔN sai ⇒ nút KHÔNG BAO GIỜ hiện
    // với bất kỳ ai, mà BE lẫn FE đều build sạch — reviewer bắt được đúng ca này.
    // Test T27 (`PeDeleteByApproverTests`) khoá cả LỚP lỗi này: fault-inject xác nhận
    // gỡ field ra ⇒ T27 ĐỎ ngay, kèm tên cờ bị thiếu.
    bool AllowApproverDelete);

public record PurchaseEvaluationWorkflowSummaryDto(
    string PolicyName,
    string PolicyDescription,
    List<PurchaseEvaluationPhase> ActivePhases,
    List<PurchaseEvaluationPhase> NextPhases);

// Mig 22-24 V2 schema — info "Bước/Cấp đang chờ duyệt" để FE disable nút
// Duyệt nếu user không phải approver. Null khi pin V1 legacy hoặc Phase
// không phải ChoDuyet.
public record PurchaseEvaluationApprovalLevelApproverDto(
    Guid UserId,
    string FullName,
    string? Email,
    // [S76] Hiển thị-only: approver được nhập/điều chỉnh ngân sách cột nào (suy từ role —
    // Admin|Procurement→PRO, Admin|CostControl→CCM). Badge "✎ NS PRO/CCM" trong flow Duyệt NCC.
    bool CanEditProBudget,
    bool CanEditCcmBudget);

public record PurchaseEvaluationCurrentApprovalDto(
    int StepIndex,                              // 0-based
    string StepName,
    Guid? StepDepartmentId,
    string? StepDepartmentName,
    int LevelOrder,                             // 1/2/3
    string? LevelName,
    List<PurchaseEvaluationApprovalLevelApproverDto> Approvers);

// Mig 22-24 V2 — full workflow flow snapshot (Bước → Cấp → NV) cho FE render
// thay 4-phase cards cũ. Mỗi Level có Status: Done/Current/Pending.
public record PurchaseEvaluationApprovalFlowLevelDto(
    int Order,                                   // 1/2/3 trong Step
    string? Name,
    List<PurchaseEvaluationApprovalLevelApproverDto> Approvers,
    string Status,                               // "Done" | "Current" | "Pending"
    // [S89 Mig 58 anh Kiệt FDC] Cấp này (OR-of-N rows cùng Order) có NV nào bật cờ
    // "Duyệt là KẾT THÚC quy trình" → FE render NOTE/chip trong flow Bước/Cấp.
    bool AllowApproverFinalize);

public record PurchaseEvaluationApprovalFlowStepDto(
    int Order,                                   // 1-based
    string Name,
    Guid? DepartmentId,
    string? DepartmentName,
    string Status,                               // "Done" | "Current" | "Pending"
    List<PurchaseEvaluationApprovalFlowLevelDto> Levels);

public record PurchaseEvaluationApprovalFlowDto(
    int? CurrentStepIndex,                       // 0-based, null khi terminal
    int? CurrentLevelOrder,
    List<PurchaseEvaluationApprovalFlowStepDto> Steps);

public record PurchaseEvaluationAttachmentDto(
    Guid Id,
    Guid? PurchaseEvaluationSupplierId,
    string FileName,
    string StoragePath,
    long FileSize,
    string ContentType,
    PurchaseEvaluationAttachmentPurpose Purpose,
    string? Note,
    DateTime CreatedAt);

public record PurchaseEvaluationDepartmentOpinionDto(
    Guid Id,
    PeDepartmentKind Kind,
    string KindLabel,
    string? Opinion,
    DateTime? SignedAt,
    Guid? UserId,
    string? UserName);

// Mig 26 (Session 19) — Ý kiến cấp duyệt V2 dynamic theo ApprovalWorkflowLevel.
// FE Section 5 render dynamic: forEach Step → forEach Level → 1 OpinionBox.
// Service ApproveV2Async UPSERT tự động khi NV duyệt (Q1=1B). Comment empty
// fallback "(duyệt — không ý kiến)". `SignedByUserId !== ApproverUserId` →
// FE show banner "Admin duyệt thay <ApproverFullName>".
public record PurchaseEvaluationLevelOpinionDto(
    Guid Id,
    Guid ApprovalWorkflowLevelId,
    int StepOrder,
    string StepName,
    Guid? StepDepartmentId,
    string? StepDepartmentName,
    int LevelOrder,
    string? LevelName,
    Guid ApproverUserId,
    string? ApproverFullName,
    string Comment,
    DateTime SignedAt,
    Guid SignedByUserId,
    string SignedByFullName);

public record PurchaseEvaluationDetailBundleDto(
    Guid Id,
    string? MaPhieu,
    PurchaseEvaluationType Type,
    PurchaseEvaluationPhase Phase,
    string TenGoiThau,
    string? DiaDiem,
    string? MoTa,
    // [HoSoLink] hyperlink thư mục hồ sơ NAS — FE render hyperlink bấm-mở.
    string? HoSoLink,
    Guid ProjectId,
    string ProjectName,
    // [Mig 49 S57bis] Hạng mục công việc — loose-Guid resolve giống ProjectName.
    Guid? WorkItemId,
    string? WorkItemName,
    string? WorkItemCode,
    Guid? DepartmentId,
    string? DepartmentName,
    Guid? DrafterUserId,
    string? DrafterName,
    Guid? SelectedSupplierId,
    string? SelectedSupplierName,
    Guid? ContractId,
    string? PaymentTerms,
    DateTime? SlaDeadline,
    DateTime CreatedAt,
    DateTime? UpdatedAt,
    // [S61 Mig 50] Ngân sách PE mới — thay BudgetId/Budget/BudgetManual* cũ
    // (module Budget XÓA HẲN, data BudgetManualAmount migrate → BudgetPeriodAmount).
    decimal? BudgetPeriodAmount,
    decimal? ExpectedRemainingAmount,
    // [Mig 59 2026-06-24] "NS kỳ này" cột CCM (Section B THỰC HIỆN tách 3 cột) —
    // PRO=BudgetPeriodAmount sẵn có, CCM=cột này độc-lập. Nhập qua PATCH
    // /budget/ccm-period role-gate Admin|CostControl.
    decimal? CcmBudgetPeriodAmount,
    PeBudgetSummaryDto? BudgetSummary,
    // [S69 2026-06-17] Cờ gấp per-vai (PRO ĐỎ / CCM XANH) — FE render badge + toggle.
    bool IsUrgentByPro,
    bool IsUrgentByCcm,
    // [S69 · S114 multi-NCC per hạng mục] Tổng giá chào của các báo giá ĐƯỢC CHỌN (winner quote
    // total) — SUM ThanhTien các quote IsSelected (NGUỒN-SỰ-THẬT per hạng mục × NCC; Supplier.IsWinner
    // = DERIVED == Any IsSelected). 0 khi chưa chọn. Mirror predicate submit-guard
    // (PurchaseEvaluationWorkflowService ~:196). FE so với CeoApprovalThreshold hiển thị
    // "CCM duyệt-final" hoặc "cần CEO".
    decimal WinnerQuoteTotal,
    // [S69] Ngưỡng gói CEO của workflow đã pin (PE.ApprovalWorkflowId). Null khi
    // phiếu chưa pin workflow V2 hoặc admin chưa set ngưỡng.
    decimal? CeoApprovalThreshold,
    // [Mig 54 2026-06-18 — anh Kiệt FDC] Giá đề xuất tại "c. Giá chào thầu" — NGOÀI giá
    // NCC (WinnerQuoteTotal). PRO nhập dải Min/Max; CCM nhập 1 giá. ApprovedPrice* = giá
    // CHỐT người duyệt cuối chọn (source ∈ Ncc/ProMin/ProMax/Ccm). CanEdit* = capability
    // theo role (mirror PeBudgetSummary). FE tự suy "đủ điều kiện CCM duyệt-done" + "là
    // người duyệt cuối" từ WinnerQuoteTotal / CeoApprovalThreshold / roles / ApprovalFlow.
    decimal? ProSuggestedMinPrice,
    decimal? ProSuggestedMaxPrice,
    decimal? CcmSuggestedPrice,
    // [Mig 57 2026-06-19] Ghi chú giải thích giá đề xuất — vì sao min vs max (PRO) / 1 giá
    // (CCM). FE render <Textarea> kế ô giá, set cùng endpoint suggested-price/{pro,ccm}.
    string? ProSuggestedPriceNote,
    string? CcmSuggestedPriceNote,
    decimal? ApprovedPriceAmount,
    string? ApprovedPriceSource,
    decimal? ApprovedPriceMaxAmount,   // [S117] Max của khoảng khi source=ProMinMax (duyệt theo Min–Max)
    bool CanEditProSuggestedPrice,
    bool CanEditCcmSuggestedPrice,
    // Mig 23 — schema mới ApprovalWorkflowsV2 pin lúc create. Hiển thị Code +
    // Name + Version để FE show "QT-DN-V2-001 - Quy trình Duyệt NCC (v01)".
    Guid? ApprovalWorkflowId,
    string? ApprovalWorkflowCode,
    string? ApprovalWorkflowName,
    int? ApprovalWorkflowVersion,
    // Mig 29 (S21 t5) + Mig 30 (S22+5) + Mig 31 (S23 t1) — 7 Allow* options
    // của Cấp hiện tại (per-NV slot). Null nếu V1 legacy hoặc không ChoDuyet.
    // FE render Trả lại dropdown + Edit Section 2 + Section 4 ngân sách +
    // Duyệt thẳng Cấp cuối conditional. Field rename "WorkflowOptions" →
    // "CurrentLevelOptions" để rõ semantic per-slot không phải workflow-wide.
    ApprovalWorkflowOptionsDto? CurrentLevelOptions,
    PurchaseEvaluationCurrentApprovalDto? CurrentApproval,
    PurchaseEvaluationApprovalFlowDto? ApprovalFlow,
    List<PurchaseEvaluationSupplierDto> Suppliers,
    List<PurchaseEvaluationDetailDto> Details,
    List<PurchaseEvaluationApprovalDto> Approvals,
    List<PurchaseEvaluationAttachmentDto> Attachments,
    List<PurchaseEvaluationDepartmentOpinionDto> DepartmentOpinions,
    // Mig 26 (Session 19) — Section 5 V2 dynamic. Empty list cho phiếu V1
    // legacy hoặc phiếu V2 chưa có cấp nào duyệt → FE fallback message.
    List<PurchaseEvaluationLevelOpinionDto> LevelOpinions,
    // [S89 Mig 58 anh Kiệt FDC] Quy trình pin có Cấp bật "Duyệt là KẾT THÚC (không
    // trình CEO)" → FE hiển thị NOTE cho MỌI người ở detail. "first-reachable
    // finalize" = Step.Order tăng → Level.Order tăng (đúng nơi flow THỰC kết thúc).
    // V1 (ApprovalWorkflowId==null) → EndsBeforeCeo=false, names null.
    bool EndsBeforeCeo,
    string? FinalizeStepName,
    string? FinalizeLevelName,
    PurchaseEvaluationWorkflowSummaryDto Workflow);

// [S134 pe-luyke-tam-tinh] Phiếu TRƯỚC cùng cặp (ProjectId, WorkItemId) CHƯA terminal —
// render list "cần lưu ý" ở block ngân sách. MaPhieu nullable (entity string?, data cổ có null).
// Phase = int (PurchaseEvaluationPhase underlying) để FE map label VN qua PurchaseEvaluationPhaseLabel.
public record PePendingPriorPeDto(Guid Id, string? MaPhieu, int Phase);

// [S61 Mig 50] Bảng "TỔNG HỢP NGÂN SÁCH TRÌNH KÝ" theo Excel anh Kiệt — BE compute
// kèm PE detail GET. Record PeWorkItemBudgets dùng chung mọi phiếu cùng cặp
// (ProjectId, WorkItemId). BudgetId null = phiếu cũ chưa gắn Hạng mục.
// FullAmount = (Initial??0)+(Adjustment??0); cả 2 null → ProEstimate??0 với
// FullIsEstimate=true (FE badge "dự trù PRO"). CanEditPro/CanEditCcm = capability
// flag BE-computed theo role (Procurement / CostControl | Admin — pattern S54).
// Lũy kế: các phiếu cùng cặp, Id != this, CreatedAt < this.CreatedAt:
//   PreviousSubmittedTotal = SUM(BudgetPeriodAmount) WHERE Phase IN (ChoDuyet, DaDuyet)
//   PreviousSelectedTotal  = SUM(quote ThanhTien WHERE IsSelected) WHERE Phase = DaDuyet
//   CurrentProposalTotal   = SUM(quote ThanhTien WHERE IsSelected) phiếu NÀY (0 khi chưa chọn).
public record PeBudgetSummaryDto(
    Guid? BudgetId,
    decimal? ProEstimateAmount,
    string? ProNote,
    decimal? InitialAmount,
    decimal? AdjustmentAmount,
    string? CcmNote,
    decimal FullAmount,
    bool FullIsEstimate,
    bool CanEditPro,
    bool CanEditCcm,
    decimal PreviousSubmittedTotal,
    int PreviousSubmittedCount,
    decimal PreviousSelectedTotal,
    int PreviousSelectedCount,
    decimal CurrentProposalTotal,
    // [S76] PRO column split — ban hành + hiệu chỉnh riêng cho PRO (mirror CCM Initial/Adjustment).
    decimal? ProInitialAmount,
    decimal? ProAdjustmentAmount,
    // [S133] true = phiếu DaDuyet serve từ snapshot ngân sách (bất biến, đọc cột ApprovedBudget*
    // thay record PeWorkItemBudgets live); false = phiếu chưa duyệt đọc LIVE. FE badge "đã chốt" +
    // ẩn nút sửa. Append CUỐI record (default false) → construction site cũ không gãy.
    bool BudgetFrozen = false,
    // [S134 pe-luyke-tam-tinh] Lũy kế TẠM TÍNH — phiếu TRƯỚC cùng cặp đã trình/chọn NHƯNG CHƯA duyệt
    // xong (BỔ SUNG số CHÍNH XÁC PreviousSubmitted*/PreviousSelected*, KHÔNG thay). Append CUỐI record
    // (default 0/null) → construction site cũ + nhánh frozen (DaDuyet bất biến) không gãy.
    decimal PendingSubmittedTotal = 0,
    int PendingSubmittedCount = 0,
    decimal PendingSelectedTotal = 0,
    int PendingSelectedCount = 0,
    IReadOnlyList<PePendingPriorPeDto>? PendingPriorPes = null);
