// admin.js — CMS 전체 관리
import { createStore } from '/assets/store.js';
import { uploadImages } from '/assets/modules/image-upload.js';

const cfg = window.__TKTX_CONFIG__;
const store = createStore(cfg);

const SESSION_KEY = 'tktx_admin_session';
const SESSION_TTL = 1000 * 60 * 60 * 4; // 4시간

// ============================================================
// 부팅
// ============================================================
(async function () {
  if (isSessionValid()) {
    showDashboard();
  } else {
    showLogin();
  }
})();

// ============================================================
// Session
// ============================================================
function isSessionValid() {
  try {
    const s = JSON.parse(sessionStorage.getItem(SESSION_KEY) || '{}');
    return s.at && (Date.now() - s.at) < SESSION_TTL;
  } catch { return false; }
}
function setSession() {
  sessionStorage.setItem(SESSION_KEY, JSON.stringify({ at: Date.now() }));
}
function clearSession() {
  sessionStorage.removeItem(SESSION_KEY);
}

// ============================================================
// Login
// ============================================================
function showLogin() {
  document.getElementById('login-screen').style.display = 'flex';
  document.getElementById('dashboard').style.display = 'none';
  const form = document.getElementById('login-form');
  form.onsubmit = async (e) => {
    e.preventDefault();
    const pw = document.getElementById('login-pw').value;
    const ok = await store.adminLogin(pw);
    if (ok) {
      setSession();
      showDashboard();
    } else {
      document.getElementById('login-error').textContent = '비밀번호가 일치하지 않습니다.';
    }
  };
}

// ============================================================
// Dashboard
// ============================================================
function showDashboard() {
  document.getElementById('login-screen').style.display = 'none';
  document.getElementById('dashboard').style.display = 'flex';

  document.getElementById('logout-btn').onclick = () => {
    clearSession();
    location.reload();
  };

  document.querySelectorAll('.admin-nav .tab').forEach(tab => {
    tab.onclick = () => {
      document.querySelectorAll('.admin-nav .tab').forEach(t => t.classList.remove('is-active'));
      tab.classList.add('is-active');
      renderPanel(tab.dataset.tab);
    };
  });

  // 우측하단 플로팅 저장 버튼 — 모든 패널에서 active form 자동 감지 + submit
  setupFloatingSave();

  renderPanel('hero');
}

// ============================================================
// Floating Save — 우측하단 고정 버튼 (모든 admin 패널 공용)
// 클릭 시 현재 보이는 패널의 form 의 submit 버튼을 트리거 (없으면 저장 버튼 텍스트가 들어간 버튼)
// ============================================================
function setupFloatingSave() {
  const fab = document.getElementById('floating-save-btn');
  if (!fab) return;
  fab.style.display = 'inline-flex';

  fab.addEventListener('click', () => {
    const main = document.getElementById('admin-main');
    if (!main) return;
    // 1순위: 패널 안의 첫 form 을 직접 submit
    const form = main.querySelector('form');
    if (form) {
      // FormData submit 이벤트 트리거 (panelXxx 가 등록한 onsubmit 핸들러 발동)
      if (typeof form.requestSubmit === 'function') {
        form.requestSubmit();
      } else {
        const evt = new Event('submit', { bubbles: true, cancelable: true });
        form.dispatchEvent(evt);
        if (!evt.defaultPrevented) form.submit();
      }
      return;
    }
    // 2순위: form 없는 패널(예: floating, list 패널)에서는 "저장" 텍스트가 들어간 버튼 클릭
    const saveBtn = Array.from(main.querySelectorAll('button')).find(b => /저장/.test(b.textContent || ''));
    if (saveBtn) { saveBtn.click(); return; }
    // 3순위: 안내
    if (typeof toast === 'function') toast('이 패널에는 저장할 내용이 없습니다');
  });

  // 패널 전환 시 버튼 상태 초기화 (저장 후 disabled 해제 등)
  const observer = new MutationObserver(() => {
    fab.disabled = false;
  });
  observer.observe(document.getElementById('admin-main'), { childList: true, subtree: false });
}

// ============================================================
// Panels
// ============================================================
async function renderPanel(name) {
  const main = document.getElementById('admin-main');
  main.innerHTML = '<div class="empty-state">로딩 중...</div>';

  switch (name) {
    case 'hero': return panelHero(main);
    case 'mente': return panelMente(main);
    case 'footer': return panelFooter(main);
    case 'main_channel': return panelMainChannel(main);
    case 'urgent': return panelUrgent(main);
    case 'notices': return panelList(main, 'notices', '공지사항', noticeFields, n => n.title);
    case 'products': return panelList(main, 'products', '제품', productFields, p => `${p.name} — ${Number(p.price).toLocaleString()} ₩`);
    case 'qna': return panelList(main, 'qna', 'QnA', qnaFields, q => q.question);
    case 'reviews': return panelReviews(main);
    case 'inquiries': return panelInquiries(main);
    case 'floating': return panelFloating(main);
    case 'external': return panelList(main, 'external_links', '외부 링크', externalFields, l => `${l.label} — ${l.position}`);
    case 'security': return panelSecurity(main);
  }
}

