// Reusable detail body — used by full-page ContractDetailPage AND embedded
// in MyContractsPage 3-panel layout (Panel 2). Renders header (title + phase
// + actions) + Info + Comments + Attachments + transition Dialog. Workflow +
// approval history live separately in WorkflowHistoryPanel (Panel 3).
// File MIRROR SHA256 identical với fe-admin counterpart.
import { useState, type FormEvent } from 'react'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { Link } from 'react-router-dom'
import { ArrowLeft, CheckCircle2, MessageSquare, Trash2, XCircle, ListChecks, GitBranch } from 'lucide-react'
import { toast } from 'sonner'
import { PhaseBadge } from '@/components/PhaseBadge'
import { SlaTimer } from '@/components/SlaTimer'
import { ContractAttachmentsSection } from '@/components/ContractAttachmentsSection'
import { ContractDetailsTab } from '@/components/contracts/ContractDetailsTab'
// [WQ3b S190 · YC-030 Q5] 🧊 Import `ContractWorkflowPanel` (W6/S187) ĐÃ GỠ khỏi file này —
// máy duyệt dời sang PANEL-3 của từng host, xem khối lineage ở `:isV2`.
import { Button } from '@/components/ui/Button'
import { Select } from '@/components/ui/Select'
import { Textarea } from '@/components/ui/Textarea'
import { Dialog } from '@/components/ui/Dialog'
import { useAuth } from '@/contexts/AuthContext'
import { api } from '@/lib/api'
import { getErrorMessage } from '@/lib/apiError'
import {
  ApprovalDecision,
  ContractPhase,
  ContractPhaseLabel,
  type ContractDetail,
} from '@/types/contracts'
import { ContractTypeLabel } from '@/types/forms'
// [W5 S187] Nhãn 8 nhóm duyệt KHKK — IMPORT, KHÔNG chép chuỗi. Map này là single-source
// (`types/khkk.ts:140-149`, đã đối chiếu từng ký tự với nhãn BE seed @K4a); đẻ map thứ 2 ở
// đây là phá đúng cái acceptance nó phục vụ.
import { KHKK_APPROVAL_GROUP_LABELS } from '@/types/khkk'

const fmt = (s: string) => new Date(s).toLocaleString('vi-VN')
const fmtMoney = (v: number) => v.toLocaleString('vi-VN') + ' VND'

