// [W2 KHKK — S161 2026-07-29] Kế hoạch ký kết HĐ (GĐ2, tờ FO-002.01) types.
// File MIRROR SHA256 identical với fe-admin counterpart.
//
// 🔴 NGUỒN SHAPE = ENTITY `src/Backend/SolutionErp.Domain/ContractSigningPlans/*.cs`
// (W1 Mig 69) — BE lane viết `ContractSigningPlanFeatures.cs` SONG SONG lượt này, DTO
// mirror thẳng tên cột entity (camelCase khi serialize). Chỗ nào BE trả khác tên thì
// SỬA Ở ĐÂY (1 file, 2 app) chứ đừng vá rải ở page.
//
// Hợp đồng FE ↔ BE lượt W2 (base `/api`):
//   GET    /contract-signing-plans            ?phase&search&page&pageSize  → PagedResult<KhkkListItemDto>
//   GET    /contract-signing-plans/deleted    (mirror PE `/purchase-evaluations/deleted`)
//   GET    /contract-signing-plans/{id}                                    → KhkkDetailDto
//   POST   /contract-signing-plans            CreateKhkkInput              → { id, maKeHoach }
//   PUT    /contract-signing-plans/{id}       UpdateKhkkDraftInput
//   DELETE /contract-signing-plans/{id}
//   GET    /contract-signing-plans/approved-pe-awaiting-plan               → KhkkPeCandidateDto[]  [F-1 S161: khớp route BE thật]
//   POST   /contract-signing-plans/{id}/dossier-items          UpsertKhkkDossierItemInput (id=null ⇒ tạo)
//   PUT    /contract-signing-plans/{id}/dossier-items/{itemId} UpsertKhkkDossierItemInput (sửa — F-4: POST luôn insert)
//   DELETE /contract-signing-plans/{id}/dossier-items/{itemId}
//   POST   /contract-signing-plans/{id}/attachments            multipart { file, purpose, dossierItemId? }
//   GET    /contract-signing-plans/{id}/attachments/{attId}/download
//   DELETE /contract-signing-plans/{id}/attachments/{attId}
//
// Hợp đồng FE ↔ BE lượt W3 (LEAD chốt — 2 lane implement đúng LITERAL từng tên field):
//   POST   /contract-signing-plans/{id}/transitions  KhkkTransitionInput → KhkkTransitionResult
//          policy `KeHoachKyKet.Update`
//
// [K2 S164] Delta hợp-đồng lượt K2 (BE đã land — đọc `ContractSigningPlanFeatures.cs`):
//   GET  /contract-signing-plans  **+`?group=n`** (`Controller:42` `[FromQuery(Name="group")]`
//        → `ListContractSigningPlansQuery.ApprovalGroup` `:700-705`). K2 = CHỦ tham số;
//        cây 8 folder (K5) + leaf nhóm (K4b) chỉ TIÊU THỤ ⇒ FE list KHÔNG tự đẻ chỗ lọc
//        thứ hai (chờ K4b/K5), chỉ HIỂN THỊ nhóm của từng phiếu.
//   POST /contract-signing-plans  body **+`approvalGroup?`** (`CreateCommand:333-337`,
//        null ⇒ nhóm 1 — CỐ Ý nullable để client cũ không gãy).
//   GET  /contract-signing-plans/approved-pe-awaiting-plan → **ĐỔI HÌNH DẠNG**: PE đã có
//        kế hoạch KHÔNG còn bị loại khỏi danh sách (`Features.cs:1291-1295`), thay vào đó
//        trả `existingGroups` để FE khoá đúng nhóm đã dùng (OG-7 UI-hướng-1).

// Mirror `ContractSigningPlanPhase.cs` — 🔴 bắt đầu từ 1 (0 falsy JS).
export const KhkkPhase = {
  DangSoanThao: 1,
  ChoDuyet: 2,
  DaDuyet: 3,
  TraLai: 98,
  TuChoi: 99,
} as const
export type KhkkPhaseValue = (typeof KhkkPhase)[keyof typeof KhkkPhase]

