// Quy trình duyệt MỚI (Mig 22 — Session 17, 2026-05-08).
// Schema riêng UAT trước khi drop legacy. Cấu trúc:
//   Quy trình (Mã + Tên + ApplicableType)
//     Bước 1 — Phòng A
//       Cấp 1 (N NV duyệt)
//       Cấp 2 (N NV duyệt)
//       Cấp 3 (N NV duyệt)
//
// Iteration 3 (UAT feedback 2026-05-08):
//  - TỐI ĐA 3 cấp/bước (không có cấp 4). 1/2/3 cấp đều OK — quy trình
//    chạy theo số cấp thật sự có.
//  - MỖI CẤP CÓ N NV: convention multiple Level rows cùng Order = same Cấp.
//    BE iterate group by Order; trong cùng cấp = OR-of-N approvers.
//  - 3 section cố định C1/C2/C3 trong UI. Mỗi section có nút "+ Thêm NV"
//    + Trash xóa từng NV.
//  - Sequential gating: C2 disabled khi C1 chưa có NV. C3 disabled khi C2
//    chưa có NV. Chặn xóa NV cuối C1 khi C2/C3 còn entries.
//  - Select NV CHỈ filter theo Phòng đã chọn (đổi Phòng → clear approvers).
import { useMemo, useState, type FormEvent } from 'react'
import { useParams } from 'react-router-dom'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { GitBranch, Plus, Trash2, CheckCircle2, History, Workflow, ChevronUp, ChevronDown, Pin, PinOff } from 'lucide-react'
import { toast } from 'sonner'
import { PageHeader } from '@/components/PageHeader'
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 { Select } from '@/components/ui/Select'
import { Textarea } from '@/components/ui/Textarea'
import { api } from '@/lib/api'
import { getErrorMessage } from '@/lib/apiError'
import type { Department, Paged } from '@/types/master'

// ===== Types (mirror BE AwAdminOverviewDto) =====

type LevelDto = {
  id: string
  order: number
  name: string | null
  approverUserId: string
  approverUserName: string | null
  approverEmail: string | null
  // Mig 29 (S21 t5) — 5 Allow* options per slot Approver
  // Mig 30 (S22+5) — +AllowApproverEditBudget cho Section ngân sách
  // Mig 31 (S23 t1) — +AllowApproverSkipToFinal F2 storage swap Users→Level (per-Approver-slot)
  allowReturnOneLevel: boolean
  allowReturnOneStep: boolean
  allowReturnToAssignee: boolean
  allowReturnToDrafter: boolean
  allowApproverEditDetails: boolean
  allowApproverEditBudget: boolean
  allowApproverSkipToFinal: boolean
  allowApproverFinalize: boolean       // [Mig 58 CCM item 4] slot Duyệt = KẾT THÚC (không trình CEO)
  // [S76] Hiển thị-only: approver được nhập/điều chỉnh ngân sách cột nào (suy từ role).
  canEditProBudget: boolean
  canEditCcmBudget: boolean
}
type StepDto = {
  id: string
  order: number
  name: string                      // "Phòng A" — display
  departmentId: string | null
  departmentName: string | null
  levels: LevelDto[]
}
type DefinitionDto = {
  id: string
  code: string
  version: number
  applicableType: number
  applicableTypeLabel: string
  name: string
  description: string | null
  isActive: boolean
  isUserSelectable: boolean    // Mig 25 — admin toggle cho user pick
  // S69 — ngưỡng giá trị "gói CEO". Null = không áp ngưỡng (luồng đủ quy trình).
  // Gói < ngưỡng: CCM duyệt-final không cần CEO. ≥ ngưỡng: phải lên CEO.
  ceoApprovalThreshold: number | null
  // Mig 29 (S21 t5) + Mig 30 (S22+5) + Mig 31 (S23 t1) — 7 Allow* options
  // ALL xuống per slot Level (xem LevelDto). Admin opt-in per-Approver-slot
  // pattern proven 3× cumulative: F1+F3 (5 flag Mig 29) + F4 (Mig 30) + F2
  // (Mig 31 refactor sang Approver scope, storage cũ Users đã drop).
  activatedAt: string | null
  createdAt: string
  steps: StepDto[]
}
type TypeSummaryDto = {
  applicableType: number
  applicableTypeLabel: string
  active: DefinitionDto | null
  history: DefinitionDto[]
}

type LevelOrder = 1 | 2 | 3
type EditLevelEntry = {
  order: LevelOrder
  approverUserId: string
  // Mig 29 (S21 t5) — 5 Allow* per slot (default backward compat S17: chỉ
  // AllowReturnToDrafter=true, 4 còn lại false).
  // Mig 30 (S22+5) — +AllowApproverEditBudget cho Section ngân sách (default false).
  // Mig 31 (S23 t1) — +AllowApproverSkipToFinal F2 admin opt-in per-Approver-slot (default false).
  allowReturnOneLevel: boolean
  allowReturnOneStep: boolean
  allowReturnToAssignee: boolean
  allowReturnToDrafter: boolean
  allowApproverEditDetails: boolean
  allowApproverEditBudget: boolean
  allowApproverSkipToFinal: boolean
  allowApproverFinalize: boolean
}
type EditStep = { name: string; departmentId: string | null; levelEntries: EditLevelEntry[] }

type ApproverUser = { id: string; fullName: string; email: string; departmentId: string | null }

// Tối đa 3 cấp/bước per UAT iter 3 (2026-05-08). Quy trình chạy theo số cấp
// thật sự có (1 / 2 / 3). Mỗi cấp có N NV (multiple Level rows cùng Order).
const MAX_LEVELS_PER_STEP = 3
const LEVEL_ORDERS: LevelOrder[] = [1, 2, 3]