export function ContractDetailContent({
  contract: c,
  onBack,
  onDeleted,
}: {
  contract: ContractDetail
  /** Optional back handler — shown as arrow button next to title. Pass `navigate(-1)` for fullpage; omit for embedded panel. */
  onBack?: () => void
  /**
   * [W5c S190] Gọi SAU khi xoá HĐ ở thanh nút đáy — host bỏ chọn / quay về danh sách.
   * KHÔNG truyền ⇒ chỉ có 3 `invalidateQueries` chạy: danh sách tự rụng dòng, còn màn chi
   * tiết đang mở refetch ra 404 và host rơi về nhánh "không tìm thấy / chưa chọn HĐ" của nó.
   * (Tính đến wave này chưa host nào truyền — xem `sub-b6-w5c-fe.md`.)
   */
  onDeleted?: () => void
}) {
  const qc = useQueryClient()
  const { user: currentUser } = useAuth()
  const [actionOpen, setActionOpen] = useState(false)
  const [targetPhase, setTargetPhase] = useState<number>(0)
  const [decision, setDecision] = useState<number>(ApprovalDecision.Approve)
  const [comment, setComment] = useState('')
  const [commentInput, setCommentInput] = useState('')

  const transition = useMutation({
    mutationFn: async () => {
      await api.post(`/contracts/${c.id}/transitions`, { targetPhase, decision, comment: comment || null })
    },
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['contract', c.id] })
      qc.invalidateQueries({ queryKey: ['my-contracts'] })
      qc.invalidateQueries({ queryKey: ['inbox'] })
      toast.success('Đã chuyển phase')
      setActionOpen(false)
      setComment('')
    },
    onError: err => toast.error(getErrorMessage(err)),
  })

  const addComment = useMutation({
    mutationFn: async (content: string) => {
      await api.post(`/contracts/${c.id}/comments`, { content })
    },
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['contract', c.id] })
      setCommentInput('')
      toast.success('Đã gửi')
    },
    onError: err => toast.error(getErrorMessage(err)),
  })

  // ===== [W5c S190 · YC-029] XOÁ HỢP ĐỒNG ================================================
  // Đường xoá MỀM (BE `ContractFeatures.cs` khối DELETE, W5b): HĐ rời danh sách thường chứ
  // không mất khỏi DB. Mọi rào ở đây là BẢN SAO HIỂN THỊ của guard BE, KHÔNG thay nó — chỗ
  // chặn thật nằm trong handler (`ContractsController.cs` DELETE còn `[Authorize]` trần vì
  // quyền per-action là W8, owner đã HOÃN).
  const deleteContract = useMutation({
    // `reason` đi QUERY-STRING vì verb DELETE không mang body — đúng hình endpoint W5b
    // (`[FromQuery] string? reason`). Màn này CHƯA thu lý do: khuôn KHKK
    // (`KhkkDetailContent.tsx:1090`) cũng chỉ `window.confirm`, và tự đẻ `window.prompt` ở
    // đây là quyết-định UX chưa ai chốt. Gọi không truyền ⇒ axios bỏ hẳn key ⇒ request y hệt
    // `DELETE /contracts/{id}`; chỗ cắm để sẵn cho lúc owner chốt có hỏi lý do hay không.
    mutationFn: async (reason?: string) =>
      api.delete(`/contracts/${c.id}`, { params: reason?.trim() ? { reason: reason.trim() } : undefined }),
    onSuccess: () => {
      // Cùng bộ key với `transition` ở trên (:57-61) — HĐ vừa xoá phải rụng khỏi CẢ danh sách
      // của tôi LẪN hộp chờ duyệt, không riêng màn đang đứng.
      qc.invalidateQueries({ queryKey: ['contract', c.id] })
      qc.invalidateQueries({ queryKey: ['my-contracts'] })
      qc.invalidateQueries({ queryKey: ['inbox'] })
      toast.success('Đã xóa hợp đồng.')
      onDeleted?.()
    },
    onError: err => toast.error(getErrorMessage(err)),
  })

  // Rào HIỂN THỊ mirror guard BE — 2 vế:
  //   • phase ∈ allow-list `< DangInKy(5)` ∪ {TraLai(98), TuChoi(99)}. ChoDuyet(10) KHÔNG có
  //     kể cả với người soạn (đang chờ người khác duyệt); DaPhatHanh(9) đã sinh mã ⇒ chặn mọi
  //     đường. Viết `<` chứ không liệt 1/2/3/4 vì allow-list HĐ gồm cả phase legacy.
  //   • người soạn HOẶC Admin. `isDrafter` theo khuôn null-safe `PeDetailTabs.tsx:141`:
  //     `currentUser?.id != null` phải ĐỨNG TRƯỚC vì `drafterUserId` là `string | null`
  //     (`types/contracts.ts:154`) — thiếu vế đó thì `null === null` cho HĐ vô chủ hiện nút.
  const isAdmin = currentUser?.roles?.includes('Admin') ?? false
  const isDrafter = currentUser?.id != null && c.drafterUserId === currentUser.id
  const canDelete =
    (c.phase < ContractPhase.DangInKy || c.phase === ContractPhase.TraLai || c.phase === ContractPhase.TuChoi)
    && (isDrafter || isAdmin)

  const availableTargets = c.workflow?.nextPhases ?? []

  // ===== [W6 S187 · YC-023 GĐ3] DUAL-RENDER V2-trạm ⟂ V1-legacy ==========================
  // 🔴 `approvalWorkflowId != null` là ĐÚNG cờ phân nhánh — cùng cờ mà BE dùng để chọn đường
  // duyệt (`ContractWorkflowService.cs:111` `if (contract.ApprovalWorkflowId is Guid awId)`)
  // VÀ cùng cờ mục "Ý kiến cấp duyệt (Quy trình V2)" bên dưới đã dùng từ S29. Một cờ, ba nơi
  // đọc, không đẻ khái niệm "HĐ mới" thứ hai.
  //   • V2 ⇒ máy duyệt V2-trạm (sơ đồ Bước→Cấp + banner lượt-ai + 2 nút Duyệt/Trả lại, có
  //     gating theo Cấp đang chờ) — 🔴 [WQ3b S190 · YC-030 Q5] KHÔNG CÒN render trong file này.
  //   • V1 legacy (không pin — 7 HĐ prod chạy nhánh này, `ContractWorkflowService.cs:110`)
  //     ⇒ GIỮ NGUYÊN 2 nút "Yêu cầu sửa"/"Duyệt → tiếp" ở header + Dialog chọn phase.
  // 2 khối là THAY THẾ nhau, không chồng: để cả hai thì cùng một HĐ V2 có 2 đường bấm duyệt
  // (đường header không nói được đang ở Bước/Cấp nào, cũng không gating theo người) — mâu
  // thuẫn hiển thị chứ không phải tiện thêm. `isV2` Ở LẠI vì nửa V1 (`!isV2` ở header) vẫn đọc.
  //
  // ===== [WQ3b S190 · YC-030 Q5] MÁY DUYỆT DỜI VỀ PANEL-3 (khuôn KHKK) ====================
  // 🧊 W6/S187 đặt `ContractWorkflowPanel` ngay TRONG file này (nhánh `isV2`, chỗ khối JSX đã
  // gỡ bên dưới) = panel 2 của các host 3-panel. FLAG WQ1 (`MyContractsPage.tsx:18-23`) chỉ ra
  // hệ quả: panel 3 muốn mang máy duyệt như `KhkkListPage` thì MỘT HĐ có HAI bộ nút Duyệt/Trả
  // lại — đúng thứ chính khối trên cấm. Owner chốt YC-030 Q5 "cấu trúc duyệt như KHKK" ⇒ máy
  // duyệt ra khỏi thân chi tiết, mỗi HOST tự render ở panel cạnh (`MyContractsPage` ·
  // `ContractDetailPage` ×2 · `ContractsListPage` fe-admin · `InboxPage`), CÙNG điều kiện
  // `approvalWorkflowId != null` đang tính ở dưới. Host nào quên render thì HĐ V2 ở host đó
  // KHÔNG có đường duyệt — đây là chỗ dễ hụt nhất của lượt dời này, đã liệt đủ 5 host.
  const isV2 = c.approvalWorkflowId != null

  // ===== [W5 S187 · YC-023 GĐ3] NGUỒN GỐC KHKK (GĐ2) =====================================
  // 🔴 Điều kiện render là `!= null` (LOOSE — bắt cả `undefined`) CÓ CHỦ ĐÍCH: `types/contracts.ts:174-182`
  // khai 2 nghĩa KHÁC NHAU — `undefined` = payload/cache TanStack CHƯA có W2; `null` = BE nói
  // "HĐ này không có nguồn KHKK". Cả 2 đều KHÔNG có gì để vẽ, nhưng KHÔNG được suy `undefined`
  // thành "HĐ tạo tay" ở bất kỳ chỗ nào khác.
  // Nguồn dữ liệu: BE reverse-join `ContractSigningPlanLines WHERE ContractId = id`
  // (`ContractFeatures.cs:720-748`) — `Contract` KHÔNG có con-trỏ ngược sang kế hoạch.
  const src = c.source
  const srcGroup = src?.approvalGroup ?? null
  // Nhãn nhóm: tra map single-source. Truthy-check theo đúng khuôn `khkkGroupMenuLabel`
  // (`types/khkk.ts:159-162`) vì `Record<number,string>` trả `string` cho MỌI số — nhóm lạ
  // (ngoài 1..8, vd dữ liệu SQL thô) phải hiện "chưa có trong danh mục" thay vì ô trống CÂM.
  const srcGroupLabel = srcGroup != null ? KHKK_APPROVAL_GROUP_LABELS[srcGroup] : undefined

  function openAction(decisionType: number) {
    const targets = c.workflow?.nextPhases ?? []
    const defaultTarget = decisionType === ApprovalDecision.Reject
      ? targets.find(t => t === ContractPhase.DangSoanThao) ?? targets[0]
      : targets[0]
    setTargetPhase(defaultTarget)
    setDecision(decisionType)
    setActionOpen(true)
  }

  return (
    <div className="space-y-4">
      {/* Header — sticky inside scroll container so actions luôn visible */}
      <div className="sticky top-0 z-10 -mx-5 -mt-5 border-b border-slate-200 bg-white px-5 pt-5 pb-3 md:-mx-6 md:-mt-6 md:px-6 md:pt-6">
        <div className="flex flex-wrap items-start justify-between gap-3">
          <div className="min-w-0 flex-1">
            <div className="flex items-center gap-2">
              {onBack && (
                <button onClick={onBack} className="text-slate-400 hover:text-slate-700" aria-label="Quay lại">
                  <ArrowLeft className="h-5 w-5" />
                </button>
              )}
              <h1 className="truncate text-[18px] font-semibold tracking-tight text-slate-900">
                {c.tenHopDong ?? 'HĐ chưa đặt tên'}
              </h1>
            </div>
            <div className="mt-1 flex items-center gap-3 text-xs text-slate-500">
              <span className="font-mono">{c.maHopDong ?? '(chưa có mã)'}</span>
              <PhaseBadge phase={c.phase} />
            </div>
          </div>
          {/* [W6 S187 · sửa WQ3b S190] `!isV2` = nửa V1 của dual-render. HĐ pin quy trình V2
              thao tác duyệt ở máy duyệt V2-trạm tại PANEL-3 của host (đúng Bước/Cấp + đúng
              người), không ở header này. */}
          {!isV2 && availableTargets.length > 0 && (
            <div className="flex shrink-0 gap-2">
              <Button variant="outline" onClick={() => openAction(ApprovalDecision.Reject)}>
                <XCircle className="h-4 w-4" />
                Yêu cầu sửa
              </Button>
              <Button onClick={() => openAction(ApprovalDecision.Approve)}>
                <CheckCircle2 className="h-4 w-4" />
                Duyệt → tiếp
              </Button>
            </div>
          )}
        </div>
      </div>

      {/* Tổng quan content — luôn hiển thị, không tabs */}
      <section className="rounded-lg border border-slate-200 bg-white p-5">
        <h2 className="mb-3 text-sm font-semibold text-slate-700">Thông tin HĐ</h2>
        <dl className="grid grid-cols-2 gap-3 text-sm">
          <div><dt className="text-slate-500">Loại</dt><dd>{ContractTypeLabel[c.type] ?? '—'}</dd></div>
          <div><dt className="text-slate-500">Giá trị</dt><dd>{fmtMoney(c.giaTri)}</dd></div>
          <div><dt className="text-slate-500">NCC</dt><dd>{c.supplierName}</dd></div>
          <div><dt className="text-slate-500">Dự án</dt><dd>{c.projectName}</dd></div>
          <div><dt className="text-slate-500">Người soạn</dt><dd>{c.drafterName ?? '—'}</dd></div>
          <div className="col-span-2">
            <dt className="text-slate-500 mb-1">SLA</dt>
            <dd><SlaTimer deadline={c.slaDeadline} createdAt={c.createdAt} variant="full" /></dd>
          </div>
        </dl>
        {c.noiDung && (
          <div className="mt-3">
            <dt className="text-sm text-slate-500">Nội dung</dt>
            <dd className="mt-1 whitespace-pre-wrap text-sm text-slate-700">{c.noiDung}</dd>
          </div>
        )}
      </section>

      {/* [W5 S187 · YC-023 GĐ3] Card "Nguồn gốc Kế hoạch ký kết" — đứng NGAY SAU khối thông
          tin chính: người mở HĐ cần biết nó đẻ ra từ đâu trước khi đọc góp ý / chi tiết.
          Tông VIOLET = GĐ2 (KHKK) theo bảng màu 4 giai đoạn `PipelineStageFolders.tsx:41-46`;
          link sang Phiếu Duyệt NCC dùng tông BRAND = GĐ1 (PE).
          ⚠️ Chỉ dùng stop violet CÓ THẬT trong `index.css` `@theme` (50/100/500/600/700) —
          violet-300/800 rơi về bảng Tailwind mặc định, lệch hệ màu (đã thấy ở
          `KhkkDetailContent.tsx:477`, pre-existing, không sửa ở wave này).
          Vỏ `<section className="rounded-lg border … p-5">` + `<h2 className="mb-3 …">` bám
          ĐÚNG khuôn các khối cùng trang — 2 app đều KHÔNG có shadcn `Card`. */}
      {src != null && (
        <section className="rounded-lg border border-violet-100 bg-violet-50/60 p-5">
          <h2 className="mb-3 flex items-center gap-2 text-sm font-semibold text-violet-700">
            <GitBranch className="h-4 w-4" />
            Nguồn gốc Kế hoạch ký kết
          </h2>
          <dl className="grid grid-cols-2 gap-3 text-sm">
            <div className="col-span-2">
              <dt className="text-slate-500">Mã kế hoạch</dt>
              <dd className="mt-1 flex flex-wrap items-center gap-2">
                {/* 🔴 CHỈ link khi phiếu cha còn đọc được. `maKeHoach === null` ⇔ phiếu đã xoá
                    mềm (BE `ContractFeatures.cs:738-740` lấy mã qua query CÓ global filter), mà
                    màn `/khkk/:id` đọc qua `GetContractSigningPlanQuery`
                    (`ContractSigningPlanFeatures.cs:957-962`) cũng KHÔNG `IgnoreQueryFilters`
                    ⇒ 404. Link tới đó = ngõ cụt. Trạng thái này nói bằng CHỮ NHÌN THẤY ĐƯỢC,
                    không giấu sau tooltip. */}
                {src.maKeHoach != null ? (
                  <Link
                    // `?group=` KHÔNG phải param chết: `KhkkDetailPage.tsx:50-52` (cả 2 app) đọc
                    // và validate bằng REGEX CHUỖI `/^[1-8]$/` rồi dựng đường "quay lại danh sách"
                    // `/khkk/list?group=n` ⇒ giữ đúng chỗ đứng + sidebar sáng đúng leaf nhóm.
                    to={`/khkk/${src.planId}${srcGroup != null ? `?group=${srcGroup}` : ''}`}
                    className="font-mono font-medium text-violet-600 underline underline-offset-2 hover:text-violet-700"
                  >
                    {src.maKeHoach}
                  </Link>
                ) : (
                  <>
                    <span className="font-mono text-slate-500">(phiếu đã xoá)</span>
                    <span className="text-[11px] text-slate-500">— không mở được phiếu gốc</span>
                  </>
                )}
                {srcGroup != null && (
                  <span className="rounded bg-violet-100 px-2 py-0.5 text-[11px] font-medium text-violet-700">
                    Nhóm N{srcGroup} · {srcGroupLabel ? srcGroupLabel : 'chưa có trong danh mục'}
                  </span>
                )}
              </dd>
            </div>
            <div className="col-span-2">
              <dt className="text-slate-500">Hạng mục đưa vào HĐ ({src.tenHangMucs.length})</dt>
              <dd className="mt-1">
                {src.tenHangMucs.length === 0 ? (
                  // BE dựng `Source` chỉ khi có ≥1 dòng nối ⇒ nhánh này gần như bất khả; giữ chữ
                  // trung tính để rỗng-vì-dữ-liệu không trông giống lỗi tải.
                  <span className="text-slate-400">(không có hạng mục nào)</span>
                ) : (
                  <ul className="flex flex-wrap gap-1.5">
                    {src.tenHangMucs.map((ten, i) => (
                      <li
                        key={`${i}-${ten}`}
                        className="rounded border border-violet-100 bg-white px-2 py-0.5 text-[12px] text-slate-700"
                      >
                        {ten}
                      </li>
                    ))}
                  </ul>
                )}
              </dd>
            </div>
            <div>
              <dt className="text-slate-500">Σ giá duyệt chốt</dt>
              {/* Dùng ĐÚNG formatter của file (`fmtMoney`) — không đẻ khuôn tiền thứ 2. */}
              <dd className="mt-0.5 font-medium text-slate-900">
                {src.approvedAmountTotal != null ? fmtMoney(src.approvedAmountTotal) : '—'}
              </dd>
            </div>
            <div>
              <dt className="text-slate-500">Phiếu Duyệt NCC gốc</dt>
              <dd className="mt-0.5">
                {src.purchaseEvaluationId ? (
                  <Link
                    to={`/purchase-evaluations/${src.purchaseEvaluationId}`}
                    className="font-medium text-brand-600 underline underline-offset-2 hover:text-brand-700"
                  >
                    Mở phiếu Duyệt NCC →
                  </Link>
                ) : (
                  <span className="text-slate-400">—</span>
                )}
              </dd>
            </div>
          </dl>
        </section>
      )}

      {/* [WQ3b S190 · YC-030 Q5] Ở ĐÂY TRƯỚC LÀ máy duyệt V2-trạm (W6/S187) — đã dời sang
          panel-3 của từng host theo khuôn KHKK; lý do + danh sách host xem khối `isV2` ở trên.
          Chỗ trống này CỐ Ý không lấp bằng khối khác: thứ tự đọc còn lại (thông tin → nguồn
          KHKK → góp ý → file → chi tiết) là thứ tự cũ, không xáo thêm trong cùng một lượt. */}

      <section className="rounded-lg border border-slate-200 bg-white p-5">
        <h2 className="mb-3 flex items-center gap-2 text-sm font-semibold text-slate-700">
          <MessageSquare className="h-4 w-4" />
          Góp ý ({c.comments.length})
        </h2>
        <div className="space-y-3">
          {c.comments.length === 0 && <div className="text-sm text-slate-400">Chưa có góp ý.</div>}
          {c.comments.map(cm => (
            <div key={cm.id} className="rounded-md border border-slate-100 p-3">
              <div className="flex items-center justify-between text-xs text-slate-500">
                <span className="font-medium text-slate-700">{cm.userName}</span>
                <span>{fmt(cm.createdAt)} · {ContractPhaseLabel[cm.phase]}</span>
              </div>
              <div className="mt-1 whitespace-pre-wrap text-sm text-slate-700">{cm.content}</div>
            </div>
          ))}
        </div>
        <form
          className="mt-4 flex gap-2"
          onSubmit={(e: FormEvent) => {
            e.preventDefault()
            if (!commentInput.trim()) return
            addComment.mutate(commentInput.trim())
          }}
        >
          <Textarea rows={2} placeholder="Thêm góp ý…" value={commentInput} onChange={e => setCommentInput(e.target.value)} />
          <Button type="submit" disabled={addComment.isPending || !commentInput.trim()}>
            Gửi
          </Button>
        </form>
      </section>

      <ContractAttachmentsSection contractId={c.id} attachments={c.attachments} />

      {/* Chi tiết HĐ full-width — Lịch sử điều chỉnh đã move sang Panel 3 */}
      <section className="rounded-lg border border-slate-200 bg-white p-5">
        <h2 className="mb-3 flex items-center gap-2 text-sm font-semibold text-slate-700">
          <ListChecks className="h-4 w-4" />
          Chi tiết ({ContractTypeLabel[c.type] ?? '—'})
        </h2>
        <ContractDetailsTab contract={c} />
      </section>

      {/* [Plan B S29 2026-05-22 Chunk E3] Section 5 — Ý kiến cấp duyệt V2 dynamic.
          Mirror PE LevelOpinionsSectionV2 pattern. Chỉ render khi V2 pin
          (approvalWorkflowId set). V1 legacy contract KHÔNG hiển thị. */}
      {c.approvalWorkflowId && (
        <section className="rounded-lg border border-emerald-200 bg-emerald-50/40 p-5">
          <h2 className="mb-3 flex items-center gap-2 text-sm font-semibold text-emerald-800">
            <ListChecks className="h-4 w-4" />
            Ý kiến cấp duyệt (Quy trình V2)
          </h2>
          {(c.levelOpinions?.length ?? 0) === 0 ? (
            <p className="text-sm text-slate-500">Chưa có ý kiến — workflow vừa bắt đầu hoặc chưa có ai duyệt.</p>
          ) : (
            <ul className="space-y-3">
              {c.levelOpinions!.map(o => {
                const adminProxy = o.signedByUserId !== o.approverUserId
                return (
                  <li key={o.id} className="rounded-md border border-emerald-200 bg-white p-3">
                    <div className="mb-1 flex items-center justify-between gap-2 text-xs">
                      <span className="font-medium text-emerald-900">
                        Bước {o.stepOrder} {o.stepName ? `(${o.stepName})` : ''} — Cấp {o.levelOrder}
                        {o.levelName ? ` (${o.levelName})` : ''}
                      </span>
                      <span className="text-slate-500">{new Date(o.signedAt).toLocaleString('vi-VN')}</span>
                    </div>
                    <p className="mb-1 text-sm text-slate-800">{o.comment}</p>
                    <div className="flex flex-wrap items-center gap-2 text-xs text-slate-600">
                      <span>NV duyệt: <strong>{o.approverFullName ?? o.approverUserId.slice(0, 8)}</strong></span>
                      {adminProxy && (
                        <span className="rounded bg-amber-100 px-2 py-0.5 text-amber-800">
                          ⚡ Admin duyệt thay ({o.signedByFullName ?? o.signedByUserId.slice(0, 8)})
                        </span>
                      )}
                    </div>
                  </li>
                )
              })}
            </ul>
          )}
        </section>
      )}

      <Dialog
        open={actionOpen}
        onClose={() => setActionOpen(false)}
        title={decision === ApprovalDecision.Reject ? 'Yêu cầu sửa' : 'Chuyển phase tiếp'}
        footer={
          <>
            <Button variant="outline" onClick={() => setActionOpen(false)}>Hủy</Button>
            <Button onClick={() => transition.mutate()} disabled={transition.isPending || !targetPhase}>
              {transition.isPending ? 'Đang xử lý…' : 'Xác nhận'}
            </Button>
          </>
        }
      >
        <div className="space-y-4">
          <div className="space-y-1.5">
            <label className="text-sm font-medium text-slate-700">Chuyển đến phase</label>
            <Select value={targetPhase} onChange={e => setTargetPhase(Number(e.target.value))}>
              {availableTargets.map(p => (
                <option key={p} value={p}>{ContractPhaseLabel[p]}</option>
              ))}
            </Select>
          </div>
          <div className="space-y-1.5">
            <label className="text-sm font-medium text-slate-700">Ghi chú (optional)</label>
            <Textarea rows={3} value={comment} onChange={e => setComment(e.target.value)} />
          </div>
        </div>
      </Dialog>

      {/* [W5c S190 · YC-029] THANH NÚT ĐÁY — khuôn `KhkkDetailContent.tsx:1076-1097`
          (🔴 KHÔNG lấy `KhkkWorkflowPanel`: nhánh xoá trong đó là code chết từ S175).
          🔴 `sticky bottom-0`: trang HĐ dài (thông tin + nguồn KHKK + góp ý + file + chi tiết
          + ý kiến duyệt) — nút đứng cuối luồng thì phải cuộn hết mới với tới.
          🔸 Hỏi bằng `window.confirm` chứ KHÔNG mở hộp thoại `Dialog` thứ hai: hộp thoại duy
          nhất của file này đang giữ ĐÚNG MỘT nghĩa — chuyển phase (chọn phase + ghi chú). Xoá
          không có gì để nhập (lý do chưa thu, xem mutation ở trên) nên hộp thứ hai chỉ là ô
          trống 2 nút — và nó cũng làm hỏng chính ô đo C-12 vế 3 (đếm token mở hộp thoại theo
          DÒNG: bình luận nhắc tên token cũng bị tính, bẫy tự-trích-dẫn S188). Câu hỏi
          mang MÃ HĐ + ĐÍCH đi tới ("mục Đã xóa") nói đủ hậu quả — mã để bấm nhầm HĐ khác thì
          nhìn ra, đích để không tưởng là xoá vĩnh viễn. */}
      {canDelete && (
        <div className="sticky bottom-0 z-10 flex flex-wrap items-center gap-3 border-t border-slate-200 bg-white/95 px-5 py-3 backdrop-blur">
          <button
            type="button"
            onClick={() => {
              if (window.confirm(`Xóa hợp đồng ${c.maHopDong ?? c.tenHopDong ?? '(chưa có mã)'}? Hợp đồng chuyển sang mục "Đã xóa".`)) deleteContract.mutate(undefined)
            }}
            disabled={deleteContract.isPending}
            className="inline-flex items-center gap-1.5 rounded-md bg-red-600 px-3 py-2 text-xs font-semibold text-white transition hover:bg-red-700 disabled:opacity-50"
          >
            <Trash2 className="h-3.5 w-3.5" />
            {deleteContract.isPending ? 'Đang xóa…' : 'Xóa hợp đồng'}
          </button>

          <span className="min-w-0 flex-1 text-[12px] text-slate-500">
            Xoá mềm — dữ liệu không mất khỏi hệ thống.
          </span>
        </div>
      )}
    </div>
  )
}

