// [W3 KHKK — S161 2026-07-29] Panel duyệt 3 trạm (PMH → CCM → CEO) cho Kế hoạch ký kết HĐ.
// File MIRROR SHA256 identical với fe-admin counterpart.
//
// Khuôn: `components/pe/PeWorkflowPanel.tsx` — GIỮ sơ đồ Bước→Cấp ✓/●/○, banner "đến lượt bạn"
// (`blockedByV2Level` :109-114), 3 nút màu (emerald/amber/red), Dialog + ô ý kiến.
// ĐƠN-GIẢN-HOÁ CÓ CHỦ ĐÍCH (spec W3 §②-3): KHÔNG price-picker, KHÔNG ngân sách, KHÔNG file-khi-duyệt,
// KHÔNG 4 return-mode (W3 = TraLai toàn phần). Chốt giá per-Line là việc BE làm ở finalize
// choke-point, KHÔNG phải việc của panel này.
//
// 🔴 [K3 S164/S165 — SUPERSEDE] Câu cũ ở đây khai "KHÔNG 2 đường kết-thúc-sớm (AllowApproverFinalize /
// CeoApprovalThreshold — anh phán «PHÁ VỠ» S155; W1 đã rào ở Designer type-10)". KHAI ĐÓ ĐÃ HẾT HIỆU LỰC:
// owner ĐẢO phán quyết S155 (@S164 — "a Chương quyết cái gì cần CEO") ⇒ BE **đã port nhánh finalize cho
// KHKK ở K3 cùng wave**, và Designer type-10 đã GỠ rào (`ApprovalWorkflowsV2Page.tsx` — hằng
// `earlyFinalizeLocked` xoá hẳn, 2 ô tick sống lại). Đừng đọc file này thành "BE không hỗ trợ".
// 🔴 [F-1 S166 — SUPERSEDE tiếp] Câu cũ "panel không có control riêng cho đường kết-thúc-sớm" HẾT hiệu lực:
// gate-K3 chấm nó là F-1 MAJOR (BE `?? true` mà 0 UI gửi false ⇒ trạm CEO chỉ đi được bằng admin bỏ cờ
// Designer). Nay panel CÓ ô-tích "Cấp này KẾT THÚC" theo khuôn PE-LIVE S97 = OPT-IN (G-1 reviewer:
// PE `useState(false)` :61 — owner đã ĐẢO opt-out S96 → opt-in S97; nhãn cũ "khuôn S96" trích trúng
// chú-thích chết). Default KHÔNG tick ⇒ gửi false ⇒ trình tiếp; TÍCH ⇒ true ⇒ BE kết thúc tại cấp.
// RATIFIED @S167 2026-08-01 (anh: "Đồng ý. Cứ theo khuôn PE") — default OPT-IN khuôn PE-live-S97 là CHỐT.
//
// 🔴 KHÁC PE Ở CHỖ ĐẮT NHẤT: PE nhận `approvalFlow` đã có `status` Done/Current/Pending do BE precompute.
// KHKK BE trả CÂY THÔ (`ContractSigningPlanFeatures.cs:112-117` + `:105-110`) — KHÔNG có `status`.
// Panel này TỰ SUY trạng thái từ cặp con-trỏ:
//   • `currentWorkflowStepIndex` = INDEX 0-based vào mảng `workflowSteps` (đã sort Order) — KHÔNG phải Order
//   • `currentApprovalLevelOrder` = GIÁ TRỊ `level.order`
// (BE tự khai ngữ nghĩa này ở `ContractSigningPlanFeatures.cs:224-226`; luật so khớp OR-of-N canonical
// `:259-260` = `steps[idx].Levels.Any(l => l.Order == cur && l.ApproverUserId == uid)` — mirror Y NGUYÊN
// bên dưới, dùng `.some()` vì N Cấp CÙNG Order = OR-of-N, chỉ 1 người ký là tiến.)
import { useState } from 'react'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import { Check, MessageSquare, Send, Undo2, Workflow, X } from 'lucide-react'
import { Button } from '@/components/ui/Button'
import { Dialog } from '@/components/ui/Dialog'
import { Label } from '@/components/ui/Label'
import { Textarea } from '@/components/ui/Textarea'
import { api } from '@/lib/api'
import { getErrorMessage } from '@/lib/apiError'
import { cn } from '@/lib/cn'
import { useAuth } from '@/contexts/AuthContext'
import {
  KHKK_PHASE_LABELS, KhkkPhase, KhkkTransitionAction,
  type KhkkDetailDto, type KhkkPhaseValue, type KhkkTransitionActionValue,
  type KhkkTransitionInput, type KhkkTransitionResult, type KhkkWorkflowLevelDto,
} from '@/types/khkk'