export const KHKK_PHASE_LABELS: Record<KhkkPhaseValue, string> = {
  1: 'Đang soạn thảo',
  2: 'Chờ duyệt',
  3: 'Đã duyệt',
  98: 'Trả lại',
  99: 'Từ chối',
}

// Pattern 14 (Tailwind JIT): full class string literal, KHÔNG nội suy mảnh class.
export const KHKK_PHASE_BADGE: Record<KhkkPhaseValue, string> = {
  1: 'bg-slate-100 text-slate-700 border-slate-300',
  2: 'bg-amber-100 text-amber-800 border-amber-300',
  3: 'bg-emerald-100 text-emerald-800 border-emerald-300',
  98: 'bg-orange-100 text-orange-800 border-orange-300',
  99: 'bg-red-100 text-red-800 border-red-300',
}

// Mirror `ContractSigningPlanDossierItem.cs` — căn cứ mục b.8-9.
export const DossierItemKind = {
  MauVatLieu: 1,
  Shopdrawing: 2,
  Khac: 99,
} as const
export type DossierItemKindValue = (typeof DossierItemKind)[keyof typeof DossierItemKind]

export const DOSSIER_KIND_LABELS: Record<DossierItemKindValue, string> = {
  1: 'Mẫu vật liệu',
  2: 'Shopdrawing',
  99: 'Khác',
}

export const DossierItemStatus = {
  ChuaNop: 1,
  DaNop: 2,
  TvgsDuyet: 3,
  TvgsBac: 4,
} as const
export type DossierItemStatusValue = (typeof DossierItemStatus)[keyof typeof DossierItemStatus]

export const DOSSIER_STATUS_LABELS: Record<DossierItemStatusValue, string> = {
  1: 'Chưa nộp',
  2: 'Đã nộp',
  3: 'TVGS duyệt',
  4: 'TVGS bác',
}

export const DOSSIER_STATUS_BADGE: Record<DossierItemStatusValue, string> = {
  1: 'bg-slate-100 text-slate-700 border-slate-300',
  2: 'bg-sky-100 text-sky-800 border-sky-300',
  3: 'bg-emerald-100 text-emerald-800 border-emerald-300',
  4: 'bg-red-100 text-red-800 border-red-300',
}

// Mirror `ContractSigningPlanAttachmentPurpose`.
export const KhkkAttachmentPurpose = {
  DossierScan: 1,
  PlanDocument: 2,
  // [S171 BE-7] File người DUYỆT đính kèm lúc bấm Duyệt/Trả lại/Từ chối (panel 3 mục 5).
  // Upload qua đường RIÊNG `POST /contract-signing-plans/{id}/approval-attachments` —
  // BE tự ép purpose, FE KHÔNG gửi số enum này lên.
  ApprovalAttachment: 3,
  Other: 99,
} as const
export type KhkkAttachmentPurposeValue =
  (typeof KhkkAttachmentPurpose)[keyof typeof KhkkAttachmentPurpose]

export const KHKK_ATTACHMENT_PURPOSE_LABELS: Record<KhkkAttachmentPurposeValue, string> = {
  1: 'Scan căn cứ',
  2: 'Bản kế hoạch',
  3: 'File duyệt',
  99: 'Khác',
}

// ===================== K2 S164 — Nhóm duyệt N1..N8 (SP-002) ==========================
// Mirror `ContractSigningPlanScope.cs` (`ContractSigningPlanFeatures.cs:201-203`):
// Min=1 · Max=8 · Default=1. Không gửi nhóm ⇒ BE gán 1 (khớp backfill Mig 71).
export const KHKK_APPROVAL_GROUP_MIN = 1
export const KHKK_APPROVAL_GROUP_MAX = 8
export const KHKK_APPROVAL_GROUP_DEFAULT = 1
export const KHKK_APPROVAL_GROUPS = [1, 2, 3, 4, 5, 6, 7, 8] as const

