/* ════════════════════════════════════════════════
   Fashion Matches Manager — app.js
   Two-panel: Product list + Detail (Phối đồ + Mô tả)
   ════════════════════════════════════════════════ */

const OCC_LABELS = {
  di_lam_cong_so: "<i data-lucide='briefcase' class='icon-sm'></i> Đi làm công sở",
  di_choi_dao_pho: "<i data-lucide='shopping-bag' class='icon-sm'></i> Đi chơi / dạo phố",
  o_nha_mac_ngu: "<i data-lucide='home' class='icon-sm'></i> Ở nhà / mặc ngủ",
  du_lich: "<i data-lucide='plane' class='icon-sm'></i> Du lịch",
};

const ROLE_LABELS = {
  bottom:    { label: "Quần / Chân váy", emoji: "<i data-lucide='book-marked' class='icon-sm'></i>" },
  outerwear: { label: "Layer ngoài",     emoji: "<i data-lucide='layers' class='icon-sm'></i>" },
  accessory: { label: "Phụ kiện",        emoji: "<i data-lucide='shopping-cart' class='icon-sm'></i>" },
};

// ── State ──────────────────────────────────────
let currentCode  = null;
let aiMatches    = {};
let activeOcc    = null;
let currentPage  = 1;
let totalPages   = 1;
let listSearchTimer = null;
let batchTimer   = null;
let addingCtx    = null;
let modalSearchTimer = null;

// ── Init ───────────────────────────────────────
window.addEventListener('DOMContentLoaded', () => {
  loadList(1);
  pollBatchOnce();
});

// ══ PRODUCT LIST ═════════════════════════════

function onListSearch(val) {
  clearTimeout(listSearchTimer);
  listSearchTimer = setTimeout(() => loadList(1), 300);
}

async function loadList(page) {
  currentPage = page;
  const q      = document.getElementById('listSearch').value.trim();
  const filter = document.getElementById('filterHasMatches').value;
  const listEl = document.getElementById('productList');

  listEl.innerHTML = '<div class="empty-state" style="padding:30px 16px;"><p style="font-size:12px;color:var(--muted-fg);">Đang tải...</p></div>';

  try {
    let url = `/api/product-desc/list?page=${page}&limit=20`;
    if (q) url += `&search=${encodeURIComponent(q)}`;

    const r = await fetch(url);
    const j = await r.json();
    const items = j.items || [];
    totalPages = Math.max(1, Math.ceil((j.total || 0) / 20));

    document.getElementById('listCount').textContent = `${j.total || 0} SP`;
    document.getElementById('pageInfo').textContent  = `${page} / ${totalPages}`;
    document.getElementById('btnPrev').disabled = page <= 1;
    document.getElementById('btnNext').disabled = page >= totalPages;

    if (!items.length) {
      listEl.innerHTML = '<div class="empty-state" style="padding:30px 16px;"><div class="empty-icon" style="font-size:24px;opacity:.4;">🔍</div><p style="font-size:12px;">Không tìm thấy</p></div>';
      return;
    }

    listEl.innerHTML = items.map(p => renderListItem(p)).join('');
  } catch (e) {
    listEl.innerHTML = '<div class="empty-state" style="padding:20px;"><p style="color:var(--error);font-size:12px;">Lỗi tải danh sách</p></div>';
  }
}

function renderListItem(p) {
  const hasMatches = p.has_ai_matches;
  const badge = hasMatches
    ? `<span class="badge badge-success" style="font-size:9px;">✓ Phối đồ</span>`
    : `<span class="badge badge-muted" style="font-size:9px;">Chưa có</span>`;
  const activeClass = p.code === currentCode ? 'active' : '';
  return `
    <div class="fm-list-item ${activeClass}" onclick="loadProduct('${esc(p.code)}')">
      <img class="fm-list-img" src="${esc(p.image_url || '')}" onerror="this.style.display='none'">
      <div class="fm-list-info">
        <div class="fm-list-name">${esc(p.name || p.code)}</div>
        <div class="fm-list-code">${esc(p.code)}</div>
        <div class="fm-list-badges">${badge}</div>
      </div>
    </div>
  `;
}

function changePage(delta) {
  const newPage = currentPage + delta;
  if (newPage < 1 || newPage > totalPages) return;
  loadList(newPage);
}

// ══ PRODUCT DETAIL ════════════════════════════