// ----- Hero -----
async function panelHero(main) {
  const cms = await store.getCmsConfig();
  const h = cms.hero || {};
  main.innerHTML = `
    <h2 class="panel-title">히어로 (Hero)</h2>
    <form class="admin-form" id="form-hero">
      <div>
        <label>태그라인 (상단 작은 글씨)</label>
        <input name="tagline" value="${esc(h.tagline)}" maxlength="60">
      </div>
      <div>
        <label>메인 타이틀 (큰 네온 글씨)</label>
        <input name="title" value="${esc(h.title)}" maxlength="40" required>
      </div>
      <div>
        <label>서브타이틀</label>
        <input name="subtitle" value="${esc(h.subtitle)}" maxlength="100">
      </div>
      <div style="border-top:1px solid var(--border-subtle);padding-top:14px;margin-top:6px;">
        <label style="color:var(--text-muted);font-size:11px;letter-spacing:1px;">하단 스탬프 — [ A ] · [ B ] · [ C ] 형태로 노출</label>
      </div>
      <div class="row">
        <div>
          <label>스탬프 1 (좌)</label>
          <input name="stamp1" value="${esc(h.stamp1)}" maxlength="20" placeholder="정품 인증">
        </div>
        <div>
          <label>스탬프 2 (중)</label>
          <input name="stamp2" value="${esc(h.stamp2)}" maxlength="20" placeholder="직구 전용">
        </div>
        <div>
          <label>스탬프 3 (우)</label>
          <input name="stamp3" value="${esc(h.stamp3)}" maxlength="20" placeholder="SINCE 2026">
        </div>
      </div>
      <button type="submit" class="btn-primary">저장</button>
    </form>
  `;
  document.getElementById('form-hero').onsubmit = async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    await store.setCmsConfig('hero', Object.fromEntries(fd));
    toast('저장되었습니다');
  };
}

// ----- Main Channel CTA (메인 채널 강조 버튼 — 2026-04-28 추가) -----
async function panelMainChannel(main) {
  const cms = await store.getCmsConfig();
  const m = cms.main_channel || {};
  main.innerHTML = `
    <h2 class="panel-title">메인 채널 강조 CTA</h2>
    <p style="color:var(--text-muted);margin-bottom:16px;font-size:13px;">문의 4채널 그리드 아래 노출되는 큰 강조 버튼. URL이 비어 있으면 자동으로 숨김.</p>
    <form class="admin-form" id="form-main-channel">
      <div class="toggle-row">
        <input type="checkbox" id="mc-enabled" name="enabled" ${m.enabled !== false ? 'checked' : ''}>
        <label for="mc-enabled" style="margin:0;text-transform:none;letter-spacing:0;font-size:14px;color:var(--text-secondary);">노출 활성화</label>
      </div>
      <div>
        <label>아이콘 (telegram / kakao / line / instagram)</label>
        <input name="icon" value="${esc(m.icon) || 'telegram'}" maxlength="20" placeholder="telegram">
      </div>
      <div>
        <label>라벨 (큰 글씨)</label>
        <input name="label" value="${esc(m.label)}" maxlength="40" placeholder="Telegram 메인 채널">
      </div>
      <div>
        <label>서브라벨 (작은 글씨, 선택)</label>
        <input name="sublabel" value="${esc(m.sublabel)}" maxlength="80" placeholder="실시간 응대 · 공지 + 신규 입고">
      </div>
      <div>
        <label>URL (필수 — 비우면 자동 숨김)</label>
        <input type="url" name="url" value="${esc(m.url)}" maxlength="300" placeholder="https://t.me/...">
      </div>
      <button type="submit" class="btn-primary">저장</button>
    </form>
  `;
  document.getElementById('form-main-channel').onsubmit = async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    const obj = Object.fromEntries(fd);
    obj.enabled = fd.get('enabled') === 'on';
    await store.setCmsConfig('main_channel', obj);
    toast('저장되었습니다');
  };
}