// 🔴 NHÃN NGHIỆP VỤ 8 nhóm — nguồn `danh-muc-sp002-transcribe.md:20-29` ("8 NHÃN MENU
// đề xuất", **[OG-6] anh soát SAU trên UI**). Cùng bộ chữ này K4a sẽ seed làm LABEL menu
// ⇒ nếu K4a land nhãn khác thì SỬA Ở ĐÂY (1 const, 2 app), đừng vá rải trong page.
// Rút gọn có chủ đích: bỏ số thứ tự đầu dòng của bảng (ô select đã có "N{n}").
//
// [K4a S166 — acceptance-5 single-source] ĐÃ ĐỐI CHIẾU TỪNG KÝ TỰ với nhãn BE seed
// (`DbInitializer.cs:1960` cho nhóm 1 + dict `khkkGroupLabels` `:2127-2136` cho nhóm
// 2..8, cùng `labelBackfill:2235`): 8/8 nhóm khớp theo quan hệ `"{n}. " + chuỗi dưới đây`.
// ⇒ K4a KHÔNG đẻ map thứ hai. Bản đầy đủ (có số thứ tự) lấy qua `khkkGroupMenuLabel(n)`
// ngay bên dưới — DERIVE chứ không chép, để sửa chữ vẫn chỉ đụng đúng 1 chỗ này.
export const KHKK_APPROVAL_GROUP_LABELS: Record<number, string> = {
  1: 'Thiết bị, máy móc, vật tư phụ (A1)',
  2: 'Kết cấu, hạ tầng, phá dỡ & DV hỗ trợ thi công (A2-A3)',
  3: 'Hoạt động văn phòng (A4)',
  4: 'Vật tư (B1)',
  5: 'Thầu phụ xây dựng (B2)',
  6: 'Thầu phụ MEP (B3)',
  7: 'BCH công trường (C1-C3)',
  8: 'HĐ chưa ủy quyền — CEO (5.2)',
}

// [K4a S166] Nhãn nhóm ĐẦY ĐỦ = đúng chuỗi BE ghi vào `MenuItems.Label` khi seed.
// 🔴 ĐÂY KHÔNG PHẢI NGUỒN CỦA SIDEBAR. Sidebar render nhãn từ payload `/api/menus/me`
//    (bảng `MenuItems`, admin còn đổi được qua `displayLabel` — Mig 27), nên đừng ai
//    tưởng sửa chuỗi ở đây thì sidebar đổi theo. Hàm này phục vụ chỗ FE tự vẽ tên nhóm
//    mà không đi qua menu: cây 8 thư mục nhóm (K5), tiêu đề trang khi vào từ leaf nhóm,
//    màn xem luồng duyệt theo nhóm (WfView).
// ⚠️ Ràng buộc ngầm: BE đang đặt nhãn theo khuôn "{n}. {tên}". Nếu BE bỏ tiền tố số thì
//    hàm này lệch một cách CÂM (không đỏ build) — lúc đó sửa chính hàm này, đừng vá page.
export function khkkGroupMenuLabel(n: number): string {
  const label = KHKK_APPROVAL_GROUP_LABELS[n]
  return label ? `${n}. ${label}` : `Nhóm ${n}`
}

// [K4a S166 — O-2] Mã quy trình duyệt của nhóm n. BE khớp bằng regex `^KHKK-N([1-8])$`
// (`ContractSigningPlanFeatures.cs:420`, rào 409 "phiếu nhóm 3 pin quy trình nhóm 5");
// 8 workflow do `DbInitializer.SeedKhkkGroupWorkflowsAsync` seed, ApplicableType=10.
// Gom về 1 hàm để FE không rải chuỗi `KHKK-N` ở nhiều nơi rồi lệch nhau.
export const khkkGroupWorkflowCode = (n: number) => `KHKK-N${n}`