async function loadProduct(code) {
  currentCode = code;

  // Highlight active in list
  document.querySelectorAll('.fm-list-item').forEach(el => el.classList.remove('active'));
  const items = document.querySelectorAll('.fm-list-item');
  items.forEach(el => { if (el.onclick?.toString().includes(code)) el.classList.add('active'); });

  // Show loading state
  document.getElementById('welcomeState').style.display  = 'none';
  document.getElementById('detailContent').style.display = 'flex';

  try {
    // 1. Product meta from ultra-desc API
    const [metaRes, fmRes] = await Promise.all([
      fetch(`/api/product-desc/saved/${encodeURIComponent(code)}`),
      fetch(`/api/fashion-matches/${encodeURIComponent(code)}`),
    ]);
    const metaJson = await metaRes.json();
    const fmJson   = await fmRes.json();

    const desc = metaJson.description || {};
    const dd   = desc.description_data || desc.description || {};
    window.aiMatches  = fmJson.ok ? (fmJson.ai_matches || {}) : {};
    window.aiClassifications  = fmJson.ok ? (fmJson.classifications || {}) : {};

    // Populate header
    document.getElementById('prodImage').src          = desc.product_image_url || '';
    document.getElementById('prodImage').style.display = '';
    document.getElementById('prodName').textContent   = dd.ten_san_pham || desc.product_name || code;
    document.getElementById('prodCode').textContent   = code;
    document.getElementById('prodLine').textContent   = desc.product_line || '';
    document.getElementById('prodColor').textContent  = desc.master_color  || '';

    // Render tabs
    renderMatchesTab();
    renderDescTab(dd);

  } catch (err) {
    showToast('❌ Lỗi tải dữ liệu: ' + err.message, 'error');
  }
}

// ══ TAB SWITCHING ════════════════════════════

function switchDetailTab(tab, btn) {
  // only toggle within detail tabs (not rules modal tabs)
  document.querySelectorAll('#detailTabs .fm-tab').forEach(b => b.classList.remove('active'));
  btn.classList.add('active');
  document.getElementById('tabMatches').style.display = tab === 'matches' ? 'flex' : 'none';
  document.getElementById('tabDesc').style.display    = tab === 'desc'    ? 'flex' : 'none';
  document.getElementById('tabTest').style.display    = tab === 'test'    ? 'flex' : 'none';
}

// ══ MATCHES TAB & SQL GROUPING ═══════════════════════════════

let currentGroupBy = 'occ';
let activeGroupTab = null;

const COLOR_TABS = {
  neutral: "<i data-lucide='circle' class='icon-sm'></i> Màu Neutral",
  light: "<i data-lucide='sun-dim' class='icon-sm'></i> Màu Light",
  dark: "<i data-lucide='moon' class='icon-sm'></i> Màu Dark"
};

const MATERIAL_TABS = {
  summer: "<i data-lucide='sun' class='icon-sm'></i> Mùa hè",
  winter: "<i data-lucide='snowflake' class='icon-sm'></i> Mùa đông"
};

function getVirtualMatches() {
   if (currentGroupBy === 'occ') {
       return window.aiMatches || {};
   } else if (currentGroupBy === 'color' || currentGroupBy === 'material') {
       return window.aiClassifications?.[currentGroupBy] || {};
   }
   return {};
}

function setGroupBy(type) {
  currentGroupBy = type;
  document.querySelectorAll('#groupTabs .btn').forEach(btn => {
      btn.classList.remove('active');
      btn.style.color = "var(--muted-fg)";
  });
  const activeBtn = document.getElementById(
      type === 'occ' ? 'btnGroupOcc' : (type === 'color' ? 'btnGroupColor' : 'btnGroupMaterial')
  );
  if(activeBtn) {
      activeBtn.classList.add('active');
      activeBtn.style.color = "var(--primary)";
  }
  
  if (type === 'occ') activeGroupTab = Object.keys(OCC_LABELS)[0];
  else if (type === 'color') activeGroupTab = 'neutral';
  else if (type === 'material') activeGroupTab = 'summer';
  
  renderMatchesTab();
}

function renderMatchesTab() {
  renderGroupTabs();
  const virtual = getVirtualMatches();
  if (!activeGroupTab || !virtual[activeGroupTab]) {
     const keys = Object.keys(virtual);
     activeGroupTab = keys.length ? keys[0] : activeGroupTab;
  }
  renderMatchContent();
}