// ----- Footer (사용자 자유 수정 — 2026-04-28 추가) -----
async function panelFooter(main) {
  const cms = await store.getCmsConfig();
  const f = cms.footer || {};
  main.innerHTML = `
    <h2 class="panel-title">푸터 (Footer)</h2>
    <p style="color:var(--text-muted);margin-bottom:16px;font-size:13px;">사이트 맨 아래 표시되는 3줄 텍스트. 빈칸 저장 시 마지막 값 유지.</p>
    <form class="admin-form" id="form-footer">
      <div>
        <label>1줄 — 브랜드명 (네온 빨강)</label>
        <input name="brand_line" value="${esc(f.brand_line)}" maxlength="40">
      </div>
      <div>
        <label>2줄 — 슬로건 / 안내</label>
        <input name="line1" value="${esc(f.line1)}" maxlength="120">
      </div>
      <div>
        <label>3줄 — 저작권 / 회사 정보</label>
        <input name="line2" value="${esc(f.line2)}" maxlength="120">
      </div>
      <button type="submit" class="btn-primary">저장</button>
    </form>
  `;
  document.getElementById('form-footer').onsubmit = async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    await store.setCmsConfig('footer', Object.fromEntries(fd));
    toast('저장되었습니다');
  };
}

// ----- Mente -----
async function panelMente(main) {
  const cms = await store.getCmsConfig();
  const m = cms.mente || {};
  main.innerHTML = `
    <h2 class="panel-title">멘트 (브랜드 인트로)</h2>
    <form class="admin-form" id="form-mente">
      <div>
        <label>본문 (줄바꿈 자유)</label>
        <textarea name="body" rows="6" maxlength="800">${esc(m.body)}</textarea>
      </div>
      <button type="submit" class="btn-primary">저장</button>
    </form>
  `;
  document.getElementById('form-mente').onsubmit = async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    await store.setCmsConfig('mente', Object.fromEntries(fd));
    toast('저장되었습니다');
  };
}

// ----- Urgent -----
async function panelUrgent(main) {
  const cms = await store.getCmsConfig();
  const u = cms.urgent_notice || {};
  main.innerHTML = `
    <h2 class="panel-title">긴급공지 팝업</h2>
    <p style="color:var(--text-muted);margin-bottom:16px;font-size:13px;">사이트 진입 시 자동으로 뜨는 팝업. 방문자가 닫으면 24시간 동안 다시 안 뜸.</p>
    <form class="admin-form" id="form-urgent">
      <div class="toggle-row">
        <input type="checkbox" id="u-enabled" name="enabled" ${u.enabled ? 'checked' : ''}>
        <label for="u-enabled" style="margin:0;text-transform:none;letter-spacing:0;font-size:14px;color:var(--text-secondary);">팝업 활성화</label>
      </div>
      <div>
        <label>제목</label>
        <input name="title" value="${esc(u.title)}" maxlength="60">
      </div>
      <div>
        <label>본문</label>
        <textarea name="body" rows="4" maxlength="500">${esc(u.body)}</textarea>
      </div>
      <div class="row">
        <div>
          <label>버튼 라벨 (선택)</label>
          <input name="cta_label" id="u-cta-label" value="${esc(u.cta_label)}" maxlength="20" placeholder="예: 자세히 보기">
        </div>
        <div>
          <label>버튼 링크 (선택)</label>
          <input name="cta_url" id="u-cta-url" value="${esc(u.cta_url)}" maxlength="200" placeholder="# 또는 https://...">
        </div>
      </div>
      <div>
        <label>빠른 링크 (클릭 시 위 두 칸 자동 입력)</label>
        <div id="u-preset-row" style="display:flex;flex-wrap:wrap;gap:8px;margin-top:6px;">
          <button type="button" class="u-preset" data-label="멘트 보기" data-url="#mente">멘트</button>
          <button type="button" class="u-preset" data-label="공지사항 보기" data-url="#notices">공지</button>
          <button type="button" class="u-preset" data-label="제품 보기" data-url="#products">제품</button>
          <button type="button" class="u-preset" data-label="QnA 보기" data-url="#qna">QnA</button>
          <button type="button" class="u-preset" data-label="후기 보기" data-url="#reviews">리뷰</button>
          <button type="button" class="u-preset" data-label="문의하기" data-url="#inquiry">문의</button>
        </div>
        <p style="color:var(--text-muted);margin-top:8px;font-size:12px;line-height:1.6;">
          ※ 고객이 버튼 클릭하면 해당 섹션으로 부드럽게 이동 + 팝업 자동 닫힘.<br>
          ※ 외부 URL(https://...)은 새 탭에서 열림 + 팝업 자동 닫힘.
        </p>
      </div>
      <button type="submit" class="btn-primary">저장</button>
    </form>
  `;
  // 빠른 링크 프리셋 — 버튼 클릭 시 두 칸 자동 입력
  document.querySelectorAll('#u-preset-row .u-preset').forEach((b) => {
    b.addEventListener('click', () => {
      document.getElementById('u-cta-label').value = b.dataset.label || '';
      document.getElementById('u-cta-url').value = b.dataset.url || '';
    });
  });
  document.getElementById('form-urgent').onsubmit = async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    const obj = Object.fromEntries(fd);
    obj.enabled = fd.get('enabled') === 'on';
    await store.setCmsConfig('urgent_notice', obj);
    toast('저장되었습니다');
  };
}