export interface KhkkListItemDto {
  id: string
  maKeHoach: string | null
  phase: KhkkPhaseValue
  purchaseEvaluationId: string
  peMaPhieu: string | null
  peTenGoiThau: string | null   // [F-5 S161] BE trả `PeTenGoiThau` (List :39 + Detail :124) — KHÔNG phải tenGoiThau
  // [S175] Hang muc CONG VIEC cua du an, tu phieu Duyet NCC nguon.
  // KHAC `KhkkLineDto.tenHangMuc` (danh-muc SP-002 phan loai hop dong) - 2 truc khac nhau.
  peWorkItemName: string | null
  projectId: string
  projectName: string | null
  departmentId: string | null
  departmentName: string | null
  drafterUserId: string
  drafterFullName: string | null
  approvalWorkflowId: string | null
  workflowCode: string | null
  currentApprovalLevelOrder: number | null
  totalProposedAmount: number | null
  // [K2 S164] `ContractSigningPlanListItemDto:63` — nhóm duyệt N1..N8 của phiếu (BE trả
  // TRÊN CẢ list lẫn detail ⇒ `KhkkDetailDto` kế thừa được, không khai lại).
  approvalGroup: number
  // [K2 S164 — vá-8] `:64` Σ `ApprovedAmount` (phiếu chưa duyệt → 0). Có Σ này thì màn
  // danh sách và màn chi tiết không nói hai con số khác nhau trên CÙNG một phiếu.
  // 🔴 nullable Ở ĐÂY (không phải ở BE): `KhkkDetailDto extends KhkkListItemDto` mà
  // `ContractSigningPlanDetailDto` KHÔNG có field này ⇒ trên màn chi tiết nó là undefined.
  totalApprovedAmount: number | null
  createdAt: string
  updatedAt: string | null
  // [K7 S167 — vá-4b] TẬP id HĐ đã sinh ra từ CÁC DÒNG của phiếu này.
  // ✅ KHỚP BE: `ContractSigningPlanListItemDto:75 List<Guid> ContractIds` (lane BE K7 vá-4a,
  //    append-CUỐI) ⇒ JSON `contractIds`. Đối chiếu đã ghi ở `sub-implfe-k7.md` mục KHỚP-DTO.
  // VÌ SAO CẦN: cây 4 folder phải hiện ĐỦ N hợp đồng của một gói, mà `pe.contractId` chỉ
  //    giữ HĐ ĐẦU (`CreateContractFromEvaluationFeatures.cs:143-145`) — HĐ thứ 2 trở đi
  //    CHỈ có ở dòng phiếu KHKK (`ContractSigningPlanLineDto:74 Guid? ContractId`).
  // 🔴 KHAI OPTIONAL DÙ BE KHÔNG NULL: payload đang nằm trong cache React Query từ trước
  //    lượt này (và API cũ chưa deploy) KHÔNG có field ⇒ optional để cây bớt nguồn chứ
  //    KHÔNG vỡ; chỗ đọc phân biệt được vắng-field ⟂ mảng-rỗng (xem `usePipelineStages`).
  // ⇒ Mọi nơi đọc qua `khkkPlanContractIds()` bên dưới — đổi tên chỉ sửa ĐÚNG 1 hàm đó.
  contractIds?: string[] | null
}

export interface KhkkLineDto {
  id: string
  supplierId: string
  supplierName: string | null
  peReferenceAmount: number
  proposedAmount: number
  approvedAmount: number | null
  contractId: string | null
  note: string | null
  // [K2 S164] `ContractSigningPlanLineDto:78-79` — hạng mục SP-002 của dòng.
  // `tenHangMuc` là DENORM lúc gán (danh mục đổi tên KHÔNG viết lại lịch sử phiếu).
  // null = dòng chưa gán hạng mục (mồi lúc auto-sinh, `Features.cs:454-455`) — màn chi
  // tiết hiện "—"; ĐƯỜNG GÁN (Lines-editor) thuộc **K4b**, K2 chỉ hiển thị.
  catalogEntryId: string | null
  tenHangMuc: string | null
  // [Mig 72 S177] `ContractSigningPlanLineDto` append-CUỐI — MÃ hạng mục ("A1-01"), DENORM
  // cùng lúc với `tenHangMuc`. null = dòng chưa gán hạng mục ⇒ hiển thị lùi về tên.
  maHangMuc: string | null
}