// FE typeCode → BE int (giống MenuKeys ApplicableType)
const TYPE_CODE_TO_INT: Record<string, number> = {
  DuyetNcc: 1,
  DuyetNccPhuongAn: 2,
  Contract: 3,
}
const DEFAULT_CODE_BY_TYPE: Record<number, string> = {
  1: 'QT-DN-V2-001',
  2: 'QT-DN-PA-V2-001',
  3: 'QT-HD-V2-001',
}

function makeEmptyStep(stepNo: number, deptId: string | null = null): EditStep {
  return {
    name: `Phòng ${stepNo}`,
    departmentId: deptId,
    levelEntries: [],
  }
}

// Clone existing definition: filter Order ∈ {1,2,3}, drop entries vượt giới hạn.
// Mig 29 (S21 t5) — clone 5 Allow* per slot từ existing Level.
function copyFromDefinition(d: DefinitionDto): EditStep[] {
  return d.steps.map(s => ({
    name: s.name,
    departmentId: s.departmentId,
    levelEntries: s.levels
      .filter(l => l.order >= 1 && l.order <= MAX_LEVELS_PER_STEP)
      .map(l => ({
        order: l.order as LevelOrder,
        approverUserId: l.approverUserId,
        allowReturnOneLevel: l.allowReturnOneLevel ?? false,
        allowReturnOneStep: l.allowReturnOneStep ?? false,
        allowReturnToAssignee: l.allowReturnToAssignee ?? false,
        allowReturnToDrafter: l.allowReturnToDrafter ?? true,
        allowApproverEditDetails: l.allowApproverEditDetails ?? false,
        allowApproverEditBudget: l.allowApproverEditBudget ?? false,
        allowApproverSkipToFinal: l.allowApproverSkipToFinal ?? false,
        allowApproverFinalize: l.allowApproverFinalize ?? false,
      })),
  }))
}

// Mig 29 — Factory default cho entry mới (admin click "+ Thêm NV"). 5 flag
// default backward compat S17: chỉ AllowReturnToDrafter=true.
function makeDefaultLevelEntry(order: LevelOrder, approverUserId: string): EditLevelEntry {
  return {
    order,
    approverUserId,
    allowReturnOneLevel: false,
    allowReturnOneStep: false,
    allowReturnToAssignee: false,
    allowReturnToDrafter: true,
    allowApproverEditDetails: false,
    allowApproverEditBudget: false,
    allowApproverSkipToFinal: false,
    allowApproverFinalize: false,
  }
}

// Filter NV theo Phòng. Nếu Phòng = null → fallback all (chưa chọn phòng).
function usersForDept(all: ApproverUser[] | undefined, deptId: string | null): ApproverUser[] {
  if (!all) return []
  if (!deptId) return all
  return all.filter(u => u.departmentId === deptId)
}

function entriesAtLevel(step: EditStep, order: LevelOrder): EditLevelEntry[] {
  return step.levelEntries.filter(e => e.order === order)
}

// Cấp k được phép thao tác khi Cấp k-1 có ≥1 NV (gating sequential).
function isLevelEnabled(step: EditStep, order: LevelOrder): boolean {
  if (order === 1) return step.departmentId !== null
  return entriesAtLevel(step, (order - 1) as LevelOrder).length > 0
}

export function ApprovalWorkflowsV2Page() {
  const qc = useQueryClient()
  const { typeCode } = useParams<{ typeCode?: string }>()
  const selectedTypeInt = typeCode ? TYPE_CODE_TO_INT[typeCode] : null

  const overview = useQuery({
    queryKey: ['approval-workflow-v2-overview', selectedTypeInt],
    queryFn: async () => {
      const params = selectedTypeInt ? { applicableType: selectedTypeInt } : {}
      return (await api.get<{ types: TypeSummaryDto[] }>('/approval-workflows-v2', { params })).data
    },
  })

  const currentType = selectedTypeInt
    ? overview.data?.types.find(t => t.applicableType === selectedTypeInt)
    : null

  return (
    <div className="p-6">
      <PageHeader
        title={
          <span className="flex items-center gap-2">
            <Workflow className="h-5 w-5" />
            {currentType
              ? `Quy trình duyệt (Mới): ${currentType.applicableTypeLabel}`
              : 'Quy trình duyệt (Mới)'}
          </span>
        }
        description={
          currentType
            ? 'Mỗi Bước = 1 Phòng. Mỗi Cấp trong Bước = 1 nhân viên cụ thể duyệt. Tuần tự: Cấp 1 → Cấp 2 → ... → Bước kế.'
            : 'Schema mới UAT — chọn loại quy trình từ menu bên trái.'
        }
      />

      {overview.isLoading && <div className="text-sm text-slate-500">Đang tải…</div>}

      {overview.data && !currentType && (
        <div className="grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3">
          {overview.data.types.map(t => (
            <div key={t.applicableType} className="rounded-xl border border-slate-200 bg-white p-4 shadow-sm">
              <div className="flex items-center justify-between">
                <h3 className="text-sm font-semibold text-slate-800">{t.applicableTypeLabel}</h3>
                {t.active && (
                  <span className="rounded bg-brand-50 px-2 py-0.5 font-mono text-[10px] font-medium text-brand-700">
                    {t.active.code} v{String(t.active.version).padStart(2, '0')}
                  </span>
                )}
              </div>
              <div className="mt-2 text-xs text-slate-500">
                {t.active
                  ? `${t.active.steps.length} bước · ${t.active.steps.reduce((s, x) => s + x.levels.length, 0)} cấp · ${t.history.length} version`
                  : 'Chưa có quy trình'}
              </div>
            </div>
          ))}
        </div>
      )}

      {currentType && (
        <TypePanel
          type={currentType}
          onSaved={() => qc.invalidateQueries({ queryKey: ['approval-workflow-v2-overview'] })}
        />
      )}
    </div>
  )
}