// ----- Floating -----
async function panelFloating(main) {
  const cms = await store.getCmsConfig();
  const f = cms.floating || {};
  const ik = cms.inquiry_kakao || {};

  const LABELS = { telegram: '텔레그램', line: '라인', instagram: '인스타그램', kakao: '카카오톡' };
  const DEFAULT_ORDER = ['telegram', 'line', 'instagram', 'kakao'];
  let order = Array.isArray(f.order) ? f.order.filter(k => LABELS[k]) : [...DEFAULT_ORDER];
  for (const k of DEFAULT_ORDER) if (!order.includes(k)) order.push(k);

  function renderGrid() {
    const grid = document.getElementById('floating-grid');
    if (!grid) return;
    grid.innerHTML = order.map((key, idx) => {
      const v = f[key] || {};
      const label = LABELS[key];
      return `
        <div class="admin-form" data-row="${key}" style="margin-bottom:16px; position:relative;">
          <div style="display:flex; align-items:center; gap:10px; margin-bottom:10px;">
            <span style="font-family:var(--font-display);font-weight:900;letter-spacing:2px;color:var(--text-muted);font-size:13px;width:20px;">${idx + 1}.</span>
            <h3 style="margin:0;font-family:var(--font-display);font-weight:900;letter-spacing:3px;text-transform:uppercase;font-size:14px;flex:1;">${label}</h3>
            <button type="button" class="btn-order-up" data-key="${key}" ${idx === 0 ? 'disabled' : ''}
              style="width:34px;height:34px;border:1px solid var(--border-subtle);background:transparent;color:var(--text-primary);cursor:pointer;border-radius:6px;${idx === 0 ? 'opacity:0.3;cursor:not-allowed;' : ''}">▲</button>
            <button type="button" class="btn-order-down" data-key="${key}" ${idx === order.length - 1 ? 'disabled' : ''}
              style="width:34px;height:34px;border:1px solid var(--border-subtle);background:transparent;color:var(--text-primary);cursor:pointer;border-radius:6px;${idx === order.length - 1 ? 'opacity:0.3;cursor:not-allowed;' : ''}">▼</button>
          </div>
          <div class="toggle-row">
            <input type="checkbox" id="${key}-enabled" data-channel="${key}" data-key="enabled" ${v.enabled !== false ? 'checked' : ''}>
            <label for="${key}-enabled" style="margin:0;text-transform:none;letter-spacing:0;font-size:13px;color:var(--text-secondary);">활성화 (꺼두면 흑백 + 빨간 X)</label>
          </div>
          <div>
            <label>URL</label>
            <input type="url" data-channel="${key}" data-key="url" value="${esc(v.url)}" placeholder="https://...">
          </div>
        </div>
      `;
    }).join('');

    // ▲▼ 핸들러 바인딩
    grid.querySelectorAll('.btn-order-up').forEach(btn => {
      btn.onclick = () => {
        const key = btn.dataset.key;
        const i = order.indexOf(key);
        if (i > 0) { [order[i-1], order[i]] = [order[i], order[i-1]]; renderGrid(); }
      };
    });
    grid.querySelectorAll('.btn-order-down').forEach(btn => {
      btn.onclick = () => {
        const key = btn.dataset.key;
        const i = order.indexOf(key);
        if (i < order.length - 1) { [order[i+1], order[i]] = [order[i], order[i+1]]; renderGrid(); }
      };
    });
  }

  main.innerHTML = `
    <h2 class="panel-title">우측 하단 플로팅 4채널</h2>
    <p style="color:var(--text-muted);margin-bottom:14px;font-size:13px;">▲▼ 버튼으로 노출 순서 변경 가능 (위에 있을수록 우측 상단). 4채널 그리드 카드도 동일 순서로 동기화.</p>
    <div id="floating-grid"></div>

    <h2 class="panel-title" style="margin-top:40px;">문의 영역 — 카톡 채널 블록</h2>
    <p style="color:var(--text-muted);margin-bottom:16px;font-size:13px;">문의 폼 위에 노란 카톡 채널 버튼 표시 여부.</p>
    <form class="admin-form" id="form-iq-kakao">
      <div class="toggle-row">
        <input type="checkbox" id="iqk-enabled" name="enabled" ${ik.enabled ? 'checked' : ''}>
        <label for="iqk-enabled" style="margin:0;text-transform:none;letter-spacing:0;font-size:14px;color:var(--text-secondary);">카톡 채널 블록 표시</label>
      </div>
      <div>
        <label>카톡 채널 URL</label>
        <input type="url" name="url" value="${esc(ik.url)}" placeholder="https://pf.kakao.com/_xxxxx">
      </div>
      <div>
        <label>버튼 라벨</label>
        <input name="label" value="${esc(ik.label) || '카톡 채널로 빠른 문의'}" maxlength="40">
      </div>
      <button type="submit" class="btn-primary">저장</button>
    </form>

    <button class="btn-primary" id="save-floating" style="margin-top:24px;">플로팅 4채널 + 순서 저장</button>
  `;

  renderGrid();

  document.getElementById('save-floating').onclick = async () => {
    const next = { telegram:{}, kakao:{}, line:{}, instagram:{}, order: [...order] };
    document.querySelectorAll('[data-channel]').forEach(el => {
      const ch = el.dataset.channel;
      const key = el.dataset.key;
      if (key === 'enabled') next[ch].enabled = el.checked;
      else next[ch][key] = el.value;
    });
    await store.setCmsConfig('floating', next);
    toast('플로팅 저장 완료 (순서 포함)');
  };

  document.getElementById('form-iq-kakao').onsubmit = async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    const obj = Object.fromEntries(fd);
    obj.enabled = fd.get('enabled') === 'on';
    await store.setCmsConfig('inquiry_kakao', obj);
    toast('저장되었습니다');
  };

  // 2026-04-29: 문의 인트로 멘트 CMS (사용자 요청)
  const intro = (cms.inquiry && cms.inquiry.intro) || '편하신 채널로 연락 주세요. 빠르게 답변드리겠습니다.';
  const introBlock = document.createElement('div');
  introBlock.style.marginTop = '40px';
  introBlock.innerHTML = `
    <h2 class="panel-title">문의 섹션 인트로 멘트</h2>
    <p style="color:var(--text-muted);margin-bottom:14px;font-size:13px;">"문의" 섹션 4채널 그리드 위에 노출되는 한 줄 안내 문구.</p>
    <form class="admin-form" id="form-inquiry-intro">
      <div>
        <label>인트로 멘트</label>
        <input name="intro" value="${esc(intro)}" maxlength="120" placeholder="편하신 채널로 연락 주세요. 빠르게 답변드리겠습니다.">
      </div>
      <button type="submit" class="btn-primary">저장</button>
    </form>
  `;
  main.appendChild(introBlock);
  document.getElementById('form-inquiry-intro').onsubmit = async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    await store.setCmsConfig('inquiry', { intro: fd.get('intro') || '' });
    toast('인트로 멘트 저장 완료');
  };
}