export interface KhkkDossierItemDto {
  id: string
  kind: DossierItemKindValue
  supplierId: string | null
  supplierName: string | null
  name: string
  status: DossierItemStatusValue
  tvgsName: string | null
  tvgsResultAt: string | null
  note: string | null
}

export interface KhkkAttachmentDto {
  id: string
  dossierItemId: string | null   // [F-7 S161] khớp DTO BE `DossierItemId`
  fileName: string
  fileSize: number
  contentType: string | null
  purpose: KhkkAttachmentPurposeValue
  note: string | null
  createdAt: string
}

export interface KhkkLevelOpinionDto {
  id: string
  approvalWorkflowLevelId: string
  stepOrder: number | null
  stepName: string | null
  levelOrder: number | null
  // [W3 S161] BE `ContractSigningPlanLevelOpinionDto:99` CÓ field này (W2 khai thiếu).
  // `signedByUserId !== approverUserId` ⇒ có người duyệt THAY (Admin) — panel gắn nhãn.
  approverUserId: string | null
  comment: string | null
  signedAt: string
  signedByUserId: string
  signedByFullName: string
}

// [W3 S161] Cây quy trình THÔ do BE trả (`ContractSigningPlanWorkflowLevelDto:105-110`).
// 🔴 KHÁC PE: BE **KHÔNG** precompute `status` Done/Current/Pending — FE tự suy từ cặp
// con-trỏ `currentWorkflowStepIndex` (INDEX 0-based vào mảng steps) + `currentApprovalLevelOrder`
// (GIÁ TRỊ `level.order`). Xem `ContractSigningPlanFeatures.cs:224-226` + `:259-260`.
export interface KhkkWorkflowLevelDto {
  id: string
  order: number
  name: string | null
  approverUserId: string
  approverFullName: string | null
  // [F-1 S166] Cờ per-Cấp "được KẾT THÚC quy trình tại cấp này" (admin tick ở Designer).
  // Panel dùng để hiện ô-tích opt-out khi duyệt — mirror BE `ResolveActingLevel`.
  allowApproverFinalize: boolean
}

// Mirror `ContractSigningPlanWorkflowStepDto`.
export interface KhkkWorkflowStepDto {
  id: string
  order: number
  name: string
  departmentId: string | null
  levels: KhkkWorkflowLevelDto[]
  // [S171 BE-4] Tên phòng của Bước (BE join `Departments`). Nuôi ĐỒNG THỜI 2 chỗ:
  // chip phòng ở panel 3 (P3-4) và header nhóm Section 5 (P2-5). null = Bước không gắn phòng.
  departmentName: string | null
}

// [S171 BE-2] Lịch sử duyệt — panel 3 mục 6 "Lịch sử duyệt (N)" của Ảnh 2.
// 🔴 BE ĐÃ LỌC hàng `decision = Pending` (hành-vi GỬI duyệt) để số `(N)` cùng nghĩa với `(N)`
// của PE. FE KHÔNG cần dedupe lại. Sự kiện "Gửi duyệt" vẫn còn ở `changelogs`.
export const KhkkApprovalDecision = {
  Pending: 0,
  Approve: 1,
  Reject: 2,
  AutoApprove: 3,
} as const
export type KhkkApprovalDecisionValue =
  (typeof KhkkApprovalDecision)[keyof typeof KhkkApprovalDecision]

export interface KhkkApprovalDto {
  id: string
  fromPhase: KhkkPhaseValue
  toPhase: KhkkPhaseValue
  decision: KhkkApprovalDecisionValue
  comment: string | null
  approvalWorkflowLevelId: string | null
  // 4 field dưới DẪN XUẤT từ `approvalWorkflowLevelId` (loose-Guid, no-FK) qua cây workflow
  // đã pin ⇒ null khi Cấp đã bị admin xoá. Dòng lịch sử VẪN hiện (BE không nuốt hàng).
  stepOrder: number | null
  stepName: string | null
  levelOrder: number | null
  levelName: string | null
  approvedByUserId: string | null
  approvedByFullName: string | null
  approvedAt: string
}

