// ELS HRM — Module 10: Quản Lý Ứng Viên (Candidate) — All Screens — Tailwind utility classes

// shadcn table styling reproduced via arbitrary child variants (1 className, structure untouched)
const TABLE_CLS = "w-full border-collapse text-sm "
  + "[&_thead_th]:border-b [&_thead_th]:border-border [&_thead_th]:bg-muted [&_thead_th]:px-3.5 [&_thead_th]:py-2.5 [&_thead_th]:text-left [&_thead_th]:text-xs [&_thead_th]:font-semibold [&_thead_th]:uppercase [&_thead_th]:tracking-[0.04em] [&_thead_th]:text-muted-foreground [&_thead_th]:whitespace-nowrap "
  + "[&_tbody_td]:border-b [&_tbody_td]:border-border [&_tbody_td]:px-3.5 [&_tbody_td]:py-3 [&_tbody_td]:align-middle [&_tbody_td]:text-foreground "
  + "[&_tbody_tr:last-child_td]:border-0 [&_tbody_tr:hover]:bg-muted";

const CARD = "rounded-xl border border-border bg-card shadow-xs";
const INPUT = "h-9 w-full rounded-md border border-input bg-transparent px-3 text-base text-foreground shadow-xs placeholder:text-muted-foreground transition-colors focus:border-primary focus:outline-none focus:ring-[3px] focus:ring-ring";
const INPUT_SM = "h-8 w-full rounded-md border border-input bg-transparent px-3 text-xs text-foreground shadow-xs placeholder:text-muted-foreground transition-colors focus:border-primary focus:outline-none focus:ring-[3px] focus:ring-ring";
const FIELD_LABEL = "mb-[5px] block text-xs font-medium text-foreground";

// Hạn mức tệp của ỨNG VIÊN — 5 MB mỗi tệp, tổng 20 MB. Luồng tệp của tin tuyển dụng và của buổi
// phỏng vấn có con số KHÁC, gấp đôi và gấp đôi rưỡi (xem `VAC_FILE_LIMIT` ở vacancy-screens.jsx và
// `INT_FILE_LIMIT` ở interview-screens.jsx). Mỗi màn phải in đúng con số của luồng mình: bản trước
// in nhầm con số của luồng kia vào form này, người dùng chọn CV 8 MB, đọc dòng chữ thấy bảo được,
// tải lên rồi mới bị từ chối (quyết định R2-30 · srs/09_recruitment/23_candidate-attachments.md).
const CAN_FILE_LIMIT = { perFile:'5MB', total:'20MB' };

// Mỗi dòng là một ĐƠN ỨNG TUYỂN (ứng viên + vị trí) — trạng thái nằm ở đơn, không ở hồ sơ
// ứng viên (srs/09_recruitment/01_shared.md §1). Vì thế bản ghi mang HAI mã: `appId` của đơn và
// `candId` của người. Ba trường của bản trước đã bỏ khỏi v1: `status` ở cấp hồ sơ, `mode` (v1 chỉ
// còn một đường vào là nhập tay) và `keywords` (chấm điểm phù hợp + tìm toàn văn đều đã cắt) —
// srs/09_recruitment/20_candidate-profile.md §2.
//
// C003 và C009 là CÙNG MỘT NGƯỜI (Phạm Minh Đức) nộp hai đơn ở hai vị trí, hai trạng thái khác
// nhau. Bản trước tám bản ghi là tám người khác nhau nên bản vẽ không chứng minh được năng lực
// lõi của mô hình một-người-nhiều-đơn (audit vấn đề 28).
const CAN_LIST = [
  { appId:'A001', candId:'C001', name:'Nguyễn Văn Bảo',    email:'bao.nv@gmail.com',    phone:'+84 912 345 678', vacancy:'Senior Backend Engineer', status:'INTERVIEW_SCHEDULED', applied:'02/05/2026' },
  { appId:'A002', candId:'C002', name:'Trần Thị Cẩm Tú',  email:'camtu.tt@gmail.com',  phone:'+84 908 234 567', vacancy:'Senior Backend Engineer', status:'SHORTLISTED',          applied:'05/05/2026' },
  { appId:'A003', candId:'C003', name:'Phạm Minh Đức',    email:'duc.pm@outlook.com',   phone:'+84 923 456 789', vacancy:'Frontend Developer',      status:'APPLICATION_INITIATED',applied:'10/05/2026' },
  { appId:'A004', candId:'C004', name:'Lê Hoàng Nam',     email:'hoangnam@hotmail.com', phone:'+84 934 567 890', vacancy:'HR Business Partner',     status:'INTERVIEW_PASSED',     applied:'28/04/2026' },
  { appId:'A005', candId:'C005', name:'Võ Thị Mỹ Linh',  email:'mylinh.vo@gmail.com',  phone:'+84 945 678 901', vacancy:'DevOps Engineer',         status:'REJECTED',             applied:'15/04/2026' },
  { appId:'A006', candId:'C006', name:'Đỗ Quang Huy',    email:'huy.do@gmail.com',     phone:'+84 956 789 012', vacancy:'Frontend Developer',      status:'JOB_OFFERED',          applied:'01/05/2026' },
  { appId:'A007', candId:'C007', name:'Bùi Thị Thu Hằng',email:'thuhang.bt@yahoo.com', phone:'+84 967 890 123', vacancy:'Senior Backend Engineer', status:'HIRED',                applied:'20/04/2026' },
  { appId:'A008', candId:'C008', name:'Ngô Thanh Tùng',  email:'tung.ngo@gmail.com',   phone:'+84 978 901 234', vacancy:'DevOps Engineer',         status:'WITHDRAWN',            applied:'18/04/2026' },
  { appId:'A009', candId:'C003', name:'Phạm Minh Đức',    email:'duc.pm@outlook.com',   phone:'+84 923 456 789', vacancy:'DevOps Engineer',         status:'SHORTLISTED',          applied:'12/05/2026' },
];