// ----- Security / PW -----
async function panelSecurity(main) {
  main.innerHTML = `
    <h2 class="panel-title">보안 / 비밀번호 변경</h2>
    <form class="admin-form" id="form-pw">
      <div>
        <label>현재 비밀번호</label>
        <input name="current" type="password" required>
      </div>
      <div>
        <label>새 비밀번호 (8자 이상)</label>
        <input name="next" type="password" minlength="6" required>
      </div>
      <div>
        <label>새 비밀번호 확인</label>
        <input name="confirm" type="password" minlength="6" required>
      </div>
      <button type="submit" class="btn-primary">변경</button>
    </form>
  `;
  document.getElementById('form-pw').onsubmit = async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    if (fd.get('next') !== fd.get('confirm')) { alert('새 비밀번호 확인이 일치하지 않습니다.'); return; }
    const result = await store.changeAdminPassword(fd.get('current'), fd.get('next'));
    if (result.ok) {
      toast('비밀번호 변경 완료');
      e.target.reset();
    } else if (result.reason === 'wrong_current_pw') {
      alert('현재 비밀번호가 일치하지 않습니다.');
    } else {
      alert('변경 실패: ' + result.reason);
    }
  };
}

// ----- Reviews (admin은 PW 무관 삭제) -----
async function panelReviews(main) {
  const items = await store.list('reviews');
  main.innerHTML = `<h2 class="panel-title">후기 관리 (admin 무권한 삭제)</h2>` + (
    items.length ? `<div class="admin-list">${items.map(r => `
      <div class="admin-list-item" data-id="${r.id}">
        <div class="head">
          <span class="name">${'★'.repeat(r.rating || 5)} ${r.is_private ? '(비공개)' : ''} — ${esc(r.author)}</span>
          <span class="meta">${formatDate(r.created_at)}</span>
        </div>
        <div class="body">${esc(r.body)}</div>
        <div class="actions"><button class="danger" data-del="${r.id}">삭제</button></div>
      </div>
    `).join('')}</div>` : `<div class="empty-state">등록된 후기가 없습니다.</div>`
  );

  main.querySelectorAll('[data-del]').forEach(b => {
    b.onclick = async () => {
      if (!confirm('정말 삭제하시겠습니까?')) return;
      await store.remove('reviews', Number(b.dataset.del));
      toast('삭제 완료');
      panelReviews(main);
    };
  });
}