type NodeStatus = 'Done' | 'Current' | 'Pending'

function formatDateTime(iso: string): string {
  return new Date(iso).toLocaleString('vi-VN')
}

// Pattern 14 (Tailwind JIT): chuỗi class ĐẦY ĐỦ, KHÔNG nội suy mảnh (`bg-${x}-50` bị purge).
const STATUS_DOT: Record<NodeStatus, string> = {
  Done: 'bg-emerald-500 text-white',
  Current: 'bg-brand-600 text-white',
  Pending: 'bg-slate-200 text-slate-500',
}

const STATUS_BOX: Record<NodeStatus, string> = {
  Done: 'border-emerald-200 bg-emerald-50/40',
  Current: 'border-brand-300 bg-brand-50/50',
  Pending: 'border-slate-200 bg-white',
}

const STATUS_ICON: Record<NodeStatus, string> = {
  Done: '✓',
  Current: '●',
  Pending: '○',
}

export function KhkkWorkflowPanel({
  plan,
  onChanged,
}: {
  plan: KhkkDetailDto
  /** gọi sau khi transition thành công — caller refetch detail/list theo id URL của nó. */
  onChanged?: () => void
}) {
  const qc = useQueryClient()
  const { user } = useAuth()
  const [action, setAction] = useState<KhkkTransitionActionValue | null>(null)
  const [comment, setComment] = useState('')
  // [F-1 S166 · G-1 reviewer] Ô-tích level-finalize theo khuôn PE-LIVE S97 = OPT-IN
  // (`PeWorkflowPanel.tsx:61` useState(false) — owner đảo opt-out S96 → opt-in S97 "cái này option
  // thôi"; đừng trích comment S96 chết ở `:769-771` file đó). Default UNCHECKED = duyệt xong TRÌNH
  // TIẾP cấp sau (fail-mode an toàn: không đọc thì phiếu vẫn lên CEO); TÍCH mới KẾT THÚC tại cấp.
  // Hành vi mặc định trạm CCM đổi so trước-F-1 (BE `?? true` auto-finalize) — RATIFIED @S167 (khuôn PE);
  // lật lại (nếu đổi ý) = đổi 1 chữ false→true + 2 nhãn dưới.
  const [applyLevelFinalize, setApplyLevelFinalize] = useState(false)

  const phase = plan.phase as KhkkPhaseValue
  const steps = plan.workflowSteps ?? []
  const opinions = plan.levelOpinions ?? []

  const isWaiting = phase === KhkkPhase.ChoDuyet
  const isApproved = phase === KhkkPhase.DaDuyet
  const isDraftLike = phase === KhkkPhase.DangSoanThao || phase === KhkkPhase.TraLai

  const curStepIdx = plan.currentWorkflowStepIndex
  const curLevelOrder = plan.currentApprovalLevelOrder

  // Suy trạng thái Bước: chỉ có nghĩa khi phiếu ĐANG chờ duyệt. DaDuyet ⇒ tất cả Done;
  // Nháp/TraLai/TuChoi ⇒ tất cả Pending (quy trình chưa chạy / đã dừng).
  const stepStatus = (idx: number): NodeStatus => {
    if (isApproved) return 'Done'
    if (!isWaiting || curStepIdx == null) return 'Pending'
    if (idx < curStepIdx) return 'Done'
    if (idx === curStepIdx) return 'Current'
    return 'Pending'
  }

  const levelStatus = (idx: number, order: number): NodeStatus => {
    const s = stepStatus(idx)
    if (s !== 'Current' || curLevelOrder == null) return s
    if (order < curLevelOrder) return 'Done'
    if (order === curLevelOrder) return 'Current'
    return 'Pending'
  }

  // 🔴 OR-of-N: mọi Cấp CÙNG `order` trong Bước hiện tại đều là người được duyệt lượt này —
  // 1 người ký là phiếu tiến (mirror BE `:259-260` `.Any(...)`). KHÔNG `.find()` một người.
  const currentLevels: KhkkWorkflowLevelDto[] =
    isWaiting && curStepIdx != null && curStepIdx >= 0 && curStepIdx < steps.length && curLevelOrder != null
      ? steps[curStepIdx].levels.filter(l => l.order === curLevelOrder)
      : []
  const currentStep = isWaiting && curStepIdx != null && curStepIdx >= 0 && curStepIdx < steps.length
    ? steps[curStepIdx]
    : null

  const isAdmin = user?.roles?.includes('Admin') ?? false
  const actorIsCurrentApprover = !!user?.id && currentLevels.some(l => l.approverUserId === user.id)
  // Admin bypass — mirror `PeWorkflowPanel.tsx:110-114` (`actorInV2Level` có `isAdmin ||`).
  const actorInLevel = isAdmin || actorIsCurrentApprover
  const blockedByLevel = isWaiting && !actorInLevel

  // [F-1 S166] Ô-tích opt-out hiện theo cờ của ĐÚNG level BE sẽ chấm — mirror `ResolveActingLevel`
  // (`ContractSigningPlanWorkflowService.cs:455-469`): own-level TRƯỚC (kể cả Admin có slot riêng),
  // Admin không có own ⇒ level ĐẦU nhóm cùng-order. Soi cờ của level KHÁC là hiện ô-tích nói dối.
  const actingLevel = currentLevels.find(l => l.approverUserId === user?.id)
    ?? (isAdmin ? currentLevels[0] : undefined)
  const approverFinalizeEligible = actingLevel?.allowApproverFinalize === true

  // Nút "Gửi duyệt": guard BE là `CreatedBy == actor ∨ DeptManager(cùng phòng) ∨ Admin`
  // (spec W3 §②-5). FE KHÔNG suy được vế DeptManager — `UserInfo` chỉ có {id,email,fullName,roles}
  // (`types/auth.ts:1-6`), không có phòng ban. CỐ Ý **không ẩn** nút theo vai: ẩn sẽ giấu nút với
  // đúng người có quyền, im lặng, không lỗi (bug-class gotcha #44 — đã đốt 1 lần ở PE S155).
  // Rào THẬT nằm ở BE (403 → toast). Chỉ chặn ca chắc-chắn-hỏng: chưa pin quy trình.
  const canSubmit = isDraftLike && !!plan.approvalWorkflowId

  const transition = useMutation({
    mutationFn: async (a: KhkkTransitionActionValue) => {
      // 🔴 BODY theo hợp-đồng LEAD chốt W3 (`action` + `comment`) + [F-1 S166] field thứ 3
      // `applyLevelFinalize` CHỈ đính kèm khi approve: cấp có cờ gửi giá trị ô-tích, cấp thường
      // gửi true = no-op (mirror PE `PeWorkflowPanel.tsx:259`; BE `bool? = null` ⇒ absent = true).
      const body: KhkkTransitionInput = {
        action: a,
        comment: comment.trim() || null,
        ...(a === KhkkTransitionAction.Approve
          ? { applyLevelFinalize: approverFinalizeEligible ? applyLevelFinalize : true }
          : {}),
      }
      const res = await api.post<KhkkTransitionResult>(
        `/contract-signing-plans/${plan.id}/transitions`,
        body,
      )
      return res.data
    },
    onSuccess: (res) => {
      const label = KHKK_PHASE_LABELS[res.phase as KhkkPhaseValue] ?? `Phase ${res.phase}`
      toast.success(`Đã cập nhật — trạng thái: ${label}.`)
      setAction(null)
      setComment('')
      qc.invalidateQueries({ queryKey: ['khkk-detail', plan.id] })
      qc.invalidateQueries({ queryKey: ['khkk-list'] })
      onChanged?.()
    },
    onError: (e) => toast.error(getErrorMessage(e)),
  })

  const dialogTitle =
    action === KhkkTransitionAction.Submit ? '➤ Gửi duyệt kế hoạch ký kết'
      : action === KhkkTransitionAction.Approve ? '✓ Duyệt kế hoạch ký kết'
        : action === KhkkTransitionAction.Return ? '← Trả lại người soạn sửa'
          : '✗ Từ chối kế hoạch ký kết'
  // Trả lại / Từ chối bắt buộc nêu lý do (ghi vào ý kiến cấp duyệt + changelog BE).
  const commentRequired =
    action === KhkkTransitionAction.Return || action === KhkkTransitionAction.Reject
  const confirmDisabled = transition.isPending || (commentRequired && !comment.trim())

  return (
    <section className="card-accent" style={{ ['--accent' as string]: 'var(--color-emerald-500)' }}>
      <header className="flex items-center gap-2 border-b border-slate-100 px-5 py-3">
        <span
          className="icon-chip"
          style={{ height: '1.75rem', width: '1.75rem', ['--chip-bg' as string]: 'var(--color-emerald-50)', ['--chip-fg' as string]: 'var(--color-emerald-600)' }}
          aria-hidden
        >
          <Workflow className="h-4 w-4" />
        </span>
        <h3 className="text-sm font-semibold tracking-tight text-emerald-700">Quy trình duyệt</h3>
        {plan.workflowCode && (
          <span className="font-mono text-[11px] text-slate-500">
            {plan.workflowCode}
            {plan.workflowName && <span className="font-sans"> · {plan.workflowName}</span>}
          </span>
        )}
      </header>

      <div className="space-y-4 p-5">
        {/* Sơ đồ Bước → Cấp. ✓ Done (emerald) / ● Current (brand) / ○ Pending (slate) */}
        {steps.length > 0 ? (
          <ol className="space-y-2">
            {steps.map((step, idx) => {
              const st = stepStatus(idx)
              return (
                <li key={step.id} className={cn('rounded-md border p-2', STATUS_BOX[st])}>
                  <div className="flex items-center gap-2 text-xs font-medium">
                    <span className={cn('flex h-5 w-5 shrink-0 items-center justify-center rounded-full font-bold', STATUS_DOT[st])}>
                      {STATUS_ICON[st]}
                    </span>
                    <span className="text-slate-800">Bước {step.order} — {step.name}</span>
                  </div>
                  {step.levels.length > 0 && (
                    <ul className="ml-7 mt-1.5 space-y-1 border-l-2 border-violet-200 pl-2">
                      {step.levels.map(lv => {
                        const ls = levelStatus(idx, lv.order)
                        const signed = opinions.find(o => o.approvalWorkflowLevelId === lv.id)
                        return (
                          <li key={lv.id} className="text-[11px]">
                            <div className="flex items-start gap-1.5">
                              <span className={cn('mt-0.5 inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[9px] font-bold', STATUS_DOT[ls])}>
                                {STATUS_ICON[ls]}
                              </span>
                              <div className="min-w-0 flex-1">
                                <div className="font-medium text-slate-700">
                                  {lv.name || `Cấp ${lv.order}`}
                                  {ls === 'Current' && <span className="ml-1.5 text-[10px] font-normal text-brand-700">đang chờ</span>}
                                  {ls === 'Done' && <span className="ml-1.5 text-[10px] font-normal text-emerald-600">đã duyệt</span>}
                                </div>
                                <div className="text-slate-500">
                                  {lv.approverFullName ?? '(chưa cấu hình)'}
                                  {signed && (
                                    <span className="ml-1.5 text-[10px] text-emerald-600">
                                      ✓ ký {formatDateTime(signed.signedAt)}
                                    </span>
                                  )}
                                </div>
                              </div>
                            </div>
                          </li>
                        )
                      })}
                    </ul>
                  )}
                </li>
              )
            })}
          </ol>
        ) : (
          <div className="rounded border border-slate-200 bg-slate-50 px-3 py-2 text-[11px] text-slate-600">
            Quy trình duyệt chưa cấu hình Bước/Cấp — liên hệ Admin để dựng quy trình loại
            &ldquo;Kế hoạch ký kết HĐ&rdquo; trước khi trình duyệt.
          </div>
        )}

        {/* Banner "đến lượt bạn" — khuôn PeWorkflowPanel:489-508. Chỉ có nghĩa khi ĐANG chờ duyệt. */}
        {isWaiting && currentStep && (
          <div className={cn(
            'rounded border px-3 py-2 text-[11px]',
            actorInLevel
              ? 'border-emerald-200 bg-emerald-50 text-emerald-800'
              : 'border-amber-300 bg-amber-50 text-amber-800',
          )}>
            <div className="font-medium">
              Đang chờ Bước {currentStep.order} ({currentStep.name}) — Cấp {curLevelOrder}
            </div>
            <div className="mt-0.5">
              Người duyệt: {currentLevels.map(l => l.approverFullName ?? '(chưa rõ)').join(' / ') || '(chưa có)'}
            </div>
            {actorInLevel
              ? <div className="mt-0.5 font-medium">✓ Đến lượt bạn duyệt</div>
              : <div className="mt-0.5">⚠ Không phải lượt bạn — chỉ người trên mới thao tác cấp này</div>}
          </div>
        )}

        {phase === KhkkPhase.TraLai && (
          <div className="rounded border border-orange-300 bg-orange-50 px-3 py-2 text-[11px] text-orange-800">
            ⚠ Kế hoạch bị TRẢ LẠI — sửa nội dung rồi bấm &ldquo;Gửi duyệt&rdquo;, quy trình chạy lại từ Bước 1 · Cấp 1.
          </div>
        )}
        {phase === KhkkPhase.TuChoi && (
          <div className="rounded border border-red-300 bg-red-50 px-3 py-2 text-[11px] text-red-800">
            ✗ Kế hoạch đã bị TỪ CHỐI — không thao tác được nữa. Lập kế hoạch mới nếu cần làm lại.
          </div>
        )}

        {/* Hành động */}
        {(canSubmit || isWaiting) && (
          <div>
            <Label className="text-xs">Hành động:</Label>
            <div className="mt-1 flex flex-wrap gap-1.5">
              {canSubmit && (
                <button
                  type="button"
                  onClick={() => { setComment(''); setAction(KhkkTransitionAction.Submit) }}
                  className="inline-flex items-center gap-1 rounded border border-brand-300 px-2 py-1 text-[11px] font-bold text-brand-700 transition hover:bg-brand-50"
                >
                  <Send className="h-3 w-3" /> Gửi duyệt
                </button>
              )}
              {isDraftLike && !plan.approvalWorkflowId && (
                <span className="rounded border border-dashed border-slate-300 px-2 py-1 text-[11px] text-slate-500">
                  Chưa pin quy trình duyệt — không gửi duyệt được.
                </span>
              )}
              {isWaiting && (
                <>
                  <button
                    type="button"
                    disabled={blockedByLevel}
                    onClick={() => {
                      if (!blockedByLevel) {
                        setComment('')
                        // [F-1 S166 · G-1] reset về default KHÔNG-tick (opt-IN, khuôn PE S97) mỗi
                        // lần mở dialog — lựa chọn tích là per-lượt-duyệt, không dính lần trước.
                        setApplyLevelFinalize(false)
                        setAction(KhkkTransitionAction.Approve)
                      }
                    }}
                    title={blockedByLevel ? 'Cấp hiện tại chỉ người được phân công mới thao tác được.' : 'Duyệt cấp hiện tại'}
                    className={cn(
                      'inline-flex items-center gap-1 rounded border px-2 py-1 text-[11px] font-bold transition',
                      blockedByLevel
                        ? 'cursor-not-allowed border-slate-200 bg-slate-50 text-slate-400'
                        : 'border-emerald-300 text-emerald-700 hover:bg-emerald-50',
                    )}
                  >
                    <Check className="h-3 w-3" /> Duyệt
                  </button>
                  <button
                    type="button"
                    disabled={blockedByLevel}
                    onClick={() => { if (!blockedByLevel) { setComment(''); setAction(KhkkTransitionAction.Return) } }}
                    title={blockedByLevel ? 'Cấp hiện tại chỉ người được phân công mới thao tác được.' : 'Trả lại người soạn sửa'}
                    className={cn(
                      'inline-flex items-center gap-1 rounded border px-2 py-1 text-[11px] font-bold transition',
                      blockedByLevel
                        ? 'cursor-not-allowed border-slate-200 bg-slate-50 text-slate-400'
                        : 'border-amber-300 text-amber-700 hover:bg-amber-50',
                    )}
                  >
                    <Undo2 className="h-3 w-3" /> Trả lại
                  </button>
                  <button
                    type="button"
                    disabled={blockedByLevel}
                    onClick={() => { if (!blockedByLevel) { setComment(''); setAction(KhkkTransitionAction.Reject) } }}
                    title={blockedByLevel ? 'Cấp hiện tại chỉ người được phân công mới thao tác được.' : 'Từ chối kế hoạch (khoá phiếu)'}
                    className={cn(
                      'inline-flex items-center gap-1 rounded border px-2 py-1 text-[11px] font-bold transition',
                      blockedByLevel
                        ? 'cursor-not-allowed border-slate-200 bg-slate-50 text-slate-400'
                        : 'border-red-300 text-red-700 hover:bg-red-50',
                    )}
                  >
                    <X className="h-3 w-3" /> Từ chối
                  </button>
                </>
              )}
            </div>
          </div>
        )}

        {/* Ý kiến cấp duyệt (UPSERT 1 row/Cấp — BE ghi khi người duyệt bấm Duyệt kèm ý kiến). */}
        {opinions.length > 0 && (
          <div>
            <div className="flex items-center gap-1.5 text-xs font-semibold text-slate-700">
              <MessageSquare className="h-3.5 w-3.5 text-violet-500" />
              Ý kiến cấp duyệt
              <span className="rounded-full bg-slate-100 px-1.5 py-0.5 text-[10px] font-semibold tabular-nums text-slate-500">
                {opinions.length}
              </span>
            </div>
            <ul className="mt-1.5 space-y-1.5">
              {opinions.map(o => (
                <li key={o.id} className="rounded border border-slate-200 bg-slate-50/60 px-2.5 py-1.5 text-[11px]">
                  <div className="flex flex-wrap items-center gap-x-1.5 text-slate-700">
                    <span className="font-medium">{o.signedByFullName}</span>
                    <span className="text-slate-400">·</span>
                    <span>
                      {o.stepName ? `Bước ${o.stepOrder} — ${o.stepName}` : 'Cấp duyệt'}
                      {o.levelOrder != null && ` · Cấp ${o.levelOrder}`}
                    </span>
                    <span className="text-slate-400">·</span>
                    <span className="text-slate-500">{formatDateTime(o.signedAt)}</span>
                    {/* Người ký ≠ người được phân công ⇒ Admin duyệt thay (mirror banner PE S17). */}
                    {o.approverUserId && o.approverUserId !== o.signedByUserId && (
                      <span className="rounded bg-amber-100 px-1.5 py-0.5 text-[9px] font-semibold text-amber-800">
                        duyệt thay
                      </span>
                    )}
                  </div>
                  <div className="mt-0.5 whitespace-pre-wrap text-slate-600">
                    {o.comment?.trim() || '(duyệt — không ý kiến)'}
                  </div>
                </li>
              ))}
            </ul>
          </div>
        )}
      </div>

      {action !== null && (
        <Dialog
          open
          onClose={() => setAction(null)}
          title={dialogTitle}
          footer={<>
            <Button variant="outline" onClick={() => setAction(null)}>Huỷ</Button>
            <Button onClick={() => transition.mutate(action)} disabled={confirmDisabled}>
              {transition.isPending ? 'Đang gửi...' : 'Xác nhận'}
            </Button>
          </>}
        >
          {action === KhkkTransitionAction.Submit && (
            <div className="mb-3 rounded border border-brand-200 bg-brand-50 px-3 py-2 text-[11px] text-brand-800">
              Kế hoạch chuyển sang &ldquo;Chờ duyệt&rdquo; và trình lên Bước 1 · Cấp 1 của quy trình
              {plan.workflowName ? ` "${plan.workflowName}"` : ''}. Sau khi trình, nội dung nháp không sửa được nữa.
            </div>
          )}
          {action === KhkkTransitionAction.Return && (
            <div className="mb-3 rounded border border-amber-200 bg-amber-50 px-3 py-2 text-[11px] text-amber-800">
              Kế hoạch về trạng thái &ldquo;Trả lại&rdquo;. Người soạn sửa xong gửi lại thì quy trình chạy
              từ Bước 1 · Cấp 1.
            </div>
          )}
          {action === KhkkTransitionAction.Reject && (
            <div className="mb-3 rounded border border-red-200 bg-red-50 px-3 py-2 text-[11px] text-red-800">
              ⚠ Kế hoạch bị khoá hoàn toàn (không sửa / không duyệt tiếp). Người soạn phải lập kế hoạch mới.
            </div>
          )}
          {/* [F-1 S166 · G-1/G-5 reviewer] Cấp cấu hình KẾT THÚC (AllowApproverFinalize) = ô-tích
              OPT-IN, khuôn PE-LIVE S97 (`PeWorkflowPanel.tsx:61` useState(false) + JSX `:772-791`;
              comment "opt-out S96" ngay trên khối JSX đó là chú-thích CHẾT — G-1 bắt đúng bẫy này):
              default KHÔNG tick = duyệt xong TRÌNH TIẾP cấp sau; TÍCH = gửi applyLevelFinalize=true
              ⇒ BE kết thúc tại cấp. Không viết "(CEO)" — cấp-sau là gì tuỳ cấu hình quy trình (G-5).
              KHÁC PE: không nhắc "chọn giá chốt" — KHKK chốt giá per-dòng do BE tự làm ở finalize
              choke-point (`ApplyApprovedValuesOnFinalize`), panel không có price-picker. */}
          {action === KhkkTransitionAction.Approve && approverFinalizeEligible && (
            <div className="mb-3 rounded border border-emerald-300 bg-emerald-50 px-3 py-2 text-[12px] text-emerald-800">
              <label className="flex cursor-pointer items-start gap-2">
                <input
                  type="checkbox"
                  className="mt-0.5"
                  checked={applyLevelFinalize}
                  onChange={e => setApplyLevelFinalize(e.target.checked)}
                />
                <span>
                  <span className="font-medium">Cấp này KẾT THÚC quy trình</span>
                  <span className="mt-0.5 block text-[11px] text-emerald-700/80">
                    {applyLevelFinalize
                      ? 'Đã tích — duyệt xong là kế hoạch "Đã duyệt", KẾT THÚC tại cấp này, KHÔNG trình tiếp cấp sau.'
                      : 'Mặc định: duyệt xong kế hoạch TRÌNH TIẾP lên cấp sau của quy trình. TÍCH vào nếu muốn KẾT THÚC ngay tại cấp này.'}
                  </span>
                </span>
              </label>
            </div>
          )}
          <Label>
            Ý kiến{commentRequired ? <span className="text-red-500"> *</span> : ' (tuỳ chọn)'}
          </Label>
          <Textarea
            value={comment}
            onChange={e => setComment(e.target.value)}
            rows={3}
            maxLength={2000}
            placeholder={commentRequired ? 'Nêu lý do trả lại / từ chối...' : 'Ý kiến của bạn (ghi vào phiếu)...'}
          />
          {action === KhkkTransitionAction.Approve && (
            <p className="mt-1 text-[11px] text-slate-500">
              Ý kiến sẽ được ghi vào mục &ldquo;Ý kiến cấp duyệt&rdquo; của kế hoạch (1 ô/Cấp — duyệt lại
              thì ghi đè ô cũ).
            </p>
          )}
        </Dialog>
      )}
    </section>
  )
}