// [S171 BE-5] "Lịch sử thay đổi" — `GET /contract-signing-plans/{id}/changelogs`
// (policy `KeHoachKyKet.Read` + rào hàng `EnsureCanViewAsync` ở handler).
export const KhkkChangelogEntityType = {
  Header: 1,
  Line: 2,
  DossierItem: 3,
  Workflow: 4,
  Attachment: 5,
} as const
export type KhkkChangelogEntityTypeValue =
  (typeof KhkkChangelogEntityType)[keyof typeof KhkkChangelogEntityType]

export const KHKK_CHANGELOG_ENTITY_TYPE_LABELS: Record<number, string> = {
  1: 'Thông tin chung',
  2: 'Dòng giá',
  3: 'Căn cứ hồ sơ',
  4: 'Quy trình',
  5: 'File đính kèm',
}

// Mirror `ChangelogAction` (enum DÙNG CHUNG 3 module — `Domain/Contracts/ChangelogAction`).
export const KHKK_CHANGELOG_ACTION_LABELS: Record<number, string> = {
  1: 'Tạo',
  2: 'Cập nhật',
  3: 'Xóa',
  4: 'Chuyển trạng thái',
}

export interface KhkkChangelogDto {
  id: string
  entityType: KhkkChangelogEntityTypeValue
  entityId: string | null
  action: number
  phaseAtChange: KhkkPhaseValue | null
  userId: string | null
  userName: string | null
  summary: string | null
  fieldChangesJson: string | null
  contextNote: string | null
  createdAt: string
}

export interface KhkkDetailDto extends KhkkListItemDto {
  workflowName: string | null
  currentWorkflowStepIndex: number | null
  slaDeadline: string | null
  hoSoLink: string | null
  ghiChu: string | null
  lines: KhkkLineDto[]
  dossierItems: KhkkDossierItemDto[]
  attachments: KhkkAttachmentDto[]
  levelOpinions: KhkkLevelOpinionDto[]
  // `ContractSigningPlanDetailDto:147` — field CUỐI của record BE.
  workflowSteps: KhkkWorkflowStepDto[]
  // [K2 S164] `ContractSigningPlanDetailDto:166` — CỜ HIỂN THỊ dẫn xuất từ phase
  // (`phase == DaDuyet`), KHÔNG phải cột DB. Số đã đóng băng ở tầng dữ liệu bởi
  // `ApprovedAmount ??=` tại choke-point finalize. Khuôn tên `budgetFrozen` của PE S133.
  budgetFrozen: boolean

  // ===================== [S171 BE-1/BE-1b/BE-2] 5 field nuôi panel 3 ====================
  // 🔸 Đính chính ghi-chú K2 cũ ("BE KHÔNG expose `endedByLevelFinalize`"): từ S171 CÓ expose.
  /** Số phiên bản quy trình đã pin — dòng meta `{workflowCode} v{NN} · {workflowName}`. */
  workflowVersion: number | null
  /**
   * Banner "kết thúc sớm — không qua CEO". 3-NGẢ ở BE, FE chỉ đọc:
   * phiếu `DaDuyet` → CỜ RUNTIME thật (Mig 71); phiếu chưa xong → suy từ cấu hình nhưng
   * POINTER-AWARE (chỉ tính cấp `allowApproverFinalize` ở-hoặc-SAU con-trỏ); chưa pin quy trình → false.
   */
  endedByLevelFinalize: boolean
  /** Tên Bước/Cấp có `allowApproverFinalize` ĐẦU TIÊN — nhãn CẤU HÌNH, KHÔNG có cột DB nào lưu. */
  finalizeStepName: string | null
  finalizeLevelName: string | null
  /** Lịch sử duyệt (BE đã lọc `decision = Pending`). */
  approvals: KhkkApprovalDto[]
  /**
   * [S177] MÃ của hạng mục CÔNG VIỆC DỰ ÁN ("DAO_MONG") — cặp mã của `peWorkItemName`.
   * 🔴 Khai Ở ĐÂY chứ KHÔNG ở `KhkkListItemDto`, dù `peWorkItemName` nằm trên đó: BE chỉ
   * trả `PeWorkItemCode` trên `ContractSigningPlanDetailDto` (append-CUỐI), list KHÔNG có.
   * Khai nhầm lên list là hứa một field mà payload danh sách không bao giờ mang.
   */
  peWorkItemCode: string | null
}