// ===== Per-type panel =====

function TypePanel({ type, onSaved }: { type: TypeSummaryDto; onSaved: () => void }) {
  const [designerOpen, setDesignerOpen] = useState(false)
  const [cloneFrom, setCloneFrom] = useState<DefinitionDto | null>(null)
  const qc = useQueryClient()

  const del = useMutation({
    mutationFn: async (id: string) => api.delete(`/approval-workflows-v2/${id}`),
    onSuccess: () => {
      toast.success('Đã xoá version')
      qc.invalidateQueries({ queryKey: ['approval-workflow-v2-overview'] })
    },
    onError: err => toast.error(getErrorMessage(err)),
  })

  // Mig 25 — toggle "cho user pick lúc create phiếu" (stick/unstick)
  const toggleSelectable = useMutation({
    mutationFn: async ({ id, isUserSelectable }: { id: string; isUserSelectable: boolean }) =>
      api.patch(`/approval-workflows-v2/${id}/user-selectable`, { isUserSelectable }),
    onSuccess: (_data, vars) => {
      toast.success(vars.isUserSelectable
        ? 'Đã ghim — user có thể chọn quy trình này'
        : 'Đã bỏ ghim — user không thấy quy trình này')
      qc.invalidateQueries({ queryKey: ['approval-workflow-v2-overview'] })
    },
    onError: err => toast.error(getErrorMessage(err)),
  })

  return (
    <div className="space-y-4">
      {type.active ? (
        <DefinitionCard
          def={type.active}
          isActive
          onClone={d => { setCloneFrom(d); setDesignerOpen(true) }}
          onToggleSelectable={() => toggleSelectable.mutate({
            id: type.active!.id,
            isUserSelectable: !type.active!.isUserSelectable,
          })}
          onDelete={() => {
            if (confirm(`Xoá version đang áp dụng "${type.active!.code} v${type.active!.version}"?`)) {
              del.mutate(type.active!.id)
            }
          }}
        />
      ) : (
        <div className="rounded-xl border border-dashed border-slate-300 p-8 text-center text-sm text-slate-500">
          Chưa có quy trình cho loại này. Tạo version đầu tiên bên dưới.
        </div>
      )}

      <div className="flex items-center justify-between">
        <h3 className="text-sm font-semibold text-slate-700">Lịch sử versions</h3>
        <Button onClick={() => { setCloneFrom(type.active); setDesignerOpen(true) }}>
          <Plus className="h-4 w-4" />
          Tạo quy trình mới
        </Button>
      </div>

      {type.history.filter(d => !d.isActive).length === 0 && (
        <div className="rounded-md border border-slate-200 bg-slate-50 p-4 text-xs text-slate-500">
          Chưa có version cũ. Khi tạo version mới, version hiện tại tự động archive.
        </div>
      )}

      <div className="space-y-2">
        {type.history.filter(d => !d.isActive).map(d => (
          <DefinitionCard
            key={d.id}
            def={d}
            isActive={false}
            onClone={dd => { setCloneFrom(dd); setDesignerOpen(true) }}
            onToggleSelectable={() => toggleSelectable.mutate({
              id: d.id,
              isUserSelectable: !d.isUserSelectable,
            })}
            onDelete={() => {
              if (confirm(`Xoá version "${d.code} v${d.version}"?`)) del.mutate(d.id)
            }}
          />
        ))}
      </div>

      {designerOpen && (
        <Designer
          applicableType={type.applicableType}
          applicableTypeLabel={type.applicableTypeLabel}
          cloneFrom={cloneFrom}
          onClose={() => { setDesignerOpen(false); setCloneFrom(null) }}
          onSaved={() => { setDesignerOpen(false); setCloneFrom(null); onSaved() }}
        />
      )}
    </div>
  )
}

// ===== Definition card (read-only) =====