// ----- Inquiries -----
async function panelInquiries(main) {
  const items = await store.list('inquiries');
  main.innerHTML = `<h2 class="panel-title">문의 (방문자 → admin)</h2>` + (
    items.length ? `<div class="admin-list">${items.map(q => `
      <div class="admin-list-item" data-id="${q.id}">
        <div class="head">
          <span class="name">${esc(q.name)} ${q.is_private ? '(비공개)' : ''} ${q.contact ? `— ${esc(q.contact)}` : ''}</span>
          <span class="meta">${formatDate(q.created_at)}</span>
        </div>
        <div class="body">${esc(q.body)}</div>
        ${q.admin_reply ? `<div class="body" style="margin-top:8px;padding:12px;background:rgba(255,42,42,0.06);border-left:3px solid var(--neon-red);"><b style="color:var(--neon-red);font-family:var(--font-display);letter-spacing:2px;font-size:11px;">REPLY</b><br>${esc(q.admin_reply)}</div>` : ''}
        <div class="actions">
          <button data-reply="${q.id}">답변</button>
          <button class="danger" data-del="${q.id}">삭제</button>
        </div>
      </div>
    `).join('')}</div>` : `<div class="empty-state">받은 문의가 없습니다.</div>`
  );

  main.querySelectorAll('[data-reply]').forEach(b => {
    b.onclick = async () => {
      const id = Number(b.dataset.reply);
      const cur = items.find(x => x.id === id);
      const reply = prompt('답변 내용:', cur?.admin_reply || '');
      if (reply === null) return;
      await store.update('inquiries', id, { admin_reply: reply, replied_at: new Date().toISOString() });
      toast('답변 저장');
      panelInquiries(main);
    };
  });
  main.querySelectorAll('[data-del]').forEach(b => {
    b.onclick = async () => {
      if (!confirm('정말 삭제하시겠습니까?')) return;
      await store.remove('inquiries', Number(b.dataset.del));
      toast('삭제 완료');
      panelInquiries(main);
    };
  });
}

