// [S171 KHKK 3-panel] PANEL 2 (giữa) — nội-dung phiếu "Kế hoạch ký kết HĐ" (GĐ2).
// File MIRROR SHA256 identical với fe-admin counterpart.
//
// 🔴 Khối ý-kiến cấp duyệt (Section 5) là bản thứ 3 của cùng một hình (PE
// `PeDetailTabs.tsx:705-774` · HĐ `components/contracts/WorkflowHistoryPanel.tsx`).
// Gộp được KHI VÀ CHỈ KHI BE 3 module thống-nhất shape `status` precompute — trước đó
// gộp chỉ đẻ ra `if (module === …)`.
//
// Bố-cục mirror Duyệt NCC: dải 4 giai-đoạn trên cùng, rồi các Section ĐÁNH SỐ nối nhau
// bằng `divide-y`, ý-kiến cấp duyệt nằm DƯỚI CÙNG (Ảnh 3 khoanh đỏ).
//   1. Thông tin kế hoạch          4. File đính kèm
//   2. Giá đề xuất theo NCC        5. Ý kiến cấp duyệt
//   3. Căn cứ hồ sơ (b.8-9)
// 🔸 KHÁC PE ở NỘI DUNG (miễn-trừ P2-3, có lý-do nghiệp-vụ): GĐ2 không có báo-giá / so-sánh
// NCC (đã chốt ở GĐ1) mà có căn-cứ hồ-sơ TVGS. Giống nhau ở KHUNG, không ở chữ.
//
// [P2-7] `readOnly` là prop TỪ HOST — host quyết `phiếu ≠ Nháp ∨ user ≠ người soạn`.
// Không dựng workspace riêng cho việc này.
// [R-8] KHKK KHÔNG có phiếu V1-legacy (module sinh 2026-07-29) ⇒ KHÔNG port nhánh fallback
// V1 của PE (`PeDetailTabs.tsx:434-436`) — đó là code chết ngay ngày đầu.
import { useState, type ReactNode } from 'react'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import {
  ClipboardList, FileCheck, Paperclip, Pencil, Plus, Save, Trash2, Upload, Users,
} from 'lucide-react'
import { toast } from 'sonner'
import { PePipelineStrip } from '@/components/pe/PePipelineStrip'
import { Button } from '@/components/ui/Button'
import { Dialog } from '@/components/ui/Dialog'
import { Input } from '@/components/ui/Input'
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 {
  DOSSIER_KIND_LABELS, DOSSIER_STATUS_BADGE, DOSSIER_STATUS_LABELS,
  DossierItemKind, DossierItemStatus,
  KHKK_APPROVAL_GROUP_LABELS, KHKK_PHASE_BADGE, KHKK_PHASE_LABELS,
  KhkkAttachmentPurpose, KhkkPhase,
  type DossierItemKindValue, type DossierItemStatusValue, type KhkkAttachmentDto,
  type KhkkDetailDto, type KhkkDossierItemDto, type KhkkPhaseValue,
  type UpsertKhkkDossierItemInput,
} from '@/types/khkk'

function formatVnd(n: number | null | undefined): string {
  if (n === null || n === undefined) return '—'
  return n.toLocaleString('vi-VN') + ' đ'
}

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

function formatSize(b: number): string {
  return b > 1024 * 1024 ? `${(b / 1024 / 1024).toFixed(1)} MB` : `${Math.round(b / 1024)} KB`
}

/** Khung Section ĐÁNH SỐ — mirror khuôn Section của màn Duyệt NCC (đánh số + divide-y). */
function Section({
  title, icon, accent, head, chipBg, chipFg, count, actions, children,
}: {
  title: string
  icon: ReactNode
  accent: string
  head: string
  chipBg: string
  chipFg: string
  count?: number
  actions?: ReactNode
  children: ReactNode
}) {
  return (
    <section className="px-5 py-4">
      <header className="mb-3 flex items-center gap-2">
        <span
          className="icon-chip"
          style={{ height: '1.75rem', width: '1.75rem', ['--chip-bg' as string]: chipBg, ['--chip-fg' as string]: chipFg }}
          aria-hidden
        >
          {icon}
        </span>
        <h3 className={cn('text-sm font-semibold tracking-tight', head)} style={{ ['--accent' as string]: accent }}>
          {title}
        </h3>
        {count != null && (
          <span className="rounded-full bg-slate-100 px-1.5 py-0.5 text-[10px] font-semibold tabular-nums text-slate-500">
            {count}
          </span>
        )}
        {actions && <span className="ml-auto">{actions}</span>}
      </header>
      {children}
    </section>
  )
}

