// gieoque.jsx — phép gieo quẻ DLVN dùng chung cho Vấn Thiên (theo Prompt_ClaudeDesign_Gieo_Que_So_Tuong_v1):
//   gqTheoSo(chuỗi): chuỗi chữ số, giữ 0 đầu; chẵn chia đôi, lẻ tra bảng {3:1, 5:3, 7:3} (phần ĐẦU = thượng), ngoài bảng floor + cảnh báo
//   gqNgauNhien(): crypto.getRandomValues + rejection sampling (không Math.random, không %)
//   gqTenNgan(hex): Thủy Thiên Nhu → Nhu; Thuần Kiền giữ nguyên
//   gqChipTuong(key): chip tượng theo Sổ Tượng (riêng trước, kho sau, đúng thứ tự file)
//   gqSelfTest(): bộ test §4 — chạy khi mở ?selftest=1, in console.table
// Exports to window: gqQ8, gqTheoSo, gqNgauNhien, gqTenNgan, gqHexTuHai, gqChipTuong, gqSelfTest, GQ_LE_BANG, GQ_NHAC, GQ_VI_DU_THAY, gqNhayCam

const gqQ8 = n => (n % 8) || 8;
const TRI_SYM = { 'Kiền': '☰', 'Đoài': '☱', 'Ly': '☲', 'Chấn': '☳', 'Tốn': '☴', 'Khảm': '☵', 'Cấn': '☶', 'Khôn': '☷' };
const gqQ6 = n => (n % 6) || 6;
const GQ_LE_BANG = { 3: 1, 5: 3, 7: 3 }; // số chữ số lẻ → số chữ số phần đầu (bảng của thầy; 5→3|2 là đúng)
const GQ_NHAC = 'Tượng là gợi ý để liên tưởng theo ngữ cảnh câu hỏi — không phải đáp án. Muốn chắc: hỏi thẳng thầy.';
const GQ_VI_DU_THAY = 'cửa hàng (thuần kiền) bị bế tắc (tiểu súc), dơ dáy (tiểu súc) đường đi, lối vào (tốn) chật hẹp (tiểu súc) nhiều kiện hàng lấp lại (thuần kiền - tiểu súc) làm cho khó đi (tiểu súc)';

function gqHexTuHai(thuong, ha) { return HEXAGRAMS.find(h => h.up === TT_TRI[thuong] && h.lo === TT_TRI[ha]) || HEXAGRAMS[0]; }
function gqTenNgan(hex) { return /^Thuần /.test(hex.name) ? hex.name : hex.name.split(' ').slice(2).join(' '); }
// chữ số full-width → 0-9, bỏ mọi ký tự khác, GIỮ 0 đứng đầu
function gqChuoiSo(raw) { return String(raw || '').replace(/[０-９]/g, c => String.fromCharCode(c.charCodeAt(0) - 0xFF10 + 48)).replace(/\D/g, ''); }
function gqTheoSo(raw) {
  const ds = gqChuoiSo(raw);
  if (ds.length < 2) return null;
  let dau, ngoaiBang = false;
  if (ds.length % 2 === 0) dau = ds.length / 2;
  else if (GQ_LE_BANG[ds.length]) dau = GQ_LE_BANG[ds.length];
  else { dau = Math.floor(ds.length / 2); ngoaiBang = true; }
  const sum = s => s.split('').reduce((a, c) => a + Number(c), 0);
  const dauStr = ds.slice(0, dau), sauStr = ds.slice(dau);
  const tDau = sum(dauStr), tSau = sum(sauStr), tong = tDau + tSau;
  const thuong = gqQ8(tDau), ha = gqQ8(tSau), hao = gqQ6(tong);
  return { ds, dauStr, sauStr, tDau, tSau, tong, thuong, ha, hao, hex: gqHexTuHai(thuong, ha), ngoaiBang };
}
function gqRandInt(k) { // 1..k đều xác suất
  const u = new Uint32Array(1), max = Math.floor(0x100000000 / k) * k;
  for (;;) { crypto.getRandomValues(u); if (u[0] < max) return (u[0] % k) + 1; }
}
function gqNgauNhien() { const thuong = gqRandInt(8), ha = gqRandInt(8), hao = gqRandInt(6); return { thuong, ha, hao, hex: gqHexTuHai(thuong, ha) }; }
// chip tượng của một key Sổ Tượng (h12 / qKhảm): riêng (ky/que/kb) trước, kho sau — đúng thứ tự
function gqChipTuong(key) { return ((window.__ttSoTuong || {})[key] || []).map(t => ({ tu: t.tu, rieng: t.src !== 'kho' })); }
// chủ đề không luận công khai
function gqNhayCam(...txt) {
  const n = txt.join(' ').toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/đ/g, 'd');
  return ['trai hay gai', 'gioi tinh thai', 'con trai hay con gai', 'be trai hay be gai', 'thai nhi la trai', 'thai nhi la gai'].some(k => n.indexOf(k) >= 0);
}