function renderGroupTabs() {
  const container = document.getElementById('occTabs');
  let LABELS = OCC_LABELS;
  if (currentGroupBy === 'color') LABELS = COLOR_TABS;
  else if (currentGroupBy === 'material') LABELS = MATERIAL_TABS;

  const virtual = getVirtualMatches();
  container.innerHTML = Object.entries(LABELS).map(([key, label]) => {
    let count = 0;
    const grpF = virtual[key];
    if (Array.isArray(grpF)) {
         count = grpF.length;
    } else if (grpF && typeof grpF === 'object') {
         count = Object.values(grpF).reduce((s, a) => s + (Array.isArray(a) ? a.length : 0), 0);
    }
    const active = key === activeGroupTab ? 'active' : '';
    return `<button class="occ-tab ${active}" onclick="switchGroupTab('${key}')">
      ${label} <span class="occ-count">${count}</span>
    </button>`;
  }).join('');
  if (window.lucide) lucide.createIcons();
}

function switchGroupTab(key) {
  activeGroupTab = key;
  renderMatchesTab();
}

function renderMatchContent() {
  const container = document.getElementById('matchContent');
  const empty     = document.getElementById('emptyState');
  const virtual   = getVirtualMatches();
  const occData   = virtual[activeGroupTab] || {};
  
  let hasAny = false;
  if (Array.isArray(occData)) {
      hasAny = occData.length > 0;
  } else {
      hasAny = Object.values(occData).some(arr => (Array.isArray(arr) && arr.length > 0));
  }

  if (!hasAny && !Object.keys(virtual).length) {
    container.style.display = 'none';
    empty.style.display     = 'flex';
    return;
  }
  container.style.display = 'flex';
  empty.style.display     = 'none';

  if (Array.isArray(occData)) {
      // Flat Array Render for SQL Super Classifications
      const items = occData;
      const cards = items.map((item, idx) => renderMatchCard(item, activeGroupTab, 'bottom', idx)).join('');
      container.innerHTML = `<div class="role-section">
        <div class="role-header">
          <div class="role-title"><i data-lucide="database" class="icon-sm"></i> Raw SQL SQL Match Results <span class="badge badge-info">${items.length}</span></div>
        </div>
        <div class="role-body">${cards}</div>
      </div>`;
  } else {
      // Nested Roles Render
      const roles = ['bottom', 'outerwear', 'accessory'];
      container.innerHTML = roles.map(role => {
        const items    = occData[role] || [];
        const roleInfo = ROLE_LABELS[role] || { label: role, emoji: '📦' };
        const cards    = items.map((item, idx) => renderMatchCard(item, activeGroupTab, role, idx)).join('');
        const addBtn   = `<div class="add-card" onclick="openAddModal('${activeGroupTab}','${role}')">
          <div class="add-card-icon">➕</div>
          <div class="add-card-label">Thêm SP</div>
        </div>`;
        return `<div class="role-section">
          <div class="role-header">
            <div class="role-title">${roleInfo.emoji} ${roleInfo.label} <span class="badge badge-info">${items.length}</span></div>
            <button class="btn btn-ghost btn-sm" onclick="openAddModal('${activeGroupTab}','${role}')">+ Thêm</button>
          </div>
          <div class="role-body">${cards}${addBtn}</div>
        </div>`;
      }).join('');
  }
  if (window.lucide) lucide.createIcons();
}

function renderMatchCard(item, occ, role, idx) {
  const score    = item.score || 0;
  const scoreCls = score >= 75 ? 'score-high' : score >= 55 ? 'score-mid' : 'score-low';
  const imgHtml  = item.image
    ? `<img class="match-img" src="${esc(item.image)}" onerror="this.parentElement.innerHTML='<div class=match-img-placeholder>👗</div>'">`
    : `<div class="match-img-placeholder">👗</div>`;
  return `<div class="match-card">
    ${imgHtml}
    <div class="match-info">
      <div class="match-name">${esc(item.name || '')}</div>
      <div class="match-code">${esc(item.code || '')}</div>
      <div class="match-reason">${esc(item.reason || '')}</div>
    </div>
    <div class="match-footer">
      <span class="match-score ${scoreCls}">${score}đ</span>
      <button class="btn-remove" onclick="removeItem('${occ}','${role}',${idx})">✕</button>
    </div>
  </div>`;
}

function removeItem(occ, role, idx) {
  const virtual = getVirtualMatches();
  if (!virtual[occ]?.[role]) return;
  virtual[occ][role].splice(idx, 1);
  if (!virtual[occ][role].length) delete virtual[occ][role];
  if (!Object.keys(virtual[occ] || {}).length) delete virtual[occ];
  renderMatchesTab();
}