// [K7 S167 — vá-4b] Tập id HỢP ĐỒNG mà một phiếu KHKK đã đẻ ra. Gom từ MỌI nguồn CÓ THẬT
// trên payload thay vì đọc một ô cố định — hình dạng "một TẬP" là thứ K5 đã chừa sẵn:
//   (1) `contractIds` — LIST payload (BE `…ListItemDto:75`; vắng khi payload đến từ cache
//       cũ / API chưa deploy ⇒ nhánh này trả rỗng, KHÔNG ném lỗi);
//   (2) `lines[].contractId` — DETAIL payload, TỒN TẠI HÔM NAY trên đĩa
//       (`KhkkDetailDto.lines` + `KhkkLineDto.contractId`, mirror BE `…LineDto:74`).
// Trả mảng CÓ THỂ TRÙNG — nơi gọi đang đổ vào `Set` nên không khử trùng hai lần.
export function khkkPlanContractIds(
  plan: KhkkListItemDto & Partial<Pick<KhkkDetailDto, 'lines'>>,
): string[] {
  const out: string[] = []
  for (const id of plan.contractIds ?? []) if (id) out.push(id)
  for (const line of plan.lines ?? []) if (line.contractId) out.push(line.contractId)
  return out
}

// Phiếu PE nguồn đủ điều kiện lập kế hoạch (DaDuyet + có NCC trúng thầu).
// CỐ Ý là TẬP CON của `ApprovedPeAwaitingPlanDto` BE trả — field thừa bỏ qua runtime.
// 🔴 [K2 S164 — OG-7] Vị ngữ "chưa có plan sống" ĐÃ BỎ khỏi picker (`Features.cs:1291-1295`):
// PE đã có kế hoạch VẪN hiện, kèm `existingGroups`.
export interface KhkkPeCandidateDto {
  id: string
  maPhieu: string | null
  tenGoiThau: string
  projectName: string | null
  workItemName: string | null
  winnerSupplierNames: string[]
  createdAt: string
  // [K2 S164] `ApprovedPeAwaitingPlanDto:191` — nhóm duyệt của các kế hoạch ĐANG SỐNG
  // trên PE này (`Phase != TuChoi`). Rỗng = PE chưa có kế hoạch nào. FE dùng để (a) hiện
  // nút "Tạo thêm cho nhóm khác" và (b) khoá đúng nhóm đã dùng trong ô chọn nhóm —
  // rào cứng 409 vẫn nằm ở BE (`:395-402`), FE chỉ có nhiệm vụ không mời bấm nhầm.
  existingGroups: number[]
}

export interface CreateKhkkInput {
  // [F-2 S161] BE Command = `PeId` (D1 — spec là hợp-đồng 2 lane); `purchaseEvaluationId`
  // KHÔNG bind ⇒ Guid.Empty ⇒ 400 mọi lần Lưu. Tên field ở đây PHẢI là peId.
  peId: string
  approvalWorkflowId: string
  ghiChu?: string | null
  // [K2 S164] Nhóm duyệt N1..N8 (`CreateCommand:337` `int? ApprovalGroup = null`).
  // Bỏ trống ⇒ BE gán nhóm 1. FE LUÔN gửi (ô chọn có default 1) — gửi tường minh để
  // người dùng thấy đúng thứ mình chọn, không phụ thuộc default ngầm của BE.
  approvalGroup?: number | null
}