function gqSelfTest() {
  const rows = [];
  const ok = (ten, got, want) => rows.push({ test: ten, got, want, kq: got === want ? 'PASS' : 'FAIL' });
  [['672', 'Thủy Thiên Nhu', 3, 'Thủy Trạch Tiết', 'Hỏa Trạch Khuể'], ['350', 'Hỏa Phong Đỉnh', 2, 'Hỏa Sơn Lữ', 'Trạch Thiên Quải'],
   ['333', 'Hỏa Thủy Vị Tế', 3, 'Hỏa Phong Đỉnh', 'Thủy Hỏa Ký Tế'], ['389', 'Hỏa Thiên Đại Hữu', 2, 'Thuần Ly', 'Trạch Thiên Quải'],
   ['678', 'Thủy Sơn Kiển', 3, 'Thủy Địa Tỷ', 'Hỏa Thủy Vị Tế'], ['072', 'Địa Thiên Thái', 3, 'Địa Trạch Lâm', 'Lôi Trạch Quy Muội'],
   ['00', 'Thuần Khôn', 6, 'Sơn Địa Bác', 'Thuần Khôn'], ['25', 'Trạch Phong Đại Quá', 1, 'Trạch Thiên Quải', 'Thuần Kiền']].forEach(([s, c, h, b, ho]) => {
    const r = gqTheoSo(s); const bien = hexBien(r.hex, r.hao), hoQ = hexHo(r.hex);
    ok(`số ${s}`, `${r.hex.name} · ${r.hao} · ${bien.name} · ${hoQ.name}`, `${c} · ${h} · ${b} · ${ho}`);
  });
  { const base = 6 + 7 + 21, g = 7; const hx = gqHexTuHai(gqQ8(base), gqQ8(base + g)), hao = gqQ6(base + g); ok('thời khắc Tỵ/7/21/Ngọ', `${hx.name} · ${hao} · ${hexBien(hx, hao).name} · ${hexHo(hx).name}`, 'Trạch Thiên Quải · 5 · Lôi Thiên Đại Tráng · Thuần Kiền'); }
  ok('Hỗ Thuần Đoài', hexHo(gqHexTuHai(2, 2)).name, 'Phong Hỏa Gia Nhân');
  ok('Tiểu Súc động 4', hexBien(gqHexTuHai(5, 1), 4).name, 'Thuần Kiền');
  const kho = window.TT_SO_TUONG_KHO || [];
  ok('kho 64 quẻ', HEXAGRAMS.filter(h => kho.some(e => e.que === h.name)).length, 64);
  ok('kho 8 quái', TT_TRI.slice(1).filter(q => kho.some(e => e.que === 'quái ' + q)).length, 8);
  console.table(rows);
  return rows;
}
if (/[?&]selftest=1/.test(location.search)) setTimeout(() => { try { gqSelfTest(); } catch (e) { console.error('selftest', e); } }, 1500);

Object.assign(window, { gqQ8, gqTheoSo, gqNgauNhien, gqTenNgan, gqHexTuHai, gqChipTuong, gqSelfTest, gqChuoiSo, GQ_LE_BANG, GQ_NHAC, GQ_VI_DU_THAY, gqNhayCam, TRI_SYM });