// ══ DESC TAB ══════════════════════════════════

function renderDescTab(dd) {
  const el = document.getElementById('descContent');
  if (!dd || !Object.keys(dd).length) {
    el.innerHTML = '<p style="color:var(--muted-fg);font-size:13px;">Chưa có mô tả cho sản phẩm này.</p>';
    return;
  }

  const sections = [
    { title: '🏷️ Thông tin cơ bản', fields: [
      ['Tên SP',       'ten_san_pham'],
      ['Tagline',      'tagline'],
      ['Mô tả chính',  'mo_ta_chinh'],
      ['Phong cách',   'phong_cach'],
      ['Tags',         'tags'],
    ]},
    { title: '🌿 Chất liệu & Bảo quản', fields: [
      ['Chất liệu',       'chat_lieu'],
      ['Tính năng vải',   'tinh_nang_vai'],
      ['Bảo quản',        'huong_dan_bao_quan'],
    ]},
    { title: '👤 Đối tượng', fields: [
      ['Giới tính',    'gioi_tinh'],
      ['Độ tuổi',      'do_tuoi'],
      ['Lối sống',     'loi_song'],
      ['Tính cách',    'tinh_cach'],
    ]},
    { title: '👗 Dịp mặc & Styling', fields: [
      ['Dịp mặc',              'dip_mac'],
      ['Gợi ý phối đồ',        'phoi_do'],
      ['Nguyên tắc',           'nguyen_tac_phoi_do'],
      ['Layering',             'layer'],
      ['Tránh phối cùng',      'tranh_phoi_cung'],
      ['Cross sell',           'cross_sell'],
    ]},
    { title: '💡 Lý do mua & Hook', fields: [
      ['Lý do mua',    'ly_do_mua'],
      ['Hook QC',      'hook_quang_cao'],
    ]},
  ];

  el.innerHTML = sections.map(sec => {
    const rows = sec.fields
      .filter(([, key]) => dd[key])
      .map(([label, key]) => `<div class="fm-desc-row">
        <div class="fm-desc-label">${label}</div>
        <div class="fm-desc-value">${esc(String(dd[key] || ''))}</div>
      </div>`).join('');
    if (!rows) return '';
    return `<div class="fm-desc-section">
      <h4>${sec.title}</h4>
      ${rows}
    </div>`;
  }).join('');
}

// ══ SAVE ══════════════════════════════════════

async function saveMatches() {
  if (!currentCode) return;
  const btn = document.getElementById('btnSave');
  btn.textContent = '⏳'; btn.disabled = true;
  try {
    const res = await fetch(`/api/fashion-matches/${encodeURIComponent(currentCode)}/update`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ ai_matches: aiMatches }),
    });
    const j = await res.json();
    showToast(j.ok ? '✅ Đã lưu' : `❌ ${j.error}`, j.ok ? 'success' : 'error');
    if (j.ok) loadList(currentPage);  // refresh badge in list
  } catch { showToast('❌ Lỗi kết nối', 'error'); }
  finally { btn.textContent = '💾 Lưu'; btn.disabled = false; }
}

// ══ AI REGEN ══════════════════════════════════

async function regenOne() {
  if (!currentCode) return;
  const btn = document.getElementById('btnRegen');
  btn.textContent = '⏳'; btn.disabled = true;
  try {
    const res = await fetch(`/api/fashion-matches/${encodeURIComponent(currentCode)}/regen`, { method: 'POST' });
    const j   = await res.json();
    showToast(j.ok ? '🤖 AI đang tính, sẽ reload sau 10s' : `❌ ${j.error}`, j.ok ? 'success' : 'error');
    if (j.ok) setTimeout(() => loadProduct(currentCode), 10000);
  } catch { showToast('❌ Lỗi kết nối', 'error'); }
  finally { btn.textContent = '🤖 AI Regen'; btn.disabled = false; }
}

async function triggerBatch() {
  const btn = document.getElementById('btnBatchRegen');
  if (!confirm('Chạy AI Stylist Engine cho toàn bộ sản phẩm?\nCó thể mất vài phút.')) return;
  btn.textContent = '⏳'; btn.disabled = true;
  try {
    const res = await fetch('/api/fashion-matches/batch', { method: 'POST' });
    const j   = await res.json();
    if (j.ok) { showToast('🤖 Batch đang chạy...', 'success'); startBatchPolling(); }
    else { showToast(`❌ ${j.error}`, 'error'); btn.textContent = '🤖 Batch AI'; btn.disabled = false; }
  } catch { showToast('❌ Lỗi', 'error'); btn.textContent = '🤖 Batch AI'; btn.disabled = false; }
}