function DefinitionCard({
  def,
  isActive,
  onClone,
  onToggleSelectable,
  onDelete,
}: {
  def: DefinitionDto
  isActive: boolean
  onClone: (d: DefinitionDto) => void
  onToggleSelectable: () => void
  onDelete: () => void
}) {
  return (
    <div className={`rounded-xl border bg-white p-5 shadow-sm ${isActive ? 'border-brand-200' : 'border-slate-200'}`}>
      <div className="flex items-start justify-between gap-4">
        <div className="min-w-0 flex-1">
          <div className="flex items-center gap-2">
            <h3 className="text-[15px] font-semibold text-slate-900">{def.name}</h3>
            <span className="rounded bg-slate-100 px-2 py-0.5 font-mono text-[11px] text-slate-600">
              {def.code} v{String(def.version).padStart(2, '0')}
            </span>
            {isActive ? (
              <span className="inline-flex items-center gap-1 rounded-full bg-emerald-100 px-2 py-0.5 text-[10px] font-medium text-emerald-700">
                <CheckCircle2 className="h-3 w-3" />
                Đang áp dụng
              </span>
            ) : (
              <span className="inline-flex items-center gap-1 rounded-full bg-slate-100 px-2 py-0.5 text-[10px] font-medium text-slate-600">
                <History className="h-3 w-3" />
                Archived
              </span>
            )}
            {/* Mig 25 — badge IsUserSelectable: ghim cho user pick */}
            {def.isUserSelectable && (
              <span className="inline-flex items-center gap-1 rounded-full bg-amber-100 px-2 py-0.5 text-[10px] font-medium text-amber-700" title="User có thể chọn quy trình này khi tạo phiếu">
                <Pin className="h-3 w-3" />
                Cho user chọn
              </span>
            )}
            {/* S69 — badge ngưỡng gói CEO (nếu có set) */}
            {def.ceoApprovalThreshold != null && (
              <span
                className="inline-flex items-center gap-1 rounded-full bg-rose-100 px-2 py-0.5 text-[10px] font-medium text-rose-700"
                title="Gói ≥ ngưỡng phải lên CEO duyệt. Gói < ngưỡng: CCM duyệt là xong."
              >
                Ngưỡng CEO: {def.ceoApprovalThreshold.toLocaleString('vi-VN')}đ
              </span>
            )}
          </div>
          {def.description && <p className="mt-1 text-xs leading-relaxed text-slate-500">{def.description}</p>}

          <ol className="mt-3 space-y-2">
            {def.steps.map(s => (
              <li key={s.id} className="rounded-lg border border-slate-100 bg-slate-50/30 p-3">
                <div className="flex items-center gap-2">
                  <div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-brand-600 text-[11px] font-bold text-white">
                    {s.order}
                  </div>
                  <span className="text-sm font-medium text-slate-800">Bước {s.order} — {s.name}</span>
                  {s.departmentName && (
                    <span className="rounded bg-emerald-50 px-1.5 py-0.5 text-[10px] font-medium text-emerald-700">
                      {s.departmentName}
                    </span>
                  )}
                </div>
                {/* Group by Order — 1 cấp có N NV */}
                <ul className="mt-2 ml-9 space-y-1.5">
                  {s.levels.length === 0 ? (
                    <li className="text-[11px] italic text-slate-400">Chưa có cấp duyệt</li>
                  ) : (
                    Array.from(
                      s.levels.reduce((map, l) => {
                        const arr = map.get(l.order) ?? []
                        arr.push(l)
                        map.set(l.order, arr)
                        return map
                      }, new Map<number, LevelDto[]>()).entries(),
                    )
                      .sort(([a], [b]) => a - b)
                      .map(([order, group]) => (
                        <li key={order} className="flex items-start gap-2 text-xs">
                          <span className="mt-0.5 shrink-0 rounded-full bg-violet-100 px-2 py-0.5 font-mono text-[10px] font-bold text-violet-700">
                            Cấp {order}
                          </span>
                          <div className="flex-1 space-y-0.5">
                            {group.map(l => (
                              <div key={l.id} className="flex flex-wrap items-center gap-1.5">
                                <span className="font-medium text-slate-800">
                                  {l.approverUserName ?? l.approverUserId}
                                </span>
                                {l.approverEmail && (
                                  <span className="text-[10px] text-slate-400">({l.approverEmail})</span>
                                )}
                                {/* [S76] Badge quyền nhập/điều chỉnh ngân sách (hiển thị-only, suy từ role) */}
                                {l.canEditProBudget && (
                                  <span className="rounded bg-amber-100 px-1.5 py-0.5 text-[9px] font-semibold text-amber-700" title="Được nhập/điều chỉnh ngân sách cột PRO">✎ NS PRO</span>
                                )}
                                {l.canEditCcmBudget && (
                                  <span className="rounded bg-sky-100 px-1.5 py-0.5 text-[9px] font-semibold text-sky-700" title="Được nhập/điều chỉnh ngân sách cột CCM">✎ NS CCM</span>
                                )}
                              </div>
                            ))}
                          </div>
                        </li>
                      ))
                  )}
                </ul>
              </li>
            ))}
          </ol>
        </div>
        <div className="flex flex-col gap-1.5">
          <Button variant="outline" size="sm" onClick={() => onClone(def)}>
            <Plus className="h-3.5 w-3.5" />
            Tạo từ bản này
          </Button>
          {/* Mig 25 — toggle stick: cho user chọn quy trình này khi tạo phiếu */}
          <Button
            variant="outline"
            size="sm"
            onClick={onToggleSelectable}
            title={def.isUserSelectable ? 'Bỏ ghim — user sẽ không thấy quy trình này' : 'Ghim — user có thể chọn quy trình này'}
          >
            {def.isUserSelectable ? <PinOff className="h-3.5 w-3.5" /> : <Pin className="h-3.5 w-3.5" />}
            {def.isUserSelectable ? 'Bỏ ghim' : 'Ghim cho user'}
          </Button>
          <Button variant="outline" size="sm" onClick={onDelete}>
            <Trash2 className="h-3.5 w-3.5" />
            Xoá version
          </Button>
        </div>
      </div>
    </div>
  )
}

// ===== Designer dialog =====