// ============================================================
// Generic List Panel (notices/products/qna/external_links)
// ============================================================
function panelList(main, table, label, fields, summary) {
  return (async () => {
    const items = await store.list(table);
    main.innerHTML = `
      <h2 class="panel-title">${label}</h2>
      <button class="btn-primary" id="add-new" style="margin-bottom:20px;">+ 새 항목 추가</button>
      <div id="form-zone"></div>
      <div class="admin-list">
        ${items.length ? items.map(it => `
          <div class="admin-list-item">
            <div class="head"><span class="name">${esc(summary(it))}</span><span class="meta">#${it.id}</span></div>
            <div class="actions">
              <button data-edit="${it.id}">수정</button>
              <button class="danger" data-del="${it.id}">삭제</button>
            </div>
          </div>
        `).join('') : `<div class="empty-state">등록된 항목이 없습니다.</div>`}
      </div>
    `;

    document.getElementById('add-new').onclick = () => {
      renderForm(null);
    };
    main.querySelectorAll('[data-edit]').forEach(b => {
      b.onclick = () => {
        const id = Number(b.dataset.edit);
        renderForm(items.find(x => x.id === id));
      };
    });
    main.querySelectorAll('[data-del]').forEach(b => {
      b.onclick = async () => {
        if (!confirm('정말 삭제하시겠습니까?')) return;
        await store.remove(table, Number(b.dataset.del));
        toast('삭제 완료');
        panelList(main, table, label, fields, summary);
      };
    });

    function renderForm(row) {
      const zone = document.getElementById('form-zone');
      zone.innerHTML = `
        <form class="admin-form" id="list-form" style="margin-bottom:24px;">
          ${fields.map(f => fieldHtml(f, row)).join('')}
          <div style="display:flex;gap:8px;">
            <button type="submit" class="btn-primary">${row ? '수정 저장' : '추가'}</button>
            <button type="button" id="cancel-form" style="padding:12px 24px;border:1px solid var(--border-subtle);color:var(--text-muted);border-radius:4px;font-family:var(--font-display);letter-spacing:2px;">취소</button>
          </div>
        </form>
      `;
      document.getElementById('cancel-form').onclick = () => zone.innerHTML = '';

      // file-multi: 기존 이미지 × 버튼으로 제거 (hidden 필드 JSON 갱신)
      zone.querySelectorAll('[data-rm-img]').forEach(btn => {
        btn.onclick = () => {
          const idx = Number(btn.dataset.rmImg);
          const fname = btn.dataset.rmField;
          const hidden = zone.querySelector(`input[type="hidden"][name="${fname}"]`);
          if (!hidden) return;
          let arr = []; try { arr = JSON.parse(hidden.value || '[]'); } catch {}
          arr.splice(idx, 1);
          hidden.value = JSON.stringify(arr);
          btn.parentElement.remove();
        };
      });

      // file-multi: 드래그앤드랍 + 새 파일 즉시 미리보기
      zone.querySelectorAll('.dropzone').forEach(dz => {
        const fname = dz.dataset.dzFor;
        const max = Number(dz.dataset.dzMax) || 2;
        const input = dz.querySelector('input[type="file"]');
        const preview = zone.querySelector(`.dz-preview[data-preview-for="${fname}"]`);
        // 클릭/포커스 → 파일 다이얼로그
        dz.addEventListener('click', e => { if (e.target === input) return; input.click(); });
        dz.addEventListener('keydown', e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); input.click(); } });
        // 드래그 시각 피드백
        ['dragenter','dragover'].forEach(ev => dz.addEventListener(ev, e => { e.preventDefault(); e.stopPropagation(); dz.classList.add('is-drag'); }));
        ['dragleave','drop'].forEach(ev => dz.addEventListener(ev, e => { e.preventDefault(); e.stopPropagation(); if (ev === 'dragleave' && dz.contains(e.relatedTarget)) return; dz.classList.remove('is-drag'); }));
        dz.addEventListener('drop', e => {
          const files = Array.from(e.dataTransfer?.files || []).filter(f => f.type.startsWith('image/'));
          if (!files.length) return;
          const dt = new DataTransfer();
          files.slice(0, max).forEach(f => dt.items.add(f));
          input.files = dt.files;
          input.dispatchEvent(new Event('change'));
        });
        // 신규 파일 선택 시 즉시 썸네일 (업로드 전 로컬 미리보기)
        input.addEventListener('change', () => {
          const files = Array.from(input.files || []).slice(0, max);
          if (!files.length) return;
          const html = files.map((f, i) => {
            const u = URL.createObjectURL(f);
            return `<div class="dz-thumb dz-pending"><img src="${u}"><span class="dz-badge">새 ${i+1}</span></div>`;
          }).join('');
          if (preview) preview.innerHTML = html;
        });
      });

      document.getElementById('list-form').onsubmit = async (e) => {
        e.preventDefault();
        const submitBtn = e.target.querySelector('button[type="submit"]');
        const originalLabel = submitBtn?.textContent;
        const fd = new FormData(e.target);
        const obj = {};
        try {
          for (const f of fields) {
            let val = fd.get(f.name);
            if (f.type === 'number') {
              obj[f.name] = val ? Number(val) : 0;
            } else if (f.type === 'checkbox') {
              obj[f.name] = fd.get(f.name) === 'on';
            } else if (f.type === 'datetime-local') {
              if (val) obj[f.name] = new Date(val).toISOString();
              // 빈값이면 obj에 추가 안 함 → INSERT는 store 기본값 사용, UPDATE는 기존값 유지
            } else if (f.type === 'file-multi') {
              const fileInput = e.target.querySelector(`input[type="file"][data-field="${f.name}"]`);
              const newFiles = Array.from(fileInput?.files || []).slice(0, f.max || 2);
              if (newFiles.length) {
                if (submitBtn) { submitBtn.disabled = true; submitBtn.textContent = '이미지 업로드 중…'; }
                obj[f.name] = await uploadImages(newFiles, cfg);
              } else {
                try { obj[f.name] = JSON.parse(val || '[]'); } catch { obj[f.name] = []; }
              }
            } else {
              obj[f.name] = val ?? '';
            }
          }
          if (row) await store.update(table, row.id, obj);
          else await store.insert(table, obj);
          toast(row ? '수정 완료' : '추가 완료');
          panelList(main, table, label, fields, summary);
        } catch (err) {
          if (submitBtn) { submitBtn.disabled = false; submitBtn.textContent = originalLabel || '저장'; }
          alert('저장 실패: ' + (err?.message || err));
        }
      };
    }
  })();
}