function startBatchPolling() {
  document.getElementById('batchBar').style.display = 'block';
  clearInterval(batchTimer);
  batchTimer = setInterval(async () => {
    try {
      const r = await fetch('/api/fashion-matches/batch/status');
      const j = await r.json();
      const s = j.state || {};
      document.getElementById('batchLabel').textContent =
        s.is_running ? `⏳ ${s.done||0}/${s.total||0}` : `✅ Xong ${s.done||0} SP (${s.elapsed_s||0}s)`;
      const pct = s.progress_pct || 0;
      document.getElementById('progressFill').style.width = pct + '%';
      document.getElementById('batchPct').textContent = pct + '%';
      if (!s.is_running) {
        clearInterval(batchTimer);
        const btn = document.getElementById('btnBatchRegen');
        btn.textContent = '🤖 Batch AI'; btn.disabled = false;
        loadList(currentPage);
        if (currentCode) setTimeout(() => loadProduct(currentCode), 1500);
      }
    } catch (_) {}
  }, 1500);
}

async function pollBatchOnce() {
  try {
    const r = await fetch('/api/fashion-matches/batch/status');
    const j = await r.json();
    if (j.state?.is_running) startBatchPolling();
  } catch (_) {}
}

// ══ ADD MODAL ════════════════════════════════

function openAddModal(occ, role) {
  addingCtx = { occ, role };
  document.getElementById('modalOccRole').textContent =
    `Thêm vào: ${OCC_LABELS[occ] || occ} → ${ROLE_LABELS[role]?.label || role}`;
  document.getElementById('modalSearch').value = '';
  document.getElementById('modalResults').innerHTML = '<p style="color:var(--muted-fg);font-size:13px;padding:10px 0;">Nhập để tìm...</p>';
  document.getElementById('addModal').style.display = 'flex';
  setTimeout(() => document.getElementById('modalSearch').focus(), 80);
}

function closeAddModal(e) {
  if (e && e.target !== document.getElementById('addModal')) return;
  document.getElementById('addModal').style.display = 'none';
  addingCtx = null;
}

async function onModalSearch(val) {
  clearTimeout(modalSearchTimer);
  const container = document.getElementById('modalResults');
  if (!val.trim()) { container.innerHTML = ''; return; }
  modalSearchTimer = setTimeout(async () => {
    try {
      const r = await fetch(`/api/product-desc/list?limit=12&page=1&search=${encodeURIComponent(val)}`);
      const j = await r.json();
      const items = j.items || [];
      if (!items.length) {
        container.innerHTML = '<p style="color:var(--muted-fg);font-size:13px;padding:10px 0;">Không tìm thấy</p>';
        return;
      }
      container.innerHTML = items.map(p => `
        <div class="fm-modal-result" onclick="addItemFromModal('${esc(p.code)}','${esc(p.name)}','${esc(p.image_url||'')}')">
          <img src="${esc(p.image_url||'')}" onerror="this.style.display='none'" style="width:38px;height:38px;object-fit:cover;border-radius:6px;border:1px solid var(--border);">
          <div>
            <div class="mr-name">${esc(p.name)}</div>
            <div class="mr-meta">${esc(p.code)}</div>
          </div>
        </div>`).join('');
    } catch { container.innerHTML = '<p style="color:var(--muted-fg);">Lỗi tìm kiếm</p>'; }
  }, 280);
}

function addItemFromModal(code, name, image) {
  if (!addingCtx) return;
  const { occ, role } = addingCtx;
  if (!aiMatches[occ]) aiMatches[occ] = {};
  if (!aiMatches[occ][role]) aiMatches[occ][role] = [];
  if (aiMatches[occ][role].some(x => x.code === code)) {
    showToast('⚠️ Đã có trong danh sách', 'error'); return;
  }
  aiMatches[occ][role].push({ code, name, image, score: 70, reason: 'Thêm thủ công' });
  document.getElementById('addModal').style.display = 'none';
  addingCtx = null; activeGroupTab = occ;
  renderMatchesTab();
  showToast(`✅ Đã thêm ${name}`, 'success');
}