// Chữ hiển thị của từng chặng CHÉP TỪ cột «Nhãn hiển thị» của `srs/09_recruitment/01_shared.md`
// §1 — đó mới là nguồn duy nhất, bản vẽ chỉ là bản sao. Mỗi mã có ĐÚNG MỘT nhãn nghiệp vụ; bản
// trước tự đặt bộ chữ thứ hai ngắn hơn ("Nộp đơn" / "Qua PV" / "Rút đơn") nên cùng một chặng có
// tới bốn cái tên giữa đặc tả, bản vẽ và nguyên mẫu (audit vấn đề 44, quyết định R2-44).
//
// `short` chỉ dùng cho chip phễu — chỗ đó có sáu cột nên nhãn dài nhất bị xuống dòng ba lần và
// vỡ hàng. Đây là RÚT GỌN vì chật chỗ, không phải tên thứ hai: mọi chỗ còn lại đọc `label`.
const CAN_ST = {
  APPLICATION_INITIATED:{ label:'Đã nộp đơn',            v:'neutral', icon:'inbox'        },
  SHORTLISTED:          { label:'Đã sàng lọc',           v:'info',    icon:'star'         },
  REJECTED:             { label:'Bị từ chối',            v:'danger',  icon:'x-circle'     },
  INTERVIEW_SCHEDULED:  { label:'Đã lên lịch phỏng vấn', v:'warning', icon:'calendar',    short:'Đã lên lịch PV' },
  INTERVIEW_PASSED:     { label:'Đạt phỏng vấn',         v:'success', icon:'check-circle' },
  INTERVIEW_FAILED:     { label:'Trượt phỏng vấn',       v:'danger',  icon:'x-circle'     },
  JOB_OFFERED:          { label:'Đã gửi lời mời',        v:'primary', icon:'gift'         },
  OFFER_DECLINED:       { label:'Từ chối lời mời',       v:'danger',  icon:'x'            },
  HIRED:                { label:'Đã tuyển',              v:'success', icon:'award'        },
  // Đơn ngừng xét KHÔNG vì đánh giá năng lực — tông trung tính, tách hẳn khỏi 'Bị từ chối'.
  WITHDRAWN:            { label:'Ngừng xét',             v:'neutral', icon:'x'            },
};

// Năm thao tác dưới đây BẮT BUỘC nhập lý do, mỗi thao tác một mã lỗi riêng — tức năm luật độc
// lập, không phải một câu chung (quyết định R2-26). Hộp thoại là MỘT mẫu dùng lại: tiêu đề đổi
// theo thao tác, bên trong là ô chọn lý do (với thao tác có danh sách cố định) cộng một ô ghi
// chú BẮT BUỘC.
const REASON_ACTIONS = {
  REJECT_CANDIDATE: { title:'Từ chối ứng viên',            options:null },
  INTERVIEW_FAILED: { title:'Ghi kết quả trượt phỏng vấn', options:null },
  OFFER_DECLINED:   { title:'Ứng viên từ chối lời mời',    options:null },
  WITHDRAW:         { title:'Ngừng xét đơn',               options:['Ứng viên tự rút','Đã nhận việc chỗ khác','Tin tuyển dụng đã đóng'] },
  CANCEL_INTERVIEW: { title:'Hủy buổi phỏng vấn',          options:null },
};

const PIPELINE_STAGES = [
  { key:'APPLICATION_INITIATED', count:3, color:'var(--color-muted-foreground)' },
  { key:'SHORTLISTED',           count:3, color:'var(--color-info)'             },
  { key:'INTERVIEW_SCHEDULED',   count:1, color:'var(--color-warning)'          },
  { key:'INTERVIEW_PASSED',      count:1, color:'var(--color-primary)'          },
  { key:'JOB_OFFERED',           count:1, color:'var(--color-success)'          },
  { key:'HIRED',                 count:1, color:'var(--color-success)'          },
];