function Field({
  label, value, mono, full, children,
}: {
  label: string
  value?: ReactNode
  mono?: boolean
  full?: boolean
  children?: ReactNode
}) {
  const empty = value == null || value === ''
  return (
    <div className={cn('min-w-0 text-sm', full && 'sm:col-span-2')}>
      <div className="text-[11px] font-semibold uppercase tracking-wide text-brand-600">{label}</div>
      <div className={cn('mt-0.5 break-words text-sm', empty && !children ? 'text-slate-300' : 'font-medium text-brand-800', mono && !empty && 'font-mono')}>
        {children ?? (empty ? '—' : value)}
      </div>
    </div>
  )
}

const EMPTY_ITEM: UpsertKhkkDossierItemInput = {
  kind: DossierItemKind.MauVatLieu,
  name: '',
  status: DossierItemStatus.ChuaNop,
  tvgsName: '',
  note: '',
}

export function KhkkDetailContent({
  plan,
  readOnly,
  onChanged,
}: {
  plan: KhkkDetailDto
  /** [P2-7] Host quyết: `true` khi phiếu ≠ Nháp/Trả lại HOẶC user ≠ người soạn. */
  readOnly: boolean
  onChanged?: () => void
}) {
  const qc = useQueryClient()
  const id = plan.id
  const [editHeader, setEditHeader] = useState(false)
  const [ghiChu, setGhiChu] = useState('')
  const [hoSoLink, setHoSoLink] = useState('')
  const [itemForm, setItemForm] = useState<UpsertKhkkDossierItemInput | null>(null)

  const phase = plan.phase as KhkkPhaseValue
  const draftPhase = phase === KhkkPhase.DangSoanThao || phase === KhkkPhase.TraLai
  // Sửa được = phiếu còn ở Nháp/Trả lại VÀ host không khoá (readOnly).
  const isDraft = draftPhase && !readOnly

  const invalidate = () => {
    qc.invalidateQueries({ queryKey: ['khkk-detail', id] })
    qc.invalidateQueries({ queryKey: ['khkk-list'] })
    onChanged?.()
  }

  const saveHeader = useMutation({
    mutationFn: async () => {
      await api.put(`/contract-signing-plans/${id}`, {
        ghiChu: ghiChu.trim() || null,
        hoSoLink: hoSoLink.trim() || null,
      })
    },
    onSuccess: () => { toast.success('Đã lưu'); setEditHeader(false); invalidate() },
    onError: (e) => toast.error(getErrorMessage(e)),
  })

  // Danh mục hạng mục SP-002 — chỉ tải khi phiếu còn sửa được (tránh 1 request thừa).
  const catalogOptions = useQuery({
    queryKey: ['contract-catalog', plan.approvalGroup],
    queryFn: async () =>
      (await api.get<{ id: string; code: string; tenVi: string }[]>('/catalogs/contract-catalog', {
        params: { approvalGroup: plan.approvalGroup },
      })).data,
    enabled: isDraft && plan.approvalGroup != null,
  })

  const assignLine = useMutation({
    mutationFn: async (p: { lineId: string; catalogEntryId: string }) =>
      api.put(`/contract-signing-plans/${id}/lines/${p.lineId}`, { catalogEntryId: p.catalogEntryId }),
    onSuccess: () => { toast.success('Đã gán hạng mục'); invalidate() },
    onError: (e) => toast.error(getErrorMessage(e)),
  })

  const upsertItem = useMutation({
    mutationFn: async (body: UpsertKhkkDossierItemInput) => {
      if (!body.name.trim()) throw new Error('Vui lòng nhập tên căn cứ')
      const payload = {
        ...body,
        contractSigningPlanId: id,
        name: body.name.trim(),
        tvgsName: body.tvgsName?.trim() || null,
        note: body.note?.trim() || null,
      }
      // [F-4 S161] POST ép Id=null = LUÔN insert ⇒ "Sửa" phải đi PUT, không thì đẻ bản sao im lặng.
      if (body.id) await api.put(`/contract-signing-plans/${id}/dossier-items/${body.id}`, payload)
      else await api.post(`/contract-signing-plans/${id}/dossier-items`, payload)
    },
    onSuccess: () => { toast.success('Đã lưu căn cứ'); setItemForm(null); invalidate() },
    onError: (e) => toast.error(getErrorMessage(e)),
  })

  const deleteItem = useMutation({
    mutationFn: async (itemId: string) => api.delete(`/contract-signing-plans/${id}/dossier-items/${itemId}`),
    onSuccess: () => { toast.success('Đã xóa căn cứ'); invalidate() },
    onError: (e) => toast.error(getErrorMessage(e)),
  })

  const upload = useMutation({
    mutationFn: async (file: File) => {
      const fd = new FormData()
      fd.append('file', file)
      fd.append('purpose', String(KhkkAttachmentPurpose.DossierScan))
      return api.post(`/contract-signing-plans/${id}/attachments`, fd, {
        headers: { 'Content-Type': 'multipart/form-data' },
      })
    },
    onSuccess: () => { toast.success('Đã tải lên'); invalidate() },
    onError: (e) => toast.error(getErrorMessage(e)),
  })

  const deleteAttachment = useMutation({
    mutationFn: async (attId: string) => api.delete(`/contract-signing-plans/${id}/attachments/${attId}`),
    onSuccess: () => { toast.success('Đã xóa file'); invalidate() },
    onError: (e) => toast.error(getErrorMessage(e)),
  })

  async function download(att: KhkkAttachmentDto) {
    try {
      const res = await api.get(`/contract-signing-plans/${id}/attachments/${att.id}/download`, {
        responseType: 'blob',
      })
      const url = window.URL.createObjectURL(res.data as Blob)
      const a = document.createElement('a')
      a.href = url
      a.download = att.fileName
      a.click()
      window.URL.revokeObjectURL(url)
    } catch (e) {
      toast.error(getErrorMessage(e))
    }
  }

  async function onPickFiles(e: React.ChangeEvent<HTMLInputElement>) {
    const files = Array.from(e.target.files ?? [])
    e.target.value = ''
    for (const f of files) {
      try { await upload.mutateAsync(f) } catch { /* lỗi đã toast ở onError */ }
    }
  }

  const startEditHeader = () => {
    setGhiChu(plan.ghiChu ?? '')
    setHoSoLink(plan.hoSoLink ?? '')
    setEditHeader(true)
  }

  // File "đính kèm khi duyệt" thuộc panel 3 (mục 5) — Section 4 chỉ liệt kê hồ-sơ của phiếu.
  const planAttachments = plan.attachments.filter(a => a.purpose !== KhkkAttachmentPurpose.ApprovalAttachment)

  // 🧊 [S174 owner] Section 5 "Ý kiến cấp duyệt" ĐÃ GỠ khỏi panel giữa — anh: "bỏ luôn cái
  // này ra luôn". Sơ-đồ Bước/Cấp + chữ ký đã sống ở PANEL 3 (`KhkkWorkflowPanel`), để cả hai
  // là kể một chuyện hai lần trên cùng màn hình. Dữ-liệu `plan.levelOpinions` /
  // `plan.workflowSteps` VẪN có trong DTO (panel 3 dùng) — chỉ bỏ chỗ VẼ ở đây.

  return (
    <div className="card-accent overflow-hidden" style={{ ['--accent' as string]: 'var(--color-brand-500)' }}>
      {/* Dải 4 giai-đoạn — GĐ2 đang sáng. Cùng component với màn Duyệt NCC (không nhân bản). */}
      <PePipelineStrip current={2} />

      <div className="flex flex-wrap items-center gap-2 border-b border-slate-200 px-5 py-3">
        <span className="font-mono text-sm font-semibold text-brand-800">{plan.maKeHoach ?? '(chưa cấp mã)'}</span>
        <span className="min-w-0 flex-1 truncate text-sm text-slate-700">{plan.peTenGoiThau ?? '—'}</span>
        {plan.approvalGroup != null && (
          <span
            className="inline-flex items-center rounded-md border border-violet-300 bg-violet-100 px-2 py-0.5 text-[11px] font-semibold text-violet-800"
            title={KHKK_APPROVAL_GROUP_LABELS[plan.approvalGroup] ?? `Nhóm ${plan.approvalGroup}`}
          >
            N{plan.approvalGroup}
          </span>
        )}
        <span className={cn('inline-flex items-center rounded-md border px-2 py-0.5 text-[11px] font-medium', KHKK_PHASE_BADGE[phase])}>
          {KHKK_PHASE_LABELS[phase]}
        </span>
      </div>

      <div className="divide-y divide-slate-200">
        {/* ─────────────── 1 ─────────────── */}
        <Section
          title="1. Thông tin kế hoạch"
          icon={<FileCheck className="h-4 w-4" />}
          accent="var(--color-brand-500)"
          head="text-brand-800"
          chipBg="var(--color-brand-50)"
          chipFg="var(--color-brand-600)"
          actions={
            isDraft && !editHeader ? (
              <Button variant="outline" size="sm" onClick={startEditHeader}>
                <Pencil className="mr-2 h-3.5 w-3.5" /> Sửa
              </Button>
            ) : undefined
          }
        >
          <div className="grid grid-cols-1 gap-x-6 gap-y-4 md:grid-cols-2">
            <Field label="Mã kế hoạch" value={plan.maKeHoach ?? '—'} mono />
            <Field label="Phiếu Duyệt NCC nguồn">
              <span className="font-mono text-sm">{plan.peMaPhieu ?? '—'}</span>
            </Field>
            <Field label="Dự án" value={plan.projectName ?? '—'} />
            <Field label="Phòng ban" value={plan.departmentName ?? '—'} />
            <Field label="Người soạn" value={plan.drafterFullName ?? '—'} />
            <Field label="Quy trình">
              {plan.workflowCode ? (
                <span>
                  <span className="font-mono">{plan.workflowCode}</span>
                  {plan.workflowVersion != null && <span className="font-mono"> v{plan.workflowVersion}</span>}
                  {plan.workflowName ? ` · ${plan.workflowName}` : ''}
                </span>
              ) : (
                <span className="text-slate-300">— Chưa chọn —</span>
              )}
            </Field>
            <Field label="Ngày tạo" value={formatDateTime(plan.createdAt)} />
            <Field label="Hạn xử lý (tham khảo)" value={plan.slaDeadline ? formatDateTime(plan.slaDeadline) : '—'} />
          </div>

          {editHeader ? (
            <div className="mt-4 space-y-3 rounded-lg border border-slate-200 bg-slate-50/60 p-4">
              <div>
                <Label htmlFor="hoSoLink">Link hồ sơ (NAS)</Label>
                <Input id="hoSoLink" value={hoSoLink} onChange={(e) => setHoSoLink(e.target.value)} maxLength={1000} placeholder="\\\\nas\\du-an\\..." />
              </div>
              <div>
                <Label htmlFor="ghiChu">Ghi chú</Label>
                <Textarea id="ghiChu" value={ghiChu} onChange={(e) => setGhiChu(e.target.value)} maxLength={2000} rows={4} />
                <div className="mt-1 text-xs text-muted-foreground">{ghiChu.length}/2000</div>
              </div>
              <div className="flex justify-end gap-2">
                <Button variant="outline" size="sm" onClick={() => setEditHeader(false)}>Huỷ</Button>
                <Button size="sm" onClick={() => saveHeader.mutate()} disabled={saveHeader.isPending}>
                  <Save className="mr-2 h-3.5 w-3.5" />
                  {saveHeader.isPending ? 'Đang lưu...' : 'Lưu'}
                </Button>
              </div>
            </div>
          ) : (
            <div className="mt-4 grid grid-cols-1 gap-x-6 gap-y-4 md:grid-cols-2">
              <Field label="Link hồ sơ" full>
                {plan.hoSoLink ? <span className="break-all font-normal text-slate-700">{plan.hoSoLink}</span> : <span className="text-slate-300">—</span>}
              </Field>
              <Field label="Ghi chú" full>
                {plan.ghiChu ? <span className="whitespace-pre-wrap font-normal text-slate-700">{plan.ghiChu}</span> : <span className="text-slate-300">—</span>}
              </Field>
            </div>
          )}
        </Section>

        {/* ─────────────── 2 ─────────────── */}
        <Section
          title={`2. Giá đề xuất theo NCC trúng thầu (${plan.lines.length} dòng)`}
          icon={<Users className="h-4 w-4" />}
          accent="var(--color-teal-500)"
          head="text-teal-700"
          chipBg="var(--color-teal-50)"
          chipFg="var(--color-teal-700)"
          actions={
            plan.budgetFrozen ? (
              <span className="inline-flex items-center rounded-md border border-amber-300 bg-amber-100 px-2 py-0.5 text-[11px] font-semibold normal-case tracking-normal text-amber-800">
                🔒 Giá đã chốt tại thời điểm duyệt
              </span>
            ) : undefined
          }
        >
          {plan.lines.length === 0 ? (
            <div className="text-sm text-muted-foreground">Phiếu nguồn chưa có NCC trúng thầu.</div>
          ) : (
            <div className="overflow-x-auto">
              <table className="w-full text-sm">
                <thead className="border-b border-slate-200 bg-slate-50/70">
                  <tr>
                    <th className="label-eyebrow px-3 py-2 text-left">Nhà cung cấp</th>
                    <th className="label-eyebrow px-3 py-2 text-left">Hạng mục</th>
                    <th className="label-eyebrow px-3 py-2 text-right">Giá tham chiếu</th>
                    <th className="label-eyebrow px-3 py-2 text-right">Giá đề xuất</th>
                    <th className="label-eyebrow px-3 py-2 text-right">Giá duyệt</th>
                    <th className="label-eyebrow px-3 py-2 text-left">Ghi chú</th>
                  </tr>
                </thead>
                <tbody>
                  {plan.lines.map((l) => (
                    <tr key={l.id} className="border-b border-slate-100 last:border-0">
                      <td className="px-3 py-2 font-medium text-brand-800">
                        {l.supplierName ?? '—'}
                        {l.contractId && (
                          <a href={`/contracts/${l.contractId}`} className="ml-2 text-[10px] font-medium text-brand-600 hover:underline" title="Dòng này đã được đưa vào hợp đồng">
                            ✓ HĐ
                          </a>
                        )}
                      </td>
                      <td className="px-3 py-2 text-xs text-slate-700">
                        {isDraft && !l.contractId ? (
                          <>
                            <select
                              value={l.catalogEntryId ?? ''}
                              onChange={(e) => e.target.value && assignLine.mutate({ lineId: l.id, catalogEntryId: e.target.value })}
                              disabled={assignLine.isPending}
                              aria-label={`Gán hạng mục SP-002 cho dòng ${l.supplierName ?? l.id}`}
                              className="h-8 w-full min-w-[12rem] rounded-md border border-slate-200 bg-white px-2 text-xs text-slate-700 focus-visible:border-brand-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500/30"
                            >
                              <option value="">— Chọn hạng mục —</option>
                              {/* Hạng mục ĐÃ LƯU mà không có trong options ⇒ chèn option đại diện,
                                  không thì dòng đã gán TRÔNG như chưa gán. */}
                              {l.catalogEntryId && !(catalogOptions.data ?? []).some((c) => c.id === l.catalogEntryId) && (
                                <option value={l.catalogEntryId}>{l.tenHangMuc ?? '(hạng mục đã gán)'}</option>
                              )}
                              {(catalogOptions.data ?? []).map((c) => (
                                <option key={c.id} value={c.id}>{c.code} — {c.tenVi}</option>
                              ))}
                            </select>
                            {catalogOptions.isError && (
                              <div className="mt-1 text-[11px] text-red-600">
                                Không tải được danh mục hạng mục —{' '}
                                <button type="button" className="underline" onClick={() => catalogOptions.refetch()}>thử lại</button>
                              </div>
                            )}
                            {catalogOptions.isSuccess && (catalogOptions.data?.length ?? 0) === 0 && (
                              <div className="mt-1 text-[11px] text-amber-700">
                                Nhóm duyệt N{plan.approvalGroup} chưa có hạng mục đang hiệu lực — liên hệ quản trị danh mục.
                              </div>
                            )}
                          </>
                        ) : l.tenHangMuc ? l.tenHangMuc : <span className="text-slate-300">—</span>}
                      </td>
                      <td className="px-3 py-2 text-right tabular-nums text-slate-600">{formatVnd(l.peReferenceAmount)}</td>
                      <td className="px-3 py-2 text-right tabular-nums text-brand-800">{formatVnd(l.proposedAmount)}</td>
                      <td className="px-3 py-2 text-right tabular-nums text-emerald-700">{formatVnd(l.approvedAmount)}</td>
                      <td className="px-3 py-2 text-xs text-slate-600">{l.note ?? '—'}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
          <div className="mt-3 text-xs text-muted-foreground">
            Giá tham chiếu là SNAPSHOT tổng báo giá được chọn của NCC trên phiếu Duyệt NCC tại thời điểm lập kế hoạch.
            {' '}Cột Hạng mục gán ngay tại bảng khi phiếu ở Nháp/Trả lại — mọi dòng phải gán xong mới trình duyệt được.
          </div>
        </Section>

        {/* ─────────────── 3 ─────────────── */}
        <Section
          title="3. Căn cứ hồ sơ (mẫu vật liệu / shopdrawing)"
          icon={<ClipboardList className="h-4 w-4" />}
          accent="var(--color-violet-500)"
          head="text-violet-700"
          chipBg="var(--color-violet-50)"
          chipFg="var(--color-violet-700)"
          count={plan.dossierItems.length}
          actions={
            isDraft ? (
              <Button variant="outline" size="sm" onClick={() => setItemForm({ ...EMPTY_ITEM })}>
                <Plus className="mr-2 h-3.5 w-3.5" /> Thêm căn cứ
              </Button>
            ) : undefined
          }
        >
          {plan.dossierItems.length === 0 ? (
            <div className="text-sm text-muted-foreground">Chưa khai căn cứ nào.</div>
          ) : (
            <div className="overflow-x-auto">
              <table className="w-full text-sm">
                <thead className="border-b border-slate-200 bg-slate-50/70">
                  <tr>
                    <th className="label-eyebrow px-3 py-2 text-left">Loại</th>
                    <th className="label-eyebrow px-3 py-2 text-left">Tên căn cứ</th>
                    <th className="label-eyebrow px-3 py-2 text-left">Trạng thái</th>
                    <th className="label-eyebrow px-3 py-2 text-left">TVGS</th>
                    <th className="label-eyebrow px-3 py-2 text-left">Ghi chú</th>
                    {isDraft && <th className="label-eyebrow px-3 py-2 text-right">Thao tác</th>}
                  </tr>
                </thead>
                <tbody>
                  {plan.dossierItems.map((d: KhkkDossierItemDto) => (
                    <tr key={d.id} className="border-b border-slate-100 last:border-0">
                      <td className="px-3 py-2 text-xs text-slate-600">{DOSSIER_KIND_LABELS[d.kind] ?? '—'}</td>
                      <td className="px-3 py-2 font-medium text-brand-800">{d.name}</td>
                      <td className="px-3 py-2">
                        <span className={cn('inline-flex items-center rounded-md border px-2 py-0.5 text-xs font-medium', DOSSIER_STATUS_BADGE[d.status])}>
                          {DOSSIER_STATUS_LABELS[d.status]}
                        </span>
                      </td>
                      <td className="px-3 py-2 text-xs text-slate-600">
                        {d.tvgsName ?? '—'}
                        {d.tvgsResultAt && <span className="ml-1 text-[11px] text-slate-400">({formatDateTime(d.tvgsResultAt)})</span>}
                      </td>
                      <td className="px-3 py-2 text-xs text-slate-600">{d.note ?? '—'}</td>
                      {isDraft && (
                        <td className="px-3 py-2 text-right">
                          <div className="flex justify-end gap-1">
                            <button
                              type="button"
                              onClick={() => setItemForm({
                                id: d.id, kind: d.kind, supplierId: d.supplierId, name: d.name,
                                status: d.status, tvgsName: d.tvgsName ?? '', note: d.note ?? '',
                              })}
                              className="rounded px-1.5 py-1 text-violet-600 hover:bg-violet-50"
                              title="Sửa"
                            >
                              <Pencil className="h-3.5 w-3.5" />
                            </button>
                            <button
                              type="button"
                              onClick={() => { if (window.confirm(`Xóa căn cứ "${d.name}"?`)) deleteItem.mutate(d.id) }}
                              className="rounded px-1.5 py-1 text-red-600 hover:bg-red-50"
                              title="Xóa"
                            >
                              <Trash2 className="h-3.5 w-3.5" />
                            </button>
                          </div>
                        </td>
                      )}
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </Section>

        {/* ─────────────── 4 ─────────────── */}
        <Section
          title="4. File đính kèm"
          icon={<Paperclip className="h-4 w-4" />}
          accent="var(--color-teal-500)"
          head="text-teal-700"
          chipBg="var(--color-teal-50)"
          chipFg="var(--color-teal-700)"
          count={planAttachments.length}
          actions={
            readOnly ? undefined : (
              <label className="inline-flex cursor-pointer items-center rounded-md border border-slate-300 px-2.5 py-1.5 text-xs font-medium text-slate-700 hover:bg-slate-50">
                <Upload className="mr-2 h-3.5 w-3.5" />
                {upload.isPending ? 'Đang tải...' : 'Tải file lên'}
                <input type="file" multiple className="hidden" onChange={onPickFiles} />
              </label>
            )
          }
        >
          {planAttachments.length === 0 ? (
            <div className="text-sm text-muted-foreground">Chưa có file đính kèm.</div>
          ) : (
            <ul className="space-y-2">
              {planAttachments.map((a) => (
                <li key={a.id} className="flex items-center justify-between rounded-lg border border-slate-200 p-2.5 text-sm">
                  <div className="min-w-0">
                    <div className="truncate font-medium text-brand-800">{a.fileName}</div>
                    <div className="text-xs text-muted-foreground">{formatSize(a.fileSize)} · {formatDateTime(a.createdAt)}</div>
                  </div>
                  <div className="flex shrink-0 gap-2">
                    <button type="button" onClick={() => download(a)} className="text-xs text-primary hover:underline">Tải xuống</button>
                    {!readOnly && (
                      <button
                        type="button"
                        onClick={() => { if (window.confirm(`Xóa file "${a.fileName}"?`)) deleteAttachment.mutate(a.id) }}
                        className="text-xs text-red-600 hover:underline"
                      >
                        Xóa
                      </button>
                    )}
                  </div>
                </li>
              ))}
            </ul>
          )}
        </Section>
      </div>

      {/* Dialog thêm/sửa căn cứ */}
      <Dialog open={!!itemForm} onClose={() => setItemForm(null)} title={itemForm?.id ? 'Sửa căn cứ hồ sơ' : 'Thêm căn cứ hồ sơ'}>
        {itemForm && (
          <div className="space-y-3">
            <div>
              <Label htmlFor="item-kind">Loại căn cứ</Label>
              <select
                id="item-kind"
                value={itemForm.kind}
                onChange={(e) => setItemForm({ ...itemForm, kind: Number(e.target.value) as DossierItemKindValue })}
                className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm"
              >
                {Object.entries(DOSSIER_KIND_LABELS).map(([v, label]) => (
                  <option key={v} value={v}>{label}</option>
                ))}
              </select>
            </div>
            <div>
              <Label htmlFor="item-name">Tên căn cứ <span className="text-red-500">*</span></Label>
              <Input id="item-name" value={itemForm.name} onChange={(e) => setItemForm({ ...itemForm, name: e.target.value })} maxLength={300} placeholder="vd. Mẫu thép D10 Hoà Phát" />
            </div>
            <div>
              <Label htmlFor="item-status">Trạng thái</Label>
              <select
                id="item-status"
                value={itemForm.status}
                onChange={(e) => setItemForm({ ...itemForm, status: Number(e.target.value) as DossierItemStatusValue })}
                className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm"
              >
                {Object.entries(DOSSIER_STATUS_LABELS).map(([v, label]) => (
                  <option key={v} value={v}>{label}</option>
                ))}
              </select>
            </div>
            <div>
              <Label htmlFor="item-tvgs">Tên TVGS xử lý</Label>
              <Input id="item-tvgs" value={itemForm.tvgsName ?? ''} onChange={(e) => setItemForm({ ...itemForm, tvgsName: e.target.value })} maxLength={200} />
            </div>
            <div>
              <Label htmlFor="item-note">Ghi chú</Label>
              <Textarea id="item-note" value={itemForm.note ?? ''} onChange={(e) => setItemForm({ ...itemForm, note: e.target.value })} maxLength={1000} rows={3} />
            </div>
            <div className="flex justify-end gap-2 pt-2">
              <Button variant="outline" onClick={() => setItemForm(null)}>Huỷ</Button>
              <Button onClick={() => upsertItem.mutate(itemForm)} disabled={upsertItem.isPending || !itemForm.name.trim()}>
                {upsertItem.isPending ? 'Đang lưu...' : 'Lưu'}
              </Button>
            </div>
          </div>
        )}
      </Dialog>
    </div>
  )
}