// ══ UTILS ════════════════════════════════════

function esc(str) {
  return String(str || '')
    .replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')
    .replace(/"/g,'&quot;').replace(/'/g,'&#39;');
}

let toastTimer = null;
function showToast(msg, type = '') {
  const el = document.getElementById('toast');
  el.textContent = msg;
  el.className = `fm-toast ${type} show`;
  clearTimeout(toastTimer);
  toastTimer = setTimeout(() => el.classList.remove('show'), 3200);
}

// ══ RULES MODAL ══════════════════════════════

let rulesData = null;
let activeRulesTab = 'weights';

async function openRulesModal() {
  document.getElementById('rulesModal').style.display = 'flex';
  if (!rulesData) await fetchRules();
  renderRulesTab(activeRulesTab);
}

function closeRulesModal(e) {
  if (e && e.target !== document.getElementById('rulesModal')) return;
  document.getElementById('rulesModal').style.display = 'none';
}

async function fetchRules() {
  try {
    const r = await fetch('/api/fashion-matches/rules/config');
    const j = await r.json();
    rulesData = j.rules || j;
  } catch (e) {
    document.getElementById('rulesBody').innerHTML =
      '<p style="color:var(--error);">Lỗi tải rules: ' + e.message + '</p>';
  }
}

function switchRulesTab(tab, btn) {
  document.querySelectorAll('#rulesModal .fm-tab').forEach(b => b.classList.remove('active'));
  btn.classList.add('active');
  activeRulesTab = tab;
  renderRulesTab(tab);
}

function renderRulesTab(tab) {
  const body = document.getElementById('rulesBody');
  if (!rulesData) { body.innerHTML = '<p style="color:var(--muted-fg);">Đang tải...</p>'; return; }
  if (tab === 'weights') renderWeights(body);
  else if (tab === 'colors') renderColorMatrix(body);
  else if (tab === 'styles') renderStyleMatrix(body);
  else if (tab === 'roles') renderRoles(body);
  else if (tab === 'occasions') renderOccasions(body);
}

function renderWeights(body) {
  const w = rulesData.score_weights || {};
  const total = Object.values(w).reduce((s,v) => s+v, 0);
  body.innerHTML = `
    <div style="margin-bottom:16px;">
      <div style="font-size:13px;color:var(--muted-fg);margin-bottom:12px;">
        Tổng điểm tối đa = <strong>${total}</strong> điểm
      </div>
      ${Object.entries(w).map(([key, val]) => {
        const pct = Math.round(val/total*100);
        const labels = {color:'🎨 Màu sắc',style:'👗 Style',occasion:'📅 Occasion',role:'📦 Role',diversity:'🔀 Diversity'};
        return `
          <div style="margin-bottom:12px;">
            <div style="display:flex;justify-content:space-between;margin-bottom:4px;">
              <span style="font-size:13px;font-weight:600;">${labels[key] || key}</span>
              <span style="font-size:13px;color:var(--primary);font-weight:700;">${val}đ (${pct}%)</span>
            </div>
            <div style="height:8px;background:var(--border);border-radius:999px;overflow:hidden;">
              <div style="height:100%;width:${pct}%;background:var(--primary);border-radius:999px;transition:width .3s;"></div>
            </div>
            <div style="display:flex;justify-content:space-between;margin-top:4px;">
              <input type="range" min="0" max="50" value="${val}"
                oninput="updateWeight('${key}', this.value)"
                style="width:100%;accent-color:var(--primary);">
            </div>
          </div>`;
      }).join('')}
    </div>
    <div style="font-size:11px;color:var(--muted-fg);background:var(--muted);padding:10px 12px;border-radius:8px;">
      💡 Kéo slider để thay đổi trọng số. Bấm <strong>Lưu rules</strong> để áp dụng vào engine.
    </div>`;
}

function updateWeight(key, val) {
  if (!rulesData.score_weights) rulesData.score_weights = {};
  rulesData.score_weights[key] = parseInt(val);
  // Re-render just the total display
  const total = Object.values(rulesData.score_weights).reduce((s,v) => s+v, 0);
  const totalEl = document.querySelector('#rulesBody strong');
  if (totalEl) totalEl.textContent = total;
}

function renderColorMatrix(body) {
  const matrix = rulesData.color_compatibility || {};
  const colors = Object.keys(matrix);
  if (!colors.length) { body.innerHTML = '<p style="color:var(--muted-fg);">Chưa có dữ liệu màu</p>'; return; }

  const getCls = v => v >= 0.8 ? 'score-high' : v >= 0.5 ? 'score-mid' : v > 0 ? 'score-low' : '';
  body.innerHTML = `
    <div style="font-size:12px;color:var(--muted-fg);margin-bottom:12px;">Điểm 0→1 — mức độ hợp màu khi phối cùng nhau</div>
    <div class="table-wrap">
      <table class="table" style="font-size:11px;text-align:center;">
        <thead>
          <tr>
            <th style="background:var(--muted);">Màu ↓ / ↑</th>
            ${colors.map(c => `<th>${esc(c)}</th>`).join('')}
          </tr>
        </thead>
        <tbody>
          ${colors.map(row => `
            <tr>
              <th style="background:var(--muted);font-weight:600;text-align:left;">${esc(row)}</th>
              ${colors.map(col => {
                const val = (matrix[row] || {})[col] ?? (matrix[col] || {})[row] ?? '-';
                const cls = typeof val === 'number' ? getCls(val) : '';
                return `<td><span class="match-score ${cls}" style="font-size:10px;">${val !== '-' ? val : '-'}</span></td>`;
              }).join('')}
            </tr>`).join('')}
        </tbody>
      </table>
    </div>`;
}

function renderStyleMatrix(body) {
  const matrix = rulesData.style_compatibility || {};
  const styles = Object.keys(matrix);
  if (!styles.length) { body.innerHTML = '<p style="color:var(--muted-fg);">Chưa có dữ liệu style</p>'; return; }

  const getCls = v => v >= 0.8 ? 'score-high' : v >= 0.5 ? 'score-mid' : v > 0 ? 'score-low' : '';
  body.innerHTML = `
    <div style="font-size:12px;color:var(--muted-fg);margin-bottom:12px;">Điểm tương thích phong cách khi phối cùng</div>
    <div class="table-wrap">
      <table class="table" style="font-size:11px;text-align:center;">
        <thead>
          <tr>
            <th>Style ↓ / ↑</th>
            ${styles.map(s => `<th>${esc(s)}</th>`).join('')}
          </tr>
        </thead>
        <tbody>
          ${styles.map(row => `
            <tr>
              <th style="background:var(--muted);font-weight:600;text-align:left;">${esc(row)}</th>
              ${styles.map(col => {
                const val = (matrix[row] || {})[col] ?? '-';
                const cls = typeof val === 'number' ? getCls(val) : '';
                return `<td><span class="match-score ${cls}" style="font-size:10px;">${val !== '-' ? val : '-'}</span></td>`;
              }).join('')}
            </tr>`).join('')}
        </tbody>
      </table>
    </div>`;
}

function renderRoles(body) {
  const roles = rulesData.role_mappings || {};
  body.innerHTML = `
    <div style="font-size:12px;color:var(--muted-fg);margin-bottom:12px;">
      Mapping loại SP → role trong công thức phối đồ
    </div>
    ${Object.entries(roles).map(([role, keywords]) => `
      <div style="margin-bottom:16px;">
        <div style="font-size:13px;font-weight:700;margin-bottom:8px;display:flex;align-items:center;gap:8px;">
          ${role === 'bottom' ? '👖' : role === 'outerwear' ? '🧥' : '👜'}
          <span style="text-transform:capitalize;">${esc(role)}</span>
          <span class="badge badge-info">${keywords.length} loại SP</span>
        </div>
        <div style="display:flex;flex-wrap:wrap;gap:6px;">
          ${keywords.map(k => `<span class="badge badge-muted" style="font-size:11px;">${esc(k)}</span>`).join('')}
        </div>
      </div>`).join('')}`;
}

function renderOccasions(body) {
  const occs = rulesData.occasion_style_boost || {};
  const OCC_VI = {
    di_lam_cong_so: 'Đi làm công sở',
    di_choi_dao_pho: 'Đi chơi / dạo phố',
    o_nha_mac_ngu: 'Ở nhà / mặc ngủ',
    du_lich: 'Du lịch'
  };
  body.innerHTML = `
    <div style="font-size:12px;color:var(--muted-fg);margin-bottom:12px;">
      Phong cách được ưu tiên cho từng dịp — boost điểm thêm khi phối đúng dịp
    </div>
    <div class="table-wrap">
      <table class="table" style="font-size:12px;">
        <thead><tr><th>Dịp</th><th>Style ưu tiên</th><th>Boost</th></tr></thead>
        <tbody>
          ${Object.entries(occs).map(([occ, styleMap]) =>
            Object.entries(styleMap).map(([style, boost], i) => `
              <tr>
                ${i === 0 ? `<td rowspan="${Object.keys(styleMap).length}" style="font-weight:600;vertical-align:top;">
                  ${OCC_VI[occ] || occ}
                </td>` : ''}
                <td>${esc(style)}</td>
                <td><span class="match-score score-high">+${boost}</span></td>
              </tr>`).join('')
          ).join('')}
        </tbody>
      </table>
    </div>`;
}

async function saveRules() {
  if (!rulesData) return;
  try {
    const res = await fetch('/api/fashion-matches/rules/config', {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(rulesData),
    });
    const j = await res.json();
    showToast(j.ok ? '✅ Đã lưu fashion_rules.json' : `❌ ${j.error}`, j.ok ? 'success' : 'error');
  } catch (e) { showToast('❌ Lỗi lưu rules', 'error'); }
}

// ══ SCORE TESTER ════════════════════════════

async function runScoreTest() {
  const sourceCode = currentCode;
  const targetCode = document.getElementById('testTargetCode').value.trim();
  const resultEl   = document.getElementById('scoreTestResult');

  if (!sourceCode) { showToast('⚠️ Chưa chọn sản phẩm nguồn', 'error'); return; }
  if (!targetCode) { showToast('⚠️ Nhập mã SP đích', 'error'); return; }

  resultEl.innerHTML = '<p style="color:var(--muted-fg);font-size:13px;">⏳ Đang tính điểm...</p>';

  try {
    const res = await fetch(`/api/fashion-matches/score-test`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ source_code: sourceCode, target_code: targetCode }),
    });
    const j = await res.json();

    if (!j.ok) {
      resultEl.innerHTML = `<p style="color:var(--error);">❌ ${j.error || 'Lỗi tính điểm'}</p>`;
      return;
    }

    const d = j.result || {};
    const breakdown = d.breakdown || {};
    const total = d.total_score || 0;
    const scoreCls = total >= 75 ? 'score-high' : total >= 50 ? 'score-mid' : 'score-low';

    const breakdownRows = Object.entries(breakdown).map(([key, info]) => {
      const labels = {color:'🎨 Màu sắc',style:'👗 Style',occasion:'📅 Occasion',role:'📦 Role',diversity:'🔀 Diversity'};
      const pct = info.max ? Math.round(info.score / info.max * 100) : 0;
      return `
        <tr>
          <td style="font-weight:500;">${labels[key] || key}</td>
          <td><span class="match-score ${info.score >= info.max*0.7 ? 'score-high' : info.score >= info.max*0.4 ? 'score-mid' : 'score-low'}">${info.score}</span></td>
          <td style="color:var(--muted-fg);">/ ${info.max}</td>
          <td>
            <div style="height:5px;background:var(--border);border-radius:999px;overflow:hidden;min-width:60px;">
              <div style="height:100%;width:${pct}%;background:var(--primary);border-radius:999px;"></div>
            </div>
          </td>
          <td style="font-size:11px;color:var(--muted-fg);">${esc(info.reason || '')}</td>
        </tr>`;
    }).join('');

    resultEl.innerHTML = `
      <div style="display:flex;align-items:center;gap:12px;margin-bottom:16px;padding:12px 14px;background:var(--card);border:1px solid var(--border);border-radius:8px;">
        <div style="font-size:32px;font-weight:800;" class="match-score ${scoreCls} " style="padding:8px 16px;">${total}</div>
        <div>
          <div style="font-size:14px;font-weight:700;">${esc(d.target_name || targetCode)}</div>
          <div style="font-size:12px;color:var(--muted-fg);">${esc(d.roles_str || '')} · ${esc(d.target_code || '')}</div>
          <div style="font-size:12px;margin-top:4px;">${esc(d.reason || '')}</div>
        </div>
      </div>
      <div class="table-wrap">
        <table class="table" style="font-size:12px;">
          <thead><tr><th>Tiêu chí</th><th>Điểm</th><th>Tối đa</th><th>Tiến độ</th><th>Lý do</th></tr></thead>
          <tbody>${breakdownRows}</tbody>
        </table>
      </div>`;
  } catch (e) {
    resultEl.innerHTML = `<p style="color:var(--error);">❌ Lỗi: ${e.message}</p>`;
  }
}