// ─── 01: Candidate Pipeline / List ────────────────────────────────────────────
const CandListScreen = ({ dark=false }) => (
  <HRMShell active="candidates" dark={dark}
    title="Quản lý ứng viên"
    crumbs={['Ứng viên']}
    meta="139 đơn ứng tuyển · 7 vị trí đang tuyển"
    actions={<>
      <Btn variant="outline" size="sm" icon="download">Xuất danh sách</Btn>
      <Btn variant="primary"  size="sm" icon="plus">Thêm ứng viên</Btn>
    </>}>

    {/* Pipeline overview — đếm ĐƠN, không đếm người */}
    <div className={CARD + " mb-4 px-5 py-4"}>
      <div className="mb-3.5 text-sm font-bold">Tổng quan pipeline tuyển dụng</div>
      <div className="relative flex items-stretch">
        {PIPELINE_STAGES.map((s, i)=>{
          const isLast = i===PIPELINE_STAGES.length-1;
          return (
            <React.Fragment key={s.key}>
              <div className="flex-1 px-1.5 py-2.5 text-center">
                <div className="mb-1 text-3xl font-extrabold leading-none" style={{ color:s.color }}>{s.count}</div>
                <div className="text-xs leading-[1.3] text-muted-foreground">{CAN_ST[s.key].short || CAN_ST[s.key].label}</div>
              </div>
              {!isLast && (
                <div className="flex shrink-0 items-center text-border-strong">
                  <Icon name="chevron-right" size={16} />
                </div>
              )}
            </React.Fragment>
          );
        })}
      </div>
    </div>

    {/* Filter */}
    <div className={CARD + " mb-3.5 flex items-center gap-2.5 px-3.5 py-2.5"}>
      <div className="relative flex w-[240px] items-center">
        <Icon name="search" size={13} className="pointer-events-none absolute left-2.5 size-3.5 text-muted-foreground" />
        <input className={INPUT_SM + " pl-8"} placeholder="Tìm ứng viên theo tên, email..." />
      </div>
      <Select className="h-8 text-xs w-40 cursor-pointer"
        options={['Tất cả vị trí', 'Senior Backend Engineer', 'Frontend Developer', 'DevOps Engineer']}
        defaultValue="Tất cả vị trí" />
      <Select className="h-8 text-xs w-[148px] cursor-pointer"
        options={['Tất cả giai đoạn', ...Object.values(CAN_ST).map(v=>v.label)]}
        defaultValue="Tất cả giai đoạn" />
      {/* Xoá hồ sơ ứng viên là xoá MỀM và KHÔI PHỤC ĐƯỢC (R2-18) — nên phải có đường nhìn thấy
          hồ sơ đã xoá. Ô lọc này chỉ hiện với người có quyền quản lý tuyển dụng. */}
      <Select className="h-8 text-xs w-[152px] cursor-pointer"
        options={['Hồ sơ đang hoạt động','Hồ sơ đã xóa','Tất cả']}
        defaultValue="Hồ sơ đang hoạt động" />
      <Btn variant="outline" size="sm" icon="filter">Lọc</Btn>
      <div className="flex-1" />
      <span className="text-xs text-muted-foreground">9 đơn ứng tuyển · 8 ứng viên</span>
    </div>

    {/* Table */}
    <div className="overflow-hidden rounded-lg border border-border bg-card">
      <table className={TABLE_CLS}>
        <thead>
          <tr>
            <th style={{ width:40 }}><input type="checkbox" /></th>
            <th>Ứng viên</th>
            <th>Vị trí ứng tuyển</th>
            <th>Giai đoạn của đơn</th>
            <th>Ngày nộp</th>
            <th>Thao tác</th>
          </tr>
        </thead>
        <tbody>
          {CAN_LIST.map(c=>{
            const st=CAN_ST[c.status];
            const multi = CAN_LIST.filter(x=>x.candId===c.candId).length > 1;
            return (
              <tr key={c.appId}>
                <td><input type="checkbox" /></td>
                <td>
                  <div className="flex items-center gap-2.5">
                    <Avatar name={c.name} />
                    <div>
                      <div className="flex items-center gap-1.5">
                        <span className="font-medium text-foreground">{c.name}</span>
                        {/* Cùng một người nộp nhiều đơn — nói rõ ra, đừng để người đọc tưởng trùng dữ liệu */}
                        {multi && <Badge variant="neutral">2 đơn</Badge>}
                      </div>
                      <div className="text-xs text-muted-foreground">{c.email}</div>
                    </div>
                  </div>
                </td>
                <td className="max-w-[200px] text-sm">
                  <div className="overflow-hidden text-ellipsis whitespace-nowrap">{c.vacancy}</div>
                </td>
                <td><Badge variant={st.v} dot>{st.label}</Badge></td>
                <td className="text-xs text-muted-foreground">{c.applied}</td>
                <td>
                  <div className="flex gap-[3px]">
                    <Btn variant="ghost" size="sm" iconOnly icon="eye" />
                    <Btn variant="ghost" size="sm" iconOnly icon="calendar" />
                  </div>
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>

    {/* Hồ sơ đã xoá mềm: hiện khi chọn ô lọc tương ứng, kèm đường khôi phục (R2-18) */}
    <div className="mt-3.5 rounded-xl border border-dashed border-border-strong bg-muted px-4 py-3">
      <div className="mb-2 flex items-center gap-2 text-xs font-semibold text-muted-foreground">
        <Icon name="trash" size={13} />
        Hồ sơ đã xóa — chọn «Hồ sơ đã xóa» ở ô lọc để xem
      </div>
      <div className="flex items-center gap-3">
        <Avatar name="Trịnh Bảo Long" size="sm" />
        <div className="flex-1">
          <div className="text-sm font-medium">Trịnh Bảo Long</div>
          <div className="text-xs text-muted-foreground">baolong.tb@gmail.com · xóa ngày 08/05/2026 bởi Nguyễn Thị Lan</div>
        </div>
        <Btn variant="outline" size="xs" icon="check-circle">Khôi phục</Btn>
      </div>
    </div>
  </HRMShell>
);

// ─── 02: Candidate Detail ─────────────────────────────────────────────────────
// HỒ SƠ ỨNG VIÊN KHÔNG CÓ TRẠNG THÁI TỔNG HỢP. Huy hiệu trạng thái và thanh tiến trình nằm ở
// TỪNG ĐƠN, trong tab «Đơn ứng tuyển» — một người có hai đơn ở hai chặng khác nhau thì không có
// con số nào gộp chung được (quyết định R2-28).
//
// Hai tầng lọc trên cùng màn (quyết định R2-03): phần hồ sơ cá nhân hiện ĐẦY ĐỦ cho mọi người
// xem được màn này; còn danh sách đơn, lịch sử chặng và buổi phỏng vấn chỉ hiện phần thuộc phạm
// vi dữ liệu của người đang xem.
const CandDetailScreen = ({ consentWithdrawn=false }) => {
  const c = CAN_LIST[2]; // Phạm Minh Đức — người có HAI đơn
  const apps = CAN_LIST.filter(x=>x.candId===c.candId);
  const [tab, setTab] = React.useState('applications');
  const [selectedApp, setSelectedApp] = React.useState(apps[0].appId);
  const app = apps.find(a=>a.appId===selectedApp) || apps[0];
  return (
    <HRMShell active="candidates"
      title={c.name}
      crumbs={['Ứng viên', c.name]}
      meta={`${apps.length} đơn ứng tuyển`}
      actions={<>
        {/* Thao tác cấp HỒ SƠ. Thao tác đổi chặng là cấp ĐƠN nên nằm trong tab Đơn ứng tuyển. */}
        <Btn variant="outline" size="sm" icon="edit">Sửa hồ sơ</Btn>
        <Btn variant="outline" size="sm" icon="lock">Ẩn danh hóa</Btn>
        <Btn variant="destructive" size="sm" icon="trash">Xóa hồ sơ</Btn>
      </>}>

      {/* Dải cảnh báo rút đồng ý — KHÔNG chặn các thao tác khác, vì xử lý yêu cầu gỡ dữ liệu cần
          thời gian và có thể còn việc dở dang (quyết định R2-23). */}
      {consentWithdrawn && (
        <div className="mb-4 flex items-start gap-3 rounded-xl border border-destructive bg-destructive-soft px-4 py-3">
          <Icon name="alert-triangle" size={16} className="mt-0.5 shrink-0 text-destructive" />
          <div className="flex-1 text-xs leading-[1.55] text-destructive">
            <strong>Ứng viên đã rút đồng ý lưu trữ dữ liệu ngày 14/05/2026.</strong> Cần ẩn danh hóa hồ sơ sau khi hoàn tất các việc còn dở. Sau khi ẩn danh hóa, họ tên và thông tin liên hệ sẽ bị thay bằng dữ liệu vô danh và <strong>không khôi phục được</strong>.
          </div>
          <Btn variant="destructive" size="sm" icon="lock">Ẩn danh hóa ngay</Btn>
        </div>
      )}

      {/* Từng bị từ chối trước đây thì phải nói ra — hiện ở MỌI hồ sơ từng bị từ chối (R2-26) */}
      <div className="mb-4 flex items-start gap-3 rounded-xl border border-warning bg-warning-soft px-4 py-3">
        <Icon name="info" size={16} className="mt-0.5 shrink-0" style={{ color:'oklch(0.45 0.1 65)' }} />
        <div className="flex-1 text-xs leading-[1.55]" style={{ color:'oklch(0.35 0.1 65)' }}>
          Ứng viên này từng bị từ chối cho <strong>Backend Engineer (Junior)</strong> ngày <strong>18/12/2025</strong>. Lý do: <em>«Kinh nghiệm chưa đủ cho yêu cầu vị trí, đề nghị xem lại sau 12 tháng.»</em>
        </div>
        <Btn variant="outline" size="xs">Xem đủ 2 lần trước</Btn>
      </div>

      <div className="grid grid-cols-[260px_1fr] gap-4">
        {/* Left — chỉ thông tin CẤP HỒ SƠ, không có trạng thái, không có thanh tiến trình */}
        <div className="flex flex-col gap-3">
          <div className={CARD + " p-5"}>
            <div className="mb-3.5 border-b border-border pb-4 text-center">
              <div className="mb-2.5 flex justify-center">
                <Avatar name={c.name} size="xl" />
              </div>
              <div className="mb-[3px] text-md font-bold">{c.name}</div>
              <div className="text-xs text-muted-foreground">{apps.length} đơn ứng tuyển đang theo dõi</div>
            </div>
            {[
              { icon:'mail',     label:'Email',    val:c.email     },
              { icon:'phone',    label:'SĐT',      val:c.phone     },
              { icon:'calendar', label:'Đơn đầu tiên', val:'10/05/2026' },
              { icon:'globe',    label:'Ngôn ngữ liên hệ', val:'Tiếng Việt' },
            ].map((f,i)=>(
              <div key={i} className="mb-[9px] flex gap-[9px]">
                <Icon name={f.icon} size={13} className="mt-0.5 shrink-0 text-muted-foreground" />
                <div>
                  <div className="text-xs text-muted-foreground">{f.label}</div>
                  <div className="break-all text-xs font-medium">{f.val}</div>
                </div>
              </div>
            ))}
          </div>

          {/* Khu «Đồng ý lưu trữ dữ liệu» — là Ô ĐIỀU KHIỂN, không phải một dòng chữ chết trong
              bảng thông tin như bản trước (audit vấn đề 23). */}
          <div className={CARD + " p-4"}>
            <div className="mb-2.5 text-xs font-bold">Đồng ý lưu trữ dữ liệu</div>
            <div className="mb-2.5 flex items-center gap-2.5">
              <div className={"relative h-5 w-9 shrink-0 rounded-full " + (consentWithdrawn ? "bg-border-strong" : "bg-primary")}>
                <div className={"absolute top-0.5 size-4 rounded-full bg-white shadow-xs " + (consentWithdrawn ? "left-0.5" : "left-[18px]")} />
              </div>
              <div className="text-sm font-medium">{consentWithdrawn ? 'Đã rút đồng ý' : 'Đang đồng ý'}</div>
            </div>
            <div className="mb-3 text-xs leading-[1.5] text-muted-foreground">
              {consentWithdrawn
                ? 'Rút ngày 14/05/2026. Dữ liệu vẫn còn trên hệ thống cho tới khi được ẩn danh hóa.'
                : 'Đồng ý ngày 10/05/2026 khi hồ sơ được nhập vào hệ thống.'}
            </div>
            <Btn variant="outline" size="xs" icon="lock">Ẩn danh hóa hồ sơ</Btn>
          </div>
        </div>

        {/* Right tabs */}
        <div className={CARD + " overflow-hidden"}>
          <div className="flex gap-1 border-b border-border px-5">
            {[
              { id:'applications', label:`Đơn ứng tuyển (${apps.length})` },
              { id:'profile',      label:'Hồ sơ'         },
              { id:'interviews',   label:'Phỏng vấn (1)' },
              { id:'notes',        label:'Ghi chú'       },
              { id:'history',      label:'Lịch sử'       },
            ].map(t=>(
              <div key={t.id} className={"-mb-px cursor-pointer border-b-2 px-3.5 py-3 text-sm font-medium " + (tab===t.id?'border-primary text-primary':'border-transparent text-muted-foreground hover:text-foreground')} onClick={()=>setTab(t.id)}>
                {t.label}
              </div>
            ))}
          </div>
          <div className="p-[22px]">
            {tab==='applications' && (
              <div>
                <div className="mb-2.5 text-xs leading-[1.5] text-muted-foreground">
                  Danh sách chỉ hiện những đơn thuộc phạm vi dữ liệu của bạn. Hồ sơ cá nhân bên trái thì hiện đầy đủ.
                </div>
                <table className={TABLE_CLS + " mb-[18px]"}>
                  <thead>
                    <tr>
                      <th>Vị trí ứng tuyển</th>
                      <th>Trạng thái</th>
                      <th>Ngày nộp</th>
                      <th>Thao tác</th>
                    </tr>
                  </thead>
                  <tbody>
                    {apps.map(a=>{
                      const st = CAN_ST[a.status];
                      return (
                        <tr key={a.appId} className={a.appId===selectedApp ? "bg-muted" : ""} onClick={()=>setSelectedApp(a.appId)}>
                          <td>
                            <div className="text-sm font-medium">{a.vacancy}</div>
                            <div className="text-xs text-muted-foreground">Mã đơn {a.appId}</div>
                          </td>
                          <td><Badge variant={st.v} dot>{st.label}</Badge></td>
                          <td className="text-xs text-muted-foreground">{a.applied}</td>
                          <td>
                            <div className="flex gap-[3px]">
                              <Btn variant="ghost" size="sm" iconOnly icon="eye" />
                              <Btn variant="ghost" size="sm" iconOnly icon="more-vertical" />
                            </div>
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>

                {/* Đơn đang chọn: thanh tiến trình + ĐỦ bộ thao tác cấp đơn */}
                <div className="rounded-md border border-border p-4">
                  <div className="mb-3.5 flex items-center justify-between">
                    <div>
                      <div className="text-sm font-bold">{app.vacancy}</div>
                      <div className="text-xs text-muted-foreground">Mã đơn {app.appId} · nộp {app.applied}</div>
                    </div>
                    <Badge variant={CAN_ST[app.status].v} dot>{CAN_ST[app.status].label}</Badge>
                  </div>

                  {/* Thanh tiến trình thuộc về ĐƠN, không thuộc hồ sơ */}
                  <div className="mb-4 flex items-stretch">
                    {[
                      { key:'APPLICATION_INITIATED', done:true,  date:'10/05' },
                      { key:'SHORTLISTED',           done:false, date:null    },
                      { key:'INTERVIEW_SCHEDULED',   done:false, date:null    },
                      { key:'JOB_OFFERED',           done:false, date:null    },
                      { key:'HIRED',                 done:false, date:null    },
                    ].map((s,i,arr)=>(
                      <div key={i} className="flex flex-1 items-start gap-2">
                        <div className="flex flex-col items-center">
                          <div className="grid size-5 shrink-0 place-items-center rounded-full" style={{ background:s.done?'var(--color-primary)':'var(--color-card)', border:`2px solid ${s.done?'var(--color-primary)':'var(--color-border-strong)'}` }}>
                            {s.done && <Icon name="check" size={10} className="text-white" />}
                          </div>
                        </div>
                        <div className="min-w-0 flex-1">
                          <div className={"text-xs leading-[1.3] " + (s.done?'font-semibold text-foreground':'text-muted-foreground')}>{CAN_ST[s.key].short || CAN_ST[s.key].label}</div>
                          {s.date && <div className="text-xs text-muted-foreground">{s.date}</div>}
                          {i<arr.length-1 && <div className="mt-1 h-0.5 w-full" style={{ background:s.done?'var(--color-primary)':'var(--color-border)' }} />}
                        </div>
                      </div>
                    ))}
                  </div>

                  {/* Mọi thao tác đổi chặng đi qua ĐÂY. Ba thao tác cuối là bổ sung của R2-28:
                      «Đã tuyển» là cửa vào duy nhất của nhánh tự đóng các đơn còn lại và tạo hồ
                      sơ nhân viên; hai thao tác kia trước đây có nhãn mà không có đường đi tới. */}
                  <div className="flex flex-wrap gap-2">
                    <Btn variant="primary"  size="xs" icon="star">Sàng lọc</Btn>
                    <Btn variant="outline"  size="xs" icon="calendar">Lên lịch phỏng vấn</Btn>
                    <Btn variant="outline"  size="xs" icon="gift">Đánh dấu đã gửi lời mời</Btn>
                    <Btn variant="soft"     size="xs" icon="award">Đã tuyển</Btn>
                    <Btn variant="outline"  size="xs" icon="x">Ứng viên từ chối lời mời</Btn>
                    <Btn variant="outline"  size="xs" icon="x-circle">Ngừng xét đơn</Btn>
                    <Btn variant="destructive" size="xs" icon="x">Từ chối</Btn>
                  </div>
                  <div className="mt-2.5 text-xs leading-[1.5] text-muted-foreground">
                    «Đã tuyển» tạo hồ sơ nhân viên từ đơn này và tự ngừng xét các đơn còn lại của cùng ứng viên. Bốn thao tác «Từ chối», «Ứng viên từ chối lời mời», «Ngừng xét đơn» và ghi kết quả trượt phỏng vấn đều mở hộp thoại nhập lý do.
                    <br />
                    Hai chặng «{CAN_ST.INTERVIEW_PASSED.label}» và «{CAN_ST.INTERVIEW_FAILED.label}» <strong>không có nút ở đây</strong>: chúng do thao tác chốt kết quả buổi phỏng vấn đặt, trên màn Lịch phỏng vấn. Chặng «{CAN_ST.APPLICATION_INITIATED.label}» do hệ thống đặt lúc tạo đơn.
                  </div>
                </div>
              </div>
            )}
            {tab==='profile' && (
              <div>
                {/* Resume download */}
                <div className="mb-[18px] flex items-center gap-3 rounded-md border border-border p-3.5">
                  <div className="grid size-10 place-items-center rounded-md bg-destructive-soft">
                    <Icon name="file-text" size={18} className="text-destructive" />
                  </div>
                  <div className="flex-1">
                    <div className="text-sm font-semibold">PhamMinhDuc_CV_2026.pdf</div>
                    <div className="text-xs text-muted-foreground">Nộp ngày 10/05/2026 · 2.3MB</div>
                  </div>
                  <Btn variant="outline" size="sm" icon="download">Tải xuống</Btn>
                </div>
                <div className="mb-[18px] rounded-md border border-border bg-muted px-3.5 py-2.5 text-xs text-muted-foreground">
                  Đã dùng 2,3MB / {CAN_FILE_LIMIT.total} · mỗi tệp tối đa {CAN_FILE_LIMIT.perFile} · đường dẫn tải xuống có hiệu lực 15 phút
                </div>

                {/* Năm dòng của bản trước — Kinh nghiệm · Học vấn · Mức lương mong đợi · Thời gian
                    bắt đầu · Người giới thiệu — ĐÃ CẮT KHỎI v1 (quyết định R2-27): không cột nào
                    trong lược đồ lưu được chúng. Ghi lại thành việc giai đoạn sau. */}
                <div className="grid grid-cols-2 gap-x-6 gap-y-1.5">
                  {[
                    ['Họ và tên',    'Phạm Minh Đức'],
                    ['Email',        c.email],
                    ['Số điện thoại',c.phone],
                    ['Ngôn ngữ liên hệ','Tiếng Việt'],
                  ].map(([l,v],i)=>(
                    <div key={i} className="border-b border-border py-[9px]">
                      <div className="mb-[3px] text-xs text-muted-foreground">{l}</div>
                      <div className="text-sm font-medium">{v}</div>
                    </div>
                  ))}
                </div>
              </div>
            )}
            {tab==='interviews' && (
              <div>
                <div className="mb-3.5 flex justify-between">
                  <div className="text-base font-semibold">1 buổi phỏng vấn</div>
                  <Btn variant="soft" size="sm" icon="plus">Lên lịch thêm</Btn>
                </div>
                <div className="rounded-md border border-warning bg-warning-soft p-4">
                  <div className="mb-2 flex justify-between">
                    <div className="text-base font-bold">Technical Interview — Vòng 1</div>
                    {/* Nhãn đọc từ bảng trạng thái buổi phỏng vấn, KHÔNG chép tay: bản trước ghi
                        "Lên lịch" trong khi bảng gốc ghi "Đã lên lịch" (audit vấn đề 44). */}
                    <Badge variant="warning" dot>{INT_ST.SCHEDULED.label}</Badge>
                  </div>
                  <div className="mb-3 grid grid-cols-2 gap-2.5 text-sm">
                    {[
                      ['Ngày','20/05/2026 (Thứ Tư)'],
                      ['Giờ','14:00 – 15:30'],
                      ['Người phỏng vấn','Lê Hữu Phước, Trần Minh Tuấn'],
                      ['Hình thức','Google Meet'],
                    ].map(([l,v],i)=>(
                      <div key={i}>
                        <div className="mb-0.5 text-xs" style={{ color:'oklch(0.45 0.1 65)' }}>{l}</div>
                        <div className="font-medium" style={{ color:'oklch(0.35 0.1 65)' }}>{v}</div>
                      </div>
                    ))}
                  </div>
                  <div className="flex gap-2">
                    <Btn variant="outline" size="xs" icon="edit">Sửa lịch</Btn>
                    {/* Mở hộp thoại nhập lý do — huỷ buổi là một trong năm chỗ bắt buộc (R2-26) */}
                    <Btn variant="outline" size="xs" icon="x">Hủy buổi</Btn>
                    <Btn variant="soft"    size="xs" icon="check-circle">Ghi kết quả</Btn>
                  </div>
                </div>
              </div>
            )}
            {tab==='notes' && (
              <div>
                <div className="mb-3.5 flex justify-between">
                  <div className="text-base font-semibold">Ghi chú nội bộ</div>
                  <Btn variant="soft" size="sm" icon="plus">Thêm ghi chú</Btn>
                </div>
                {[
                  { by:'Nguyễn Thị Lan', time:'10/05/2026 14:22', note:'CV rất ấn tượng, kinh nghiệm React và Next.js phù hợp với yêu cầu vị trí. Đề xuất tiến hành technical interview sớm.' },
                  { by:'Lê Hữu Phước',  time:'12/05/2026 09:15', note:'Đã liên hệ, ứng viên hiện đang làm tại FPT Software. Notice period 1 tháng. Có hỏi thêm về vị trí DevOps nên đã tạo đơn thứ hai.' },
                ].map((n,i)=>(
                  <div key={i} className="mb-2.5 rounded-md bg-muted p-3.5">
                    <div className="mb-1.5 flex justify-between">
                      <div className="flex items-center gap-2">
                        <Avatar name={n.by} size="sm" />
                        <span className="text-sm font-semibold">{n.by}</span>
                      </div>
                      <span className="text-xs text-muted-foreground">{n.time}</span>
                    </div>
                    <div className="text-sm leading-[1.55] text-foreground">{n.note}</div>
                  </div>
                ))}
              </div>
            )}
            {tab==='history' && (
              <div>
                <div className="mb-3.5 text-base font-semibold">Lịch sử hoạt động</div>
                {[
                  { icon:'star',        color:'var(--color-info)',     label:'Đơn DevOps Engineer chuyển sang giai đoạn Sàng lọc', time:'13/05/2026 11:05', by:'Lê Hữu Phước'   },
                  { icon:'inbox',       color:'var(--color-success)', label:'Tạo đơn ứng tuyển — DevOps Engineer',                time:'12/05/2026 16:40', by:'Lê Hữu Phước'   },
                  { icon:'file-text',   color:'var(--color-primary)',  label:'Đính kèm CV — PhamMinhDuc_CV_2026.pdf',              time:'10/05/2026 10:15', by:'Nguyễn Thị Lan'  },
                  { icon:'inbox',       color:'var(--color-success)', label:'Tạo đơn ứng tuyển — Frontend Developer',             time:'10/05/2026 10:14', by:'Nguyễn Thị Lan'  },
                ].map((ev,i)=>(
                  <div key={i} className={"flex gap-3 py-2.5 " + (i<3?'border-b border-border':'')}>
                    <div className="grid size-8 shrink-0 place-items-center rounded-full bg-muted">
                      <Icon name={ev.icon} size={14} style={{ color:ev.color }} />
                    </div>
                    <div>
                      <div className="text-sm font-medium">{ev.label}</div>
                      <div className="mt-0.5 text-xs text-muted-foreground">{ev.by} · {ev.time}</div>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>
      </div>
    </HRMShell>
  );
};

// ─── 02b: Candidate Detail — đã rút đồng ý lưu trữ dữ liệu ────────────────────
const CandConsentWithdrawnScreen = () => <CandDetailScreen consentWithdrawn />;

// ─── 03: Add Candidate Form ────────────────────────────────────────────────────
const CandCreateScreen = () => (
  <HRMShell active="candidates"
    title="Thêm ứng viên mới"
    crumbs={['Ứng viên','Thêm mới']}
    actions={<>
      <Btn variant="outline" size="sm">Hủy</Btn>
      <Btn variant="primary"  size="sm">Lưu ứng viên</Btn>
    </>}>
    <div className="grid grid-cols-[1fr_300px] gap-[18px]">
      <div className={CARD + " p-6"}>
        {/* Basic info */}
        <div className="mb-[18px] flex items-center gap-2">
          <div className="grid size-7 place-items-center rounded-md bg-primary-soft">
            <Icon name="user" size={14} className="text-primary" />
          </div>
          <span className="text-base font-bold">Thông tin ứng viên</span>
        </div>
        <div className="mb-3.5 grid grid-cols-3 gap-3.5">
          <div>
            <label className={FIELD_LABEL}>Họ *</label>
            <input className={INPUT} placeholder="Nguyễn Thị" />
          </div>
          <div>
            <label className={FIELD_LABEL}>Tên đệm</label>
            <input className={INPUT} placeholder="Minh" />
          </div>
          <div>
            <label className={FIELD_LABEL}>Tên *</label>
            <input className={INPUT} placeholder="Hoa" />
          </div>
        </div>
        <div className="mb-3.5 grid grid-cols-3 gap-3.5">
          <div>
            <label className={FIELD_LABEL}>Email *</label>
            <div className="relative flex items-center">
              <Icon name="mail" size={13} className="pointer-events-none absolute left-2.5 size-3.5 text-muted-foreground" />
              <input className={INPUT + " pl-8"} type="email" placeholder="email@gmail.com" />
            </div>
          </div>
          <div>
            <label className={FIELD_LABEL}>Số điện thoại</label>
            <div className="relative flex items-center">
              <Icon name="phone" size={13} className="pointer-events-none absolute left-2.5 size-3.5 text-muted-foreground" />
              <input className={INPUT + " pl-8"} placeholder="+84 9xx xxx xxx" />
            </div>
          </div>
          <div>
            {/* Ngôn ngữ liên hệ quyết định thư gửi cho ứng viên dùng bản dịch nào (R2-02) */}
            <label className={FIELD_LABEL}>Ngôn ngữ liên hệ *</label>
            <Select className="cursor-pointer" options={['Tiếng Việt','English','中文']} defaultValue="Tiếng Việt" />
          </div>
        </div>

        {/* Vacancy link */}
        <div className="mb-[18px] border-t border-border pt-[18px]">
          <div className="mb-3.5 flex items-center gap-2">
            <div className="grid size-7 place-items-center rounded-md bg-primary-soft">
              <Icon name="briefcase" size={14} className="text-primary" />
            </div>
            <span className="text-base font-bold">Liên kết vị trí tuyển dụng *</span>
          </div>
          <Select className="mb-2.5 cursor-pointer" placeholder="— Chọn vị trí —"
            options={VAC_LIST.filter(v=>v.status==='ACTIVE').map(v=>`${v.title} (${v.dept})`)} />
          {/* Đơn LUÔN bắt đầu ở chặng "Nộp đơn" — không có ô chọn chặng ban đầu (quyết định R2-44).
              Ô chọn cũ cho phép đặt thẳng vào "Sàng lọc", tức bỏ qua một bước của máy trạng thái. */}
          <div className="flex gap-2 rounded-md bg-muted px-3.5 py-2.5 text-xs leading-[1.55] text-muted-foreground">
            <Icon name="info" size={13} className="mt-0.5 shrink-0" />
            Đơn ứng tuyển sẽ được tạo ở chặng <strong className="text-foreground">{CAN_ST.APPLICATION_INITIATED.label}</strong>. Muốn chuyển sang chặng «{CAN_ST.SHORTLISTED.label}» thì dùng thao tác trên màn chi tiết sau khi lưu.
          </div>
        </div>

        {/* Consent — ô tích THẬT, mặc định CHƯA tích. Bản trước vẽ một hình vuông đã tô sẵn, không
            có <input> nào, nên trên bản vẽ ứng viên luôn "đã đồng ý" (audit vấn đề 44). */}
        <div className="rounded-md border bg-info-soft px-4 py-3.5" style={{ borderColor:'oklch(0.604 0.180 253 / 0.3)' }}>
          <label className="flex cursor-pointer items-start gap-2.5">
            <input type="checkbox" className="mt-0.5 size-[18px] shrink-0" />
            <div className="text-xs leading-[1.55]" style={{ color:'oklch(0.385 0.062 222)' }}>
              <strong>Đồng ý lưu trữ dữ liệu (GDPR) *</strong> — Ứng viên đã đồng ý cho phép ELS Technologies lưu trữ và xử lý thông tin cá nhân cho mục đích tuyển dụng.
            </div>
          </label>
        </div>
        <div className="mt-2 flex items-center gap-1.5 text-xs text-destructive">
          <Icon name="alert-circle" size={13} />
          Chưa tích ô đồng ý — nút «Lưu ứng viên» bị chặn cho tới khi ô này được tích.
        </div>
      </div>

      {/* Right */}
      <div className="flex flex-col gap-3">
        {/* Upload CV */}
        <div className={CARD + " p-[18px]"}>
          <div className="mb-3 text-sm font-bold">Đính kèm CV / Hồ sơ</div>
          <div className="cursor-pointer rounded-md border-2 border-dashed border-border-strong p-6 text-center">
            <Icon name="upload" size={20} className="mb-2 text-primary" />
            <div className="mb-1 text-sm font-medium">Kéo thả file hoặc click</div>
            <div className="text-xs leading-[1.45] text-muted-foreground">
              PDF, DOC, DOCX · Tối đa {CAN_FILE_LIMIT.perFile} mỗi tệp, tổng {CAN_FILE_LIMIT.total} cho một ứng viên
            </div>
          </div>
        </div>
      </div>
    </div>
  </HRMShell>
);

// ─── 06: Hộp thoại nhập lý do (mẫu dùng chung cho cả năm thao tác) ────────────
// MỘT mẫu, dùng lại cho: từ chối ứng viên · ghi kết quả trượt phỏng vấn · ứng viên từ chối lời
// mời · ngừng xét đơn · huỷ buổi phỏng vấn (quyết định R2-26). Thao tác có danh sách lý do cố
// định thì hiện thêm ô chọn; ô ghi chú thì LUÔN có và LUÔN bắt buộc.
const CandReasonDialog = ({ action='WITHDRAW' }) => {
  const cfg = REASON_ACTIONS[action];
  return (
    <div className="absolute inset-0 z-[60] grid place-items-center bg-black/50">
      <div className="w-[460px] rounded-xl bg-popover p-6 shadow-2xl outline outline-4 outline-black/5">
        <div className="mb-4 flex items-start gap-3">
          <div className="grid size-10 shrink-0 place-items-center rounded-md bg-destructive-soft">
            <Icon name="alert-triangle" size={18} className="text-destructive" />
          </div>
          <div>
            <div className="text-base font-bold">{cfg.title}</div>
            <div className="mt-0.5 text-xs text-muted-foreground">
              Phạm Minh Đức — DevOps Engineer (đơn A009)
            </div>
          </div>
        </div>

        {cfg.options && (
          <div className="mb-3.5">
            <label className={FIELD_LABEL}>Lý do *</label>
            {/* Danh sách cố định để THỐNG KÊ ĐƯỢC vì sao mất ứng viên — không để gõ tự do ở đây */}
            <Select className="cursor-pointer" options={cfg.options} placeholder="— Chọn lý do —" />
          </div>
        )}

        <div className="mb-1.5">
          <label className={FIELD_LABEL}>Ghi chú *</label>
          <textarea className="h-24 w-full resize-none rounded-md border border-input bg-transparent px-3 pt-2 text-base text-foreground shadow-xs placeholder:text-muted-foreground transition-colors focus:border-primary focus:outline-none focus:ring-[3px] focus:ring-ring"
            placeholder="Nêu rõ hoàn cảnh — ghi chú này hiện lại ở mọi lần ứng viên quay lại ứng tuyển." />
        </div>
        <div className="mb-4 text-xs leading-[1.5] text-muted-foreground">
          Ghi chú là <strong>bắt buộc</strong>. Nội dung được lưu vào lịch sử của đơn và hiện trong dải thông báo ở đầu hồ sơ những lần sau.
        </div>

        <div className="flex justify-end gap-2">
          <Btn variant="outline">Hủy</Btn>
          <Btn variant="destructive">Xác nhận {cfg.title.toLowerCase()}</Btn>
        </div>
      </div>
    </div>
  );
};

const CandReasonDialogScreen = () => (
  <div className="relative size-full">
    <CandListScreen />
    <CandReasonDialog action="WITHDRAW" />
  </div>
);

// ─── 04: Empty State ──────────────────────────────────────────────────────────
const CandEmptyScreen = () => (
  <HRMShell active="candidates" title="Quản lý ứng viên" crumbs={['Ứng viên']}
    actions={<Btn variant="primary" size="sm" icon="plus">Thêm ứng viên đầu tiên</Btn>}>
    <div className={CARD + " flex min-h-[460px] flex-col items-center justify-center p-12"}>
      <svg width="80" height="80" viewBox="0 0 80 80" fill="none" className="mb-6">
        <circle cx="40" cy="40" r="40" fill="var(--color-muted)" />
        <circle cx="32" cy="30" r="10" fill="none" stroke="var(--color-border-strong)" strokeWidth="2.5" />
        <path d="M16 64c0-8.84 7.16-16 16-16s16 7.16 16 16" stroke="var(--color-border-strong)" strokeWidth="2.5" fill="none" strokeLinecap="round" />
        <circle cx="56" cy="34" r="7" fill="none" stroke="var(--color-border-strong)" strokeWidth="2" />
        <path d="M46 56c0-5.52 4.48-10 10-10" stroke="var(--color-border-strong)" strokeWidth="2" fill="none" strokeLinecap="round" />
        <circle cx="59" cy="59" r="12" fill="var(--color-primary-soft)" stroke="var(--color-primary)" strokeWidth="2" />
        <path d="M55 59h8M59 55v8" stroke="var(--color-primary)" strokeWidth="2" strokeLinecap="round" />
      </svg>
      <div className="mb-2.5 text-xl font-bold">Chưa có ứng viên nào</div>
      <div className="mb-7 max-w-[420px] text-center text-base leading-[1.65] text-muted-foreground">
        Ứng viên sẽ xuất hiện ở đây khi được thêm vào hệ thống và liên kết với một vị trí đang tuyển.
      </div>
      <div className="flex gap-2.5">
        <Btn variant="primary" icon="plus">Thêm ứng viên</Btn>
      </div>
    </div>
  </HRMShell>
);

// ─── 05: Dark Mode ────────────────────────────────────────────────────────────
const CandDarkScreen = () => <CandListScreen dark />;

Object.assign(window, {
  CandListScreen, CandDetailScreen, CandConsentWithdrawnScreen, CandCreateScreen,
  CandReasonDialog, CandReasonDialogScreen, CandEmptyScreen, CandDarkScreen,
});