export interface UpdateKhkkDraftInput {
  approvalWorkflowId?: string | null
  ghiChu?: string | null
  hoSoLink?: string | null
}

export interface UpsertKhkkDossierItemInput {
  // [F-3 S161] BE verify id-path == cmd.ContractSigningPlanId — thiếu trong BODY = 400 vĩnh viễn.
  // Optional ở FORM-STATE: mutation inject `contractSigningPlanId: id` lúc submit (KhkkDetailPage).
  contractSigningPlanId?: string
  id?: string | null
  kind: DossierItemKindValue
  supplierId?: string | null
  name: string
  status: DossierItemStatusValue
  tvgsName?: string | null
  note?: string | null
}

// ===================== W3 — chuyển trạng thái (duyệt 3 trạm) =========================
// 🔴 HỢP-ĐỒNG LITERAL do LEAD chốt (S161 W3). Tên field ở đây = tên field BE bind.
// Đổi 1 chữ ở đây mà không đổi BE = đứt im lặng (bài W2 6-điểm-đứt).
//   submit  = trình duyệt (DangSoanThao | TraLai → ChoDuyet)
//   approve = duyệt cấp hiện tại (OR-of-N; comment ≠ rỗng ⇒ UPSERT LevelOpinion)
//   return  = trả lại (→ TraLai)
//   reject  = từ chối (→ TuChoi)
export const KhkkTransitionAction = {
  Submit: 'submit',
  Approve: 'approve',
  Return: 'return',
  Reject: 'reject',
} as const
export type KhkkTransitionActionValue =
  (typeof KhkkTransitionAction)[keyof typeof KhkkTransitionAction]

export interface KhkkTransitionInput {
  action: KhkkTransitionActionValue
  comment: string | null
  // [F-1 S166] Opt-out level-finalize (khuôn PE S96): chỉ gửi khi action=approve.
  // BE `ContractSigningPlanTransitionBody.ApplyLevelFinalize` là `bool? = null` — absent/true
  // = auto kết-thúc-tại-cấp khi Cấp có cờ; false = người duyệt BỎ tick ⇒ trình tiếp CEO.
  applyLevelFinalize?: boolean
}

// Response 200 — 3 field, ĐÚNG tên hợp-đồng. `phase` là INT (mirror `KhkkPhase`).
export interface KhkkTransitionResult {
  phase: number
  currentWorkflowStepIndex: number | null
  currentApprovalLevelOrder: number | null
}

// ===================== K7 S167 — cầu KHKK → Hợp đồng ================================
// 🔴 HỢP-ĐỒNG LITERAL với lane BE K7 (nguồn `sub-invest-fable-b2-cum3.md §K7.1:29-54`,
// lane BE viết SONG SONG lượt này — lệch 1 chữ = đứt CÂM, bài W2 6-điểm-đứt):
//   POST /contract-signing-plans/{id}/create-contract   policy **`Contracts.Create`**
//        (gotcha #85 — key theo TÀI NGUYÊN SINH RA là Contract, KHÔNG phải `KeHoachKyKet.*`)
//   201 → { contractId, maHopDong }
// `lineIds` là MẢNG vì máy BE gộp-capable (OG-1 "máy rộng"), còn ô chọn hiện gửi ĐÚNG 1
// phần tử (OG-1 "giao diện 1-1") ⇒ mở gộp sau = đổi ô chọn, KHÔNG đụng hợp-đồng này.
export interface CreateContractFromKhkkInput {
  lineIds: string[]
  contractType: number
  approvalWorkflowId: string
  tenHopDong?: string | null
}

export interface CreateContractFromKhkkResult {
  contractId: string
  // BE gen mã NGAY lúc bắc cầu (khuôn bridge PE `:113`), nhưng khai nullable để lỡ nhánh
  // nào chưa gen thì FE hiện câu khác chứ không in "undefined" lên toast.
  maHopDong: string | null
}

export interface PagedResult<T> {
  items: T[]
  total: number
  page: number
  pageSize: number
  totalPages: number
  hasNext: boolean
  hasPrev: boolean
}