function fieldHtml(f, row) {
  const v = row ? row[f.name] : (f.default ?? '');
  const lbl = `<label>${f.label}</label>`;
  if (f.type === 'textarea') return `<div>${lbl}<textarea name="${f.name}" rows="4" maxlength="${f.maxlength || 2000}">${esc(v)}</textarea></div>`;
  if (f.type === 'checkbox') return `<div class="toggle-row"><input type="checkbox" id="f-${f.name}" name="${f.name}" ${v ? 'checked' : ''}><label for="f-${f.name}" style="margin:0;text-transform:none;letter-spacing:0;font-size:14px;color:var(--text-secondary);">${f.label}</label></div>`;
  if (f.type === 'select') return `<div>${lbl}<select name="${f.name}">${f.options.map(o => `<option value="${o.value}" ${v===o.value?'selected':''}>${o.label}</option>`).join('')}</select></div>`;
  if (f.type === 'datetime-local') {
    const dt = v ? toLocalDatetime(v) : '';
    return `<div>${lbl}<input type="datetime-local" name="${f.name}" value="${dt}"></div>`;
  }
  if (f.type === 'file-multi') {
    const max = f.max || 2;
    const existing = Array.isArray(v) ? v : [];
    const previewHtml = existing.map((u, i) => `<div class="dz-thumb"><img src="${esc(u)}"><button type="button" class="dz-rm" data-rm-img="${i}" data-rm-field="${f.name}" aria-label="삭제">×</button></div>`).join('');
    return `<div>${lbl}
      <div class="dropzone" data-dz-for="${f.name}" data-dz-max="${max}" tabindex="0" role="button" aria-label="${esc(f.label)} 업로드 영역">
        <input type="file" name="${f.name}__files" data-field="${f.name}" data-max="${max}" accept="image/*" multiple class="dz-input">
        <div class="dz-cta">
          <div class="dz-icon">⬆</div>
          <div class="dz-msg"><strong>사진을 끌어다 놓거나 클릭</strong></div>
          <div class="dz-sub">최대 ${max}장 · JPG/PNG/WEBP · 새 파일 선택 시 기존 이미지를 대체합니다</div>
        </div>
      </div>
      <input type="hidden" name="${f.name}" value='${esc(JSON.stringify(existing))}'>
      <div class="img-preview dz-preview" data-preview-for="${f.name}">${previewHtml}</div>
    </div>`;
  }
  return `<div>${lbl}<input type="${f.type || 'text'}" name="${f.name}" value="${esc(v)}" ${f.required ? 'required' : ''} ${f.maxlength ? `maxlength="${f.maxlength}"` : ''}></div>`;
}

function toLocalDatetime(iso) {
  const d = new Date(iso);
  if (isNaN(d.getTime())) return '';
  const pad = n => String(n).padStart(2, '0');
  return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
}

// ============================================================
// Field schemas
// ============================================================
const noticeFields = [
  { name: 'title', label: '제목', type: 'text', required: true, maxlength: 100 },
  { name: 'body', label: '본문', type: 'textarea', maxlength: 3000 },
  { name: 'images', label: '사진 (최대 2장)', type: 'file-multi', max: 2 },
  { name: 'external_url', label: '외부링크 (선택)', type: 'url' },
  { name: 'pinned', label: '상단 고정 (PIN)', type: 'checkbox' },
  { name: 'created_at', label: '게시 날짜', type: 'datetime-local' }
];

const productFields = [
  { name: 'name', label: '제품명', type: 'text', required: true, maxlength: 60 },
  { name: 'price', label: '가격 (원)', type: 'number', required: true },
  { name: 'images', label: '제품 사진 (최대 5장 · 첫 장이 대표 이미지)', type: 'file-multi', max: 5 },
  { name: 'description', label: '설명', type: 'textarea', maxlength: 500 },
  { name: 'sort_order', label: '정렬 순번 (낮을수록 위)', type: 'number', default: 0 }
];

const qnaFields = [
  { name: 'question', label: '질문', type: 'text', required: true, maxlength: 200 },
  { name: 'answer', label: '답변', type: 'textarea', required: true, maxlength: 2000 },
  { name: 'images', label: '사진 (최대 2장)', type: 'file-multi', max: 2 },
  { name: 'external_url', label: '외부링크 (선택, 예: 통관 고유번호)', type: 'url' },
  { name: 'external_label', label: '버튼 라벨 (선택)', type: 'text', maxlength: 40 },
  { name: 'sort_order', label: '정렬 순번', type: 'number', default: 0 },
  { name: 'created_at', label: '게시 날짜', type: 'datetime-local' }
];

const externalFields = [
  { name: 'label', label: '라벨', type: 'text', required: true, maxlength: 40 },
  { name: 'url', label: 'URL', type: 'url', required: true },
  { name: 'position', label: '위치', type: 'select', options: [
    { value: 'top', label: '상단 (멘트 다음)' },
    { value: 'middle', label: '중간 (제품 다음)' },
    { value: 'bottom', label: '하단 (문의 다음)' }
  ]},
  { name: 'sort_order', label: '정렬 순번', type: 'number', default: 0 },
  { name: 'enabled', label: '활성화', type: 'checkbox', default: true }
];

// ============================================================
// Utils
// ============================================================
function esc(s) {
  return String(s ?? '').replace(/[&<>"']/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]));
}

function formatDate(iso) {
  if (!iso) return '';
  const d = new Date(iso);
  return `${d.getFullYear()}.${String(d.getMonth()+1).padStart(2,'0')}.${String(d.getDate()).padStart(2,'0')}`;
}

function toast(msg) {
  const t = document.createElement('div');
  t.className = 'success-toast';
  t.textContent = msg;
  document.body.appendChild(t);
  setTimeout(() => t.remove(), 1800);
}