function Designer({
  applicableType,
  applicableTypeLabel,
  cloneFrom,
  onClose,
  onSaved,
}: {
  applicableType: number
  applicableTypeLabel: string
  cloneFrom: DefinitionDto | null
  onClose: () => void
  onSaved: () => void
}) {
  const initialSteps: EditStep[] = useMemo(
    () => (cloneFrom ? copyFromDefinition(cloneFrom) : [makeEmptyStep(1)]),
    [cloneFrom],
  )

  const defaultCode = DEFAULT_CODE_BY_TYPE[applicableType] ?? 'QT-V2-001'
  const [code, setCode] = useState(cloneFrom?.code ?? defaultCode)
  const [name, setName] = useState(cloneFrom ? cloneFrom.name : `Quy trình ${applicableTypeLabel}`)
  const [description, setDescription] = useState(cloneFrom?.description ?? '')
  // S69 — Ngưỡng gói CEO (nullable). String form, '' = null. Clone giữ ngưỡng cũ.
  const [ceoThreshold, setCeoThreshold] = useState(
    cloneFrom?.ceoApprovalThreshold != null ? String(cloneFrom.ceoApprovalThreshold) : '',
  )
  const [steps, setSteps] = useState<EditStep[]>(initialSteps)

  // Mig 29 (S21 t5) + Mig 30 (S22+5) + Mig 31 (S23 t1) — 7 Allow* options
  // ALL xuống per Level slot (xem EditLevelEntry, render inline mỗi Level row).
  // Admin opt-in per-Approver-slot pattern proven 3× cumulative.

  const usersList = useQuery({
    queryKey: ['users-for-approver-v2'],
    queryFn: async () =>
      (await api.get<{ items: ApproverUser[] }>('/users', {
        params: { page: 1, pageSize: 500 },
      })).data.items,
  })

  const departmentsList = useQuery({
    queryKey: ['departments-list-v2'],
    queryFn: async () =>
      (await api.get<Paged<Department>>('/departments', { params: { page: 1, pageSize: 200 } })).data.items,
  })

  const save = useMutation({
    mutationFn: async () => {
      // Validate per Bước:
      //   - Phòng required
      //   - Cấp 1 phải có ≥1 NV (sequential gating đảm bảo nếu C1 empty thì C2/C3 cũng empty)
      //   - All approver thuộc đúng Phòng (defensive double-check)
      for (const s of steps) {
        if (!s.departmentId) {
          throw new Error(`Bước "${s.name}" chưa chọn Phòng.`)
        }
        if (entriesAtLevel(s, 1).length === 0) {
          throw new Error(`Bước "${s.name}" chưa có NV ở Cấp 1.`)
        }
        // Sequential gating đã enforce ở UI nhưng kiểm tra lại
        if (entriesAtLevel(s, 2).length === 0 && entriesAtLevel(s, 3).length > 0) {
          throw new Error(`Bước "${s.name}": Cấp 3 chỉ thao tác được khi Cấp 2 có NV.`)
        }
        for (const e of s.levelEntries) {
          if (!e.approverUserId) {
            throw new Error(`Bước "${s.name}": có dòng cấp chưa chọn NV.`)
          }
          const u = usersList.data?.find(x => x.id === e.approverUserId)
          if (u && u.departmentId !== s.departmentId) {
            throw new Error(`Bước "${s.name}": NV "${u.fullName}" không thuộc Phòng đã chọn.`)
          }
        }
      }
      await api.post('/approval-workflows-v2', {
        applicableType,
        code,
        name,
        description: description || null,
        // S69 — ngưỡng gói CEO: '' → null (không áp ngưỡng), else parse số.
        ceoApprovalThreshold: ceoThreshold.trim() === '' ? null : Number(ceoThreshold.replace(/[^\d]/g, '')),
        steps: steps.map((s, i) => ({
          order: i + 1,
          name: s.name,
          departmentId: s.departmentId,
          // Mỗi entry → 1 Level row. Multiple rows cùng Order = same Cấp với
          // N approvers (BE iterate group by Order).
          // Mig 29 (S21 t5) — 5 Allow* options per slot Approver.
          // Mig 30 (S22+5) — +AllowApproverEditBudget.
          // Mig 31 (S23 t1) — +AllowApproverSkipToFinal F2 storage swap per-slot.
          levels: s.levelEntries.map(e => ({
            order: e.order,
            name: `Cấp ${e.order}`,
            approverUserId: e.approverUserId,
            allowReturnOneLevel: e.allowReturnOneLevel,
            allowReturnOneStep: e.allowReturnOneStep,
            allowReturnToAssignee: e.allowReturnToAssignee,
            allowReturnToDrafter: e.allowReturnToDrafter,
            allowApproverEditDetails: e.allowApproverEditDetails,
            allowApproverEditBudget: e.allowApproverEditBudget,
            allowApproverSkipToFinal: e.allowApproverSkipToFinal,
            allowApproverFinalize: e.allowApproverFinalize,
          })),
        })),
      })
    },
    onSuccess: () => {
      toast.success('Đã lưu quy trình mới. Version cũ đã archive.')
      onSaved()
    },
    onError: err => toast.error(getErrorMessage(err)),
  })

  function submit(e: FormEvent) {
    e.preventDefault()
    if (steps.length === 0) {
      toast.error('Phải có ít nhất 1 bước')
      return
    }
    save.mutate()
  }

  function moveStep(idx: number, dir: -1 | 1) {
    const newIdx = idx + dir
    if (newIdx < 0 || newIdx >= steps.length) return
    const next = [...steps]
    ;[next[idx], next[newIdx]] = [next[newIdx], next[idx]]
    setSteps(next)
  }

  return (
    <Dialog
      open
      onClose={onClose}
      title={`Tạo quy trình mới — ${applicableTypeLabel}`}
      size="lg"
      footer={
        <>
          <Button variant="outline" onClick={onClose}>Hủy</Button>
          <Button onClick={submit} disabled={save.isPending} form="aw-v2-form">
            {save.isPending ? 'Đang lưu…' : 'Lưu + kích hoạt'}
          </Button>
        </>
      }
    >
      <form id="aw-v2-form" onSubmit={submit} className="space-y-4">
        <div className="grid grid-cols-2 gap-3">
          <div className="space-y-1.5">
            <Label>Mã quy trình *</Label>
            <Input value={code} onChange={e => setCode(e.target.value)} required className="font-mono" />
            <div className="text-[11px] text-slate-400">Vd QT-DN-V2-001. Version auto-tăng mỗi lần lưu.</div>
          </div>
          <div className="space-y-1.5">
            <Label>Tên hiển thị *</Label>
            <Input value={name} onChange={e => setName(e.target.value)} required />
          </div>
          <div className="col-span-2 space-y-1.5">
            <Label>Mô tả</Label>
            <Textarea rows={2} value={description} onChange={e => setDescription(e.target.value)} />
          </div>
          {/* S69 — Ngưỡng giá trị gói CEO (nullable). Empty = không áp ngưỡng. */}
          <div className="col-span-2 space-y-1.5">
            <Label>Ngưỡng giá trị gói CEO (đ)</Label>
            <Input
              inputMode="numeric"
              value={ceoThreshold === '' ? '' : Number(ceoThreshold.replace(/[^\d]/g, '')).toLocaleString('vi-VN')}
              onChange={e => setCeoThreshold(e.target.value.replace(/[^\d]/g, ''))}
              placeholder="Để trống = luôn theo đủ quy trình"
            />
            <div className="text-[11px] leading-relaxed text-slate-400">
              Gói &lt; ngưỡng: CCM duyệt là xong, không cần CEO. ≥ ngưỡng: phải lên CEO.
              Để trống = luôn theo đủ quy trình.
            </div>
          </div>
        </div>

        {/* Mig 29 (S21 t5) — 5 Allow* F1+F3 per slot Approver.
            Mig 30 (S22+5) — +AllowApproverEditBudget per slot.
            Mig 31 (S23 t1) — F2 storage swap Users→Level: per-Approver-slot.
            ALL Allow* options now configured PER NV trong slot Approver dưới đây. */}
        <div className="rounded-lg border border-violet-200 bg-violet-50/30 px-3 py-2 text-[11px] leading-relaxed text-violet-800">
          ⓘ Cấu hình quyền duyệt riêng cho từng NV trong slot Approver bên dưới
          (Trả lại / Edit Section 2 / Edit Budget / Duyệt thẳng Cấp cuối).
        </div>

        <div className="space-y-2 rounded-lg border border-slate-200 p-3">
          <div className="flex items-center justify-between">
            <Label>
              Các bước duyệt — mỗi bước = 1 Phòng × <span className="font-bold text-violet-700">tối đa {MAX_LEVELS_PER_STEP} cấp NV</span> ({steps.length} bước)
            </Label>
            <Button
              type="button"
              size="sm"
              variant="outline"
              onClick={() => setSteps([...steps, makeEmptyStep(steps.length + 1)])}
            >
              <Plus className="h-3.5 w-3.5" />
              Thêm bước
            </Button>
          </div>

          {steps.map((s, idx) => (
            <div key={idx} className="rounded-md border border-slate-200 bg-slate-50/40 p-3">
              <div className="flex items-start gap-2">
                <div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-brand-600 text-[11px] font-bold text-white">
                  {idx + 1}
                </div>
                <div className="grid flex-1 grid-cols-3 gap-2">
                  <div>
                    <Label className="text-[11px]">Tên bước</Label>
                    <Input
                      value={s.name}
                      onChange={e => setSteps(steps.map((x, i) => (i === idx ? { ...x, name: e.target.value } : x)))}
                      placeholder="Phòng A"
                    />
                  </div>
                  <div className="col-span-2">
                    <Label className="text-[11px]">Phòng * (chọn để filter NV duyệt)</Label>
                    <Select
                      value={s.departmentId ?? ''}
                      onChange={e => {
                        // Đổi Phòng → clear hết approvers vì NV cũ có thể không thuộc Phòng mới.
                        const newDeptId = e.target.value || null
                        setSteps(steps.map((x, i) => (i === idx
                          ? { ...x, departmentId: newDeptId, levelEntries: [] }
                          : x)))
                      }}
                      required
                    >
                      <option value="">— Chọn Phòng —</option>
                      {departmentsList.data?.map(d => (
                        <option key={d.id} value={d.id}>{d.name}</option>
                      ))}
                    </Select>
                  </div>
                </div>
                <div className="flex flex-col gap-0.5">
                  <button
                    type="button"
                    onClick={() => moveStep(idx, -1)}
                    disabled={idx === 0}
                    className="flex h-6 w-6 items-center justify-center rounded text-slate-400 hover:bg-slate-100 hover:text-slate-700 disabled:opacity-30"
                    title="Lên"
                  >
                    <ChevronUp className="h-3.5 w-3.5" />
                  </button>
                  <button
                    type="button"
                    onClick={() => moveStep(idx, 1)}
                    disabled={idx === steps.length - 1}
                    className="flex h-6 w-6 items-center justify-center rounded text-slate-400 hover:bg-slate-100 hover:text-slate-700 disabled:opacity-30"
                    title="Xuống"
                  >
                    <ChevronDown className="h-3.5 w-3.5" />
                  </button>
                  <button
                    type="button"
                    onClick={() => setSteps(steps.filter((_, i) => i !== idx))}
                    className="flex h-6 w-6 items-center justify-center rounded text-slate-400 hover:bg-red-50 hover:text-red-600"
                    title="Xóa bước"
                  >
                    <Trash2 className="h-3.5 w-3.5" />
                  </button>
                </div>
              </div>

              {/* Levels — 3 section cố định C1/C2/C3. Mỗi cấp có N NV.
                  Sequential gating: Cấp k chỉ active khi Cấp k-1 có ≥1 NV. */}
              <div className="mt-2 ml-9 space-y-2 border-l-2 border-violet-200 pl-3">
                {!s.departmentId && (
                  <div className="rounded bg-amber-50 px-2 py-1 text-[11px] font-medium text-amber-700">
                    ⚠ Chọn Phòng để bắt đầu cấu hình cấp duyệt.
                  </div>
                )}
                {s.departmentId && usersForDept(usersList.data, s.departmentId).length === 0 && (
                  <div className="rounded border border-dashed border-amber-300 bg-amber-50 px-2 py-1.5 text-[11px] italic text-amber-700">
                    ⚠ Phòng này chưa có nhân viên. Vào /system/users gán NV vào Phòng trước, sau đó quay lại.
                  </div>
                )}

                {LEVEL_ORDERS.map(order => {
                  const entries = entriesAtLevel(s, order)
                  const enabled = isLevelEnabled(s, order)
                  const filteredUsers = usersForDept(usersList.data, s.departmentId)
                  // NV còn khả dụng (chưa được dùng ở cấp này — cùng cấp không trùng NV)
                  const usedInThisLevel = new Set(entries.map(e => e.approverUserId))
                  const availableUsers = filteredUsers.filter(u => !usedInThisLevel.has(u.id))

                  // Disable Add: Phòng chưa chọn / cấp trước chưa có NV / hết NV available
                  const addDisabled = !enabled || availableUsers.length === 0

                  return (
                    <div
                      key={order}
                      className={`rounded-md border p-2 ${
                        enabled
                          ? 'border-violet-200 bg-white'
                          : 'border-slate-200 bg-slate-50/50 opacity-60'
                      }`}
                    >
                      <div className="flex items-center justify-between">
                        <div className="flex items-center gap-2">
                          <span className="rounded-full bg-violet-100 px-2 py-0.5 font-mono text-[10px] font-bold text-violet-700">
                            Cấp {order}
                          </span>
                          <span className="text-[11px] text-slate-500">
                            {entries.length === 0
                              ? (enabled ? 'Chưa có NV' : `Hoàn tất Cấp ${order - 1} trước`)
                              : `${entries.length} NV duyệt`}
                          </span>
                        </div>
                        <button
                          type="button"
                          disabled={addDisabled}
                          onClick={() => {
                            if (availableUsers.length === 0) return
                            const firstUser = availableUsers[0]
                            setSteps(steps.map((x, i) =>
                              i === idx
                                ? { ...x, levelEntries: [...x.levelEntries, makeDefaultLevelEntry(order, firstUser.id)] }
                                : x,
                            ))
                          }}
                          className="rounded bg-violet-50 px-2 py-1 text-[11px] font-medium text-violet-700 hover:bg-violet-100 disabled:cursor-not-allowed disabled:opacity-40"
                          title={
                            !enabled
                              ? `Cấp ${order - 1} phải có ≥1 NV trước`
                              : availableUsers.length === 0
                                ? 'Hết NV khả dụng (đã thêm hết hoặc Phòng không còn NV)'
                                : 'Thêm NV duyệt vào cấp này'
                          }
                        >
                          + Thêm NV
                        </button>
                      </div>

                      {entries.length > 0 && (
                        <div className="mt-1.5 space-y-1">
                          {entries.map((entry, ei) => {
                            // Tính index trong levelEntries gốc để update
                            const globalIdx = s.levelEntries.findIndex(
                              x => x === entry,
                            )
                            // NV available cho dropdown: filtered + chính NV đang chọn (giữ option hiện tại)
                            const dropdownUsers = filteredUsers.filter(
                              u => u.id === entry.approverUserId || !usedInThisLevel.has(u.id),
                            )
                            return (
                              <div key={ei} className="flex items-center gap-1.5">
                                <span className="text-[10px] text-slate-400">#{ei + 1}</span>
                                <Select
                                  value={entry.approverUserId}
                                  onChange={e => {
                                    const newId = e.target.value
                                    setSteps(steps.map((x, i) =>
                                      i === idx
                                        ? {
                                            ...x,
                                            levelEntries: x.levelEntries.map((y, j) =>
                                              j === globalIdx ? { ...y, approverUserId: newId } : y,
                                            ),
                                          }
                                        : x,
                                    ))
                                  }}
                                  className="h-7 flex-1 text-xs"
                                >
                                  {dropdownUsers.map(u => (
                                    <option key={u.id} value={u.id}>
                                      {u.fullName} ({u.email})
                                    </option>
                                  ))}
                                </Select>
                                <button
                                  type="button"
                                  onClick={() => {
                                    // Chặn xóa NV cuối Cấp 1 nếu Cấp 2/3 còn entries (gating)
                                    if (entries.length === 1) {
                                      const nextLevelHasEntries =
                                        order < MAX_LEVELS_PER_STEP &&
                                        entriesAtLevel(s, (order + 1) as LevelOrder).length > 0
                                      if (nextLevelHasEntries) {
                                        toast.error(
                                          `Hãy xóa hết NV ở Cấp ${order + 1} trước khi rỗng Cấp ${order}.`,
                                        )
                                        return
                                      }
                                    }
                                    setSteps(steps.map((x, i) =>
                                      i === idx
                                        ? { ...x, levelEntries: x.levelEntries.filter((_, j) => j !== globalIdx) }
                                        : x,
                                    ))
                                  }}
                                  className="flex h-6 w-6 items-center justify-center rounded text-slate-400 hover:bg-red-50 hover:text-red-600"
                                  title="Xóa NV khỏi cấp này"
                                >
                                  <Trash2 className="h-3 w-3" />
                                </button>
                              </div>
                            )
                          })}
                          {/* Mig 29 (S21 t5) — 5 Allow* checkbox inline cho mỗi
                              NV entry. Mặc định AllowReturnToDrafter=true (S17
                              backward compat). Admin tick mở mode khác per slot. */}
                          {entries.map((entry, ei) => {
                            const globalIdx = s.levelEntries.findIndex(x => x === entry)
                            const updateField = (field: keyof EditLevelEntry, value: boolean) => {
                              setSteps(steps.map((x, i) =>
                                i === idx
                                  ? {
                                      ...x,
                                      levelEntries: x.levelEntries.map((y, j) =>
                                        j === globalIdx ? { ...y, [field]: value } : y,
                                      ),
                                    }
                                  : x,
                              ))
                            }
                            return (
                              <div
                                key={`opts-${ei}`}
                                className="ml-4 mt-1 rounded border border-amber-100 bg-amber-50/30 px-2 py-1.5"
                              >
                                <div className="mb-1 text-[10px] font-medium uppercase text-amber-700">
                                  Quyền duyệt {usersList.data?.find(u => u.id === entry.approverUserId)?.fullName ?? 'Chưa chọn NV'}
                                </div>
                                <div className="grid grid-cols-2 gap-1">
                                  <label className="flex items-center gap-1 text-[11px] text-slate-700">
                                    <input
                                      type="checkbox"
                                      className="h-3 w-3"
                                      checked={entry.allowReturnOneLevel}
                                      onChange={e => updateField('allowReturnOneLevel', e.target.checked)}
                                    />
                                    <span>Trả về 1 Cấp trước</span>
                                  </label>
                                  <label className="flex items-center gap-1 text-[11px] text-slate-700">
                                    <input
                                      type="checkbox"
                                      className="h-3 w-3"
                                      checked={entry.allowReturnOneStep}
                                      onChange={e => updateField('allowReturnOneStep', e.target.checked)}
                                    />
                                    <span>Trả về 1 Bước trước</span>
                                  </label>
                                  <label className="flex items-center gap-1 text-[11px] text-slate-700">
                                    <input
                                      type="checkbox"
                                      className="h-3 w-3"
                                      checked={entry.allowReturnToAssignee}
                                      onChange={e => updateField('allowReturnToAssignee', e.target.checked)}
                                    />
                                    <span>Trả về Người chỉ định</span>
                                  </label>
                                  <label className="flex items-center gap-1 text-[11px] text-slate-700">
                                    <input
                                      type="checkbox"
                                      className="h-3 w-3"
                                      checked={entry.allowReturnToDrafter}
                                      onChange={e => updateField('allowReturnToDrafter', e.target.checked)}
                                    />
                                    <span>Trả về Drafter (mặc định)</span>
                                  </label>
                                  <label className="col-span-2 flex items-center gap-1 text-[11px] text-slate-700">
                                    <input
                                      type="checkbox"
                                      className="h-3 w-3"
                                      checked={entry.allowApproverEditDetails}
                                      onChange={e => updateField('allowApproverEditDetails', e.target.checked)}
                                    />
                                    <span>Cho phép chỉnh sửa Section 2 (Hạng mục/NCC/Báo giá) lúc đang duyệt</span>
                                  </label>
                                  <label className="col-span-2 flex items-center gap-1 text-[11px] text-slate-700">
                                    <input
                                      type="checkbox"
                                      className="h-3 w-3"
                                      checked={entry.allowApproverEditBudget}
                                      onChange={e => updateField('allowApproverEditBudget', e.target.checked)}
                                    />
                                    <span>Cho phép chỉnh sửa Section ngân sách lúc đang duyệt</span>
                                  </label>
                                  {/* Mig 31 (S23 t1) — F2 AllowApproverSkipToFinal admin opt-in per-slot.
                                      Approver tick = skip thẳng Cấp cuối khi đang ChoDuyet. */}
                                  <label className="col-span-2 flex items-center gap-1 text-[11px] text-slate-700">
                                    <input
                                      type="checkbox"
                                      className="h-3 w-3"
                                      checked={entry.allowApproverSkipToFinal}
                                      onChange={e => updateField('allowApproverSkipToFinal', e.target.checked)}
                                    />
                                    <span>Cho phép duyệt thẳng Cấp cuối khi đang duyệt</span>
                                  </label>
                                  {/* [Mig 58 CCM item 4 — anh Kiệt FDC] Duyệt là KẾT THÚC: NV slot
                                      này duyệt xong → DaDuyet luôn, KHÔNG trình tiếp CEO (vd Cấp anh Chương). */}
                                  <label className="col-span-2 flex items-center gap-1 text-[11px] text-emerald-700">
                                    <input
                                      type="checkbox"
                                      className="h-3 w-3"
                                      checked={entry.allowApproverFinalize}
                                      onChange={e => updateField('allowApproverFinalize', e.target.checked)}
                                    />
                                    <span>Duyệt là KẾT THÚC quy trình (không trình tiếp CEO)</span>
                                  </label>
                                </div>
                              </div>
                            )
                          })}
                        </div>
                      )}
                    </div>
                  )
                })}
              </div>
            </div>
          ))}
        </div>

        <div className="flex items-start gap-2 rounded-md border border-blue-200 bg-blue-50 px-3 py-2 text-xs text-blue-800">
          <GitBranch className="mt-0.5 h-3.5 w-3.5 shrink-0" />
          <div>
            Quy tắc: mỗi Bước có 1 Phòng + tối đa {MAX_LEVELS_PER_STEP} Cấp. Quy trình chạy theo số cấp thật sự có
            (1 / 2 / 3 cấp đều OK). Trong cùng 1 Cấp có thể có nhiều NV — chỉ cần 1 NV duyệt là cấp đó pass
            (OR-of-N). Tuần tự: Cấp 1 → Cấp 2 → Cấp 3 → Bước kế. Hết tất cả Bước = Đã duyệt.
          </div>
        </div>
      </form>
    </Dialog>
  )
}
