// ═══════════════════════════════════════════════════════════
// Firebase Firestore 초기화 + 데이터 함수 (Firestore 버전)
// 이 파일은 다른 모든 jsx 파일보다 먼저 로드되어야 합니다
// ═══════════════════════════════════════════════════════════

// Firebase 초기화
const firebaseConfig = {
  apiKey: "AIzaSyBcT5e2Jrak0uLe8zh6o-p8dJweZIrLFfM",
  authDomain: "workup-langpoon-8cc75.firebaseapp.com",
  projectId: "workup-langpoon-8cc75",
  storageBucket: "workup-langpoon-8cc75.firebasestorage.app",
  messagingSenderId: "627661358440",
  appId: "1:627661358440:web:94e45e52a06b1f952982dd",
  measurementId: "G-0BJ3F9SM54"
};

firebase.initializeApp(firebaseConfig);
const wu_db = firebase.firestore();

// 오프라인 캐시 활성화 (PWA 지원)
wu_db.enablePersistence({ synchronizeTabs: true }).catch(err => {
  console.warn('Firestore persistence failed:', err.code);
});

window.wu_db = wu_db;
const wu_storage = firebase.storage();
window.wu_storage = wu_storage;

// ─────────────────────────────────────────
// USERS (Firestore: 'users' collection)
// ─────────────────────────────────────────
const DEFAULT_ADMIN = {
  email: 'langpoon@gmail.com', password: '12fkdvns',
  name: '관리자', role: 'admin', status: 'APPROVED', createdAt: '2026-01-01'
};

// ─── Firebase Auth 인스턴스 ───
const wu_auth = firebase.auth();
window.wu_auth = wu_auth;

async function getUsers() {
  try {
    const snap = await wu_db.collection('users').get();
    const users = snap.docs.map(d => ({ _docId: d.id, ...d.data() }));
    const adminUser = users.find(u => u.email === DEFAULT_ADMIN.email);
    if (!adminUser) {
      const ref = await wu_db.collection('users').add(DEFAULT_ADMIN);
      users.push({ _docId: ref.id, ...DEFAULT_ADMIN });
    } else if (adminUser.role !== 'admin' || adminUser.status !== 'APPROVED') {
      adminUser.role = 'admin';
      adminUser.status = 'APPROVED';
      if (adminUser._docId) {
        await wu_db.collection('users').doc(adminUser._docId).update({ role: 'admin', status: 'APPROVED' });
      }
    }
    return users;
  } catch (e) {
    console.error('getUsers error:', e);
    const raw = localStorage.getItem('wu-auth-users');
    const users = raw ? JSON.parse(raw) : [];
    if (!users.find(u => u.email === DEFAULT_ADMIN.email)) users.push(DEFAULT_ADMIN);
    return users;
  }
}

async function saveUsers(users) {
  try {
    const batch = wu_db.batch();
    const existing = await wu_db.collection('users').get();
    existing.docs.forEach(d => batch.delete(d.ref));
    users.forEach(u => {
      const { _docId, ...data } = u;
      batch.set(wu_db.collection('users').doc(), data);
    });
    await batch.commit();
  } catch (e) {
    console.error('saveUsers error:', e);
    localStorage.setItem('wu-auth-users', JSON.stringify(users));
  }
}

async function addUser(user) {
  try {
    await wu_db.collection('users').add(user);
  } catch (e) {
    console.error('addUser error:', e);
    const users = JSON.parse(localStorage.getItem('wu-auth-users') || '[]');
    users.push(user);
    localStorage.setItem('wu-auth-users', JSON.stringify(users));
  }
}

async function updateUserByEmail(email, updates) {
  try {
    const snap = await wu_db.collection('users').where('email', '==', email).get();
    if (!snap.empty) {
      await snap.docs[0].ref.update(updates);
    }
  } catch (e) {
    console.error('updateUserByEmail error:', e);
  }
}

function getAuth() {
  const raw = localStorage.getItem('wu-auth-user');
  return raw ? JSON.parse(raw) : null;
}
function setAuth(user) {
  localStorage.setItem('wu-auth-user', JSON.stringify(user));
}
function clearAuth() {
  localStorage.removeItem('wu-auth-user');
}

// ─────────────────────────────────────────
// STORES (Firestore: 'stores' collection)
// ─────────────────────────────────────────
async function getAllStores() {
  try {
    const snap = await wu_db.collection('stores').get();
    return snap.docs.map(d => ({ id: d.id, ...d.data() }));
  } catch (e) {
    console.error('getAllStores error:', e);
    return [];
  }
}

async function saveStoresBulk(list) {
  try {
    const batch = wu_db.batch();
    list.forEach(item => {
      const docId = item.id && typeof item.id === 'string' && item.id.length > 5
        ? item.id : wu_db.collection('stores').doc().id;
      const { id, ...data } = item;
      batch.set(wu_db.collection('stores').doc(docId), data);
    });
    await batch.commit();
  } catch (e) {
    console.error('saveStoresBulk error:', e);
  }
}

async function deleteStore(id) {
  try {
    await wu_db.collection('stores').doc(String(id)).delete();
  } catch (e) {
    console.error('deleteStore error:', e);
  }
}

async function clearAllStores() {
  try {
    const snap = await wu_db.collection('stores').get();
    const batch = wu_db.batch();
    snap.docs.forEach(d => batch.delete(d.ref));
    await batch.commit();
  } catch (e) {
    console.error('clearAllStores error:', e);
  }
}

// ─────────────────────────────────────────
// STORE INFO (Firestore: 'storeInfo' collection)
// key = storeName
// ─────────────────────────────────────────
async function getStoreInfo(storeName) {
  try {
    const doc = await wu_db.collection('storeInfo').doc(storeName).get();
    return doc.exists ? doc.data() : null;
  } catch (e) {
    console.error('getStoreInfo error:', e);
    return null;
  }
}

async function saveStoreInfo(data) {
  try {
    await wu_db.collection('storeInfo').doc(data.storeName).set(data);
  } catch (e) {
    console.error('saveStoreInfo error:', e);
  }
}

// ─────────────────────────────────────────
// PUBLISHED PRODUCTS (Firestore: 'published' collection)
// ─────────────────────────────────────────
async function getPublished() {
  try {
    const snap = await wu_db.collection('published').orderBy('publishedAt', 'desc').get();
    return snap.docs.map(d => ({ id: d.id, ...d.data() }));
  } catch (e) {
    console.error('getPublished error:', e);
    return [];
  }
}

// ─────────────────────────────────────────
// Firebase Storage — 이미지 원본 업로드
// ─────────────────────────────────────────

// base64 → Blob 변환
function _base64ToBlob(base64Str) {
  const parts = base64Str.split(',');
  const mime = parts[0].match(/:(.*?);/)[1];
  const binary = atob(parts[1]);
  const arr = new Uint8Array(binary.length);
  for (let i = 0; i < binary.length; i++) arr[i] = binary.charCodeAt(i);
  return new Blob([arr], { type: mime });
}

// 단일 이미지를 Storage에 업로드하고 URL 반환
async function uploadImageToStorage(base64OrUrl, productId, index) {
  // 이미 URL이면 그대로 반환
  if (!base64OrUrl || !base64OrUrl.startsWith('data:')) return base64OrUrl;
  try {
    const blob = _base64ToBlob(base64OrUrl);
    const ext = blob.type === 'image/png' ? 'png' : 'jpg';
    const path = 'products/' + productId + '/img_' + index + '_' + Date.now() + '.' + ext;
    const ref = wu_storage.ref(path);
    await ref.put(blob);
    const url = await ref.getDownloadURL();
    return url;
  } catch (e) {
    console.error('Storage upload failed:', e);
    return base64OrUrl; // 실패 시 base64 유지
  }
}

// 상품의 모든 이미지를 Storage에 업로드하고 URL로 교체 (병렬 업로드)
async function _uploadProductImages(product) {
  const id = product.id || 'P-' + Date.now();

  // photos 배열 병렬 업로드
  if (product.photos && product.photos.length) {
    product.photos = await Promise.all(
      product.photos.map((p, i) => uploadImageToStorage(p, id, i))
    );
  }

  // media 배열도 병렬 업로드 (영상 제외)
  if (product.media && product.media.length) {
    product.media = await Promise.all(
      product.media.map(async (m, i) => {
        if (m.type === 'image' && m.src && m.src.startsWith('data:')) {
          const url = await uploadImageToStorage(m.src, id, 'media_' + i);
          return { ...m, src: url };
        }
        return m;
      })
    );
  }

  return product;
}

// (레거시 호환) base64 압축 — Storage 실패 시 폴백
function _compressBase64(base64Str, maxW, quality) {
  return new Promise((resolve) => {
    if (!base64Str || !base64Str.startsWith('data:image')) { resolve(base64Str); return; }
    const img = new Image();
    img.onload = () => {
      let w = img.width, h = img.height;
      if (w > maxW) { h = Math.round(h * maxW / w); w = maxW; }
      const c = document.createElement('canvas');
      c.width = w; c.height = h;
      c.getContext('2d').drawImage(img, 0, 0, w, h);
      resolve(c.toDataURL('image/jpeg', quality));
    };
    img.onerror = () => resolve(base64Str);
    img.src = base64Str;
  });
}

async function _shrinkProduct(product) {
  const steps = [
    { maxW: 1200, q: 0.88 },
    { maxW: 1000, q: 0.78 },
    { maxW: 800,  q: 0.68 },
    { maxW: 600,  q: 0.55 },
  ];
  const applyCompress = async (prod, maxW, q) => {
    const comp = (src) => _compressBase64(src, maxW, q);
    if (prod.photos && prod.photos.length) {
      prod.photos = await Promise.all(prod.photos.map(s => s.startsWith('data:') ? comp(s) : Promise.resolve(s)));
    }
    if (prod.media && prod.media.length) {
      prod.media = await Promise.all(prod.media.map(async (m) => {
        if (m.type === 'image' && m.src && m.src.startsWith('data:')) return { ...m, src: await comp(m.src) };
        return m;
      }));
    }
  };
  for (const { maxW, q } of steps) {
    await applyCompress(product, maxW, q);
    const size = new Blob([JSON.stringify(product)]).size;
    if (size <= 950000) return product;
  }
  while (product.photos && product.photos.length > 1) {
    product.photos = product.photos.slice(0, product.photos.length - 1);
    if (product.media) {
      const vids = product.media.filter(m => m.type === 'video');
      const imgs = product.media.filter(m => m.type === 'image').slice(0, product.photos.length);
      product.media = [...vids, ...imgs];
    }
    const size = new Blob([JSON.stringify(product)]).size;
    if (size <= 950000) break;
  }
  return product;
}

async function publishProduct(product) {
  // ── 중복 상품명 체크 ──
  const newName = (product.title || (product.parsed || {}).kr || (product.parsed || {}).name || product.kr || product.name || '').trim().toLowerCase();
  if (newName) {
    const existing = await wu_db.collection('published').get();
    const dup = existing.docs.find(d => {
      const data = d.data();
      const exName = (data.title || (data.parsed || {}).kr || (data.parsed || {}).name || data.kr || data.name || '').trim().toLowerCase();
      return exName === newName;
    });
    if (dup) {
      throw new Error('중복 상품: "' + newName + '" 이름의 상품이 이미 등록되어 있습니다.');
    }
  }

  // ── AI 자동 카테고리 분류 ──
  if (!product.parsed) product.parsed = {};
  const autoCategories = aiAutoCategory(product);
  if (autoCategories.length > 0 && (!product.parsed.category || !Array.isArray(product.parsed.category) || product.parsed.category.length === 0)) {
    product.parsed.category = autoCategories;
    product._aiCategorized = true;
  }

  const id = 'PUB-' + Date.now();
  product.id = id;
  product.publishedAt = new Date().toISOString();
  // 1차: Storage에 원본 업로드 시도
  try {
    await _uploadProductImages(product);
  } catch (e) {
    console.warn('Storage upload failed, fallback to base64 compress:', e);
  }
  // Firestore 저장 전 1MB 체크 — 아직 base64가 남아있으면 압축
  const size = new Blob([JSON.stringify(product)]).size;
  if (size > 950000) await _shrinkProduct(product);
  await wu_db.collection('published').doc(id).set(product);
  return product;
}

async function updatePublished(product) {
  if (!product || !product.id) throw new Error('상품 ID가 없습니다');
  product.updatedAt = new Date().toISOString();
  // 1차: Storage에 원본 업로드 시도
  try {
    await _uploadProductImages(product);
  } catch (e) {
    console.warn('Storage upload failed, fallback to base64 compress:', e);
  }
  // Firestore 저장 전 1MB 체크
  const size = new Blob([JSON.stringify(product)]).size;
  if (size > 950000) await _shrinkProduct(product);
  await wu_db.collection('published').doc(String(product.id)).set(product);
  return product;
}

async function deletePublished(id) {
  try {
    await wu_db.collection('published').doc(String(id)).delete();
  } catch (e) {
    console.error('deletePublished error:', e);
  }
}

// ─────────────────────────────────────────
// MANAGED PRODUCTS (Firestore: 'managedProducts' collection)
// ─────────────────────────────────────────
async function getManagedProducts() {
  try {
    const snap = await wu_db.collection('managedProducts').get();
    return snap.docs.map(d => ({ id: d.id, ...d.data() }));
  } catch (e) {
    console.error('getManagedProducts error:', e);
    return [];
  }
}

async function saveManagedProduct(product) {
  try {
    const id = product.id || 'P-' + Date.now();
    product.id = id;
    await wu_db.collection('managedProducts').doc(id).set(product);
  } catch (e) {
    console.error('saveManagedProduct error:', e);
  }
}

async function deleteManagedProduct(id) {
  try {
    await wu_db.collection('managedProducts').doc(String(id)).delete();
  } catch (e) {
    console.error('deleteManagedProduct error:', e);
  }
}

// ─────────────────────────────────────────
// SETTINGS (Firestore: 'settings' collection)
// 예: 카카오맵 API 키 등
// ─────────────────────────────────────────
async function getSettingFromCloud(key) {
  try {
    const doc = await wu_db.collection('settings').doc(key).get();
    return doc.exists ? doc.data().value : null;
  } catch (e) { return null; }
}

async function saveSettingToCloud(key, value) {
  try {
    await wu_db.collection('settings').doc(key).set({ value });
  } catch (e) { console.error('saveSetting error:', e); }
}

// 카카오 키를 Firestore에서도 동기화 (JavaScript키 + REST API키)
(async () => {
  // JavaScript 키 (지도용)
  const localKey = localStorage.getItem('wu-kakao-key');
  if (localKey) {
    await saveSettingToCloud('kakao-key', localKey);
  } else {
    const cloudKey = await getSettingFromCloud('kakao-key');
    if (cloudKey) localStorage.setItem('wu-kakao-key', cloudKey);
  }
  // REST API 키 (카카오 로그인용)
  const localRest = localStorage.getItem('wu-kakao-rest-key');
  if (localRest) {
    await saveSettingToCloud('kakao-rest-key', localRest);
  } else {
    const cloudRest = await getSettingFromCloud('kakao-rest-key');
    if (cloudRest) localStorage.setItem('wu-kakao-rest-key', cloudRest);
  }
})();

// ─────────────────────────────────────────
// CUSTOM CATEGORIES (Firestore: 'settings/custom-categories')
// ─────────────────────────────────────────
async function loadCustomCategories() {
  try {
    const val = await getSettingFromCloud('custom-categories');
    if (val && Array.isArray(val)) {
      WU_DATA._customCategories = val;
    }
  } catch (e) { console.warn('loadCustomCategories error:', e); }
  return WU_DATA.categories;
}

async function saveCustomCategories(list) {
  WU_DATA._customCategories = list;
  await saveSettingToCloud('custom-categories', list);
}

async function loadCustomBrands() {
  try {
    const val = await getSettingFromCloud('custom-brands');
    if (val && Array.isArray(val)) {
      WU_DATA._customBrands = val;
    }
  } catch (e) { console.warn('loadCustomBrands error:', e); }
  return WU_DATA.brands;
}

async function saveCustomBrands(list) {
  WU_DATA._customBrands = list;
  await saveSettingToCloud('custom-brands', list);
}

// ═══ 공지사항 CRUD ═══
async function getNotices() {
  try {
    const snap = await wu_db.collection('notices').orderBy('createdAt', 'desc').get();
    return snap.docs.map(d => ({ id: d.id, ...d.data() }));
  } catch (e) { console.error('getNotices error:', e); return []; }
}

async function publishNotice(notice) {
  const id = 'NTC-' + Date.now();
  notice.id = id;
  notice.createdAt = new Date().toISOString();
  notice.status = 'PUBLISHED';
  await wu_db.collection('notices').doc(id).set(notice);
  return notice;
}

async function updateNotice(notice) {
  if (!notice || !notice.id) throw new Error('공지 ID 없음');
  notice.updatedAt = new Date().toISOString();
  await wu_db.collection('notices').doc(notice.id).set(notice, { merge: true });
  return notice;
}

async function deleteNotice(id) {
  await wu_db.collection('notices').doc(id).delete();
}

// ─────────────────────────────────────────
// AI 자동 카테고리 분류
// ─────────────────────────────────────────
const _CATEGORY_RULES = {
  '긴팔': { keywords: ['긴팔', '셔츠', '작업복 상의', '워크셔츠', '롱슬리브', 'long sleeve', '남방', '자카르', '폴로 긴팔', '기능성 셔츠', '쿨링 긴팔', '방한 셔츠', '용접 셔츠'], parts: ['상의'] },
  '반팔': { keywords: ['반팔', '티셔츠', 't-shirt', 'tee', '쿨링 팬', '반팔 셔츠', '하프', 'half', '반소매', '쿨티', '에어', '폴로 반팔', '쿨링 반팔', '라운드', '크루넥'], parts: ['상의'] },
  '긴바지': { keywords: ['긴바지', '팬츠', 'pants', '카고', 'cargo', '워크팬츠', '작업바지', '방한 바지', '기능성 바지', '스판 바지', '스트레치 팬츠', '데님', '청바지', '조거', 'jogger'], parts: ['하의'] },
  '반바지': { keywords: ['반바지', '숏팬츠', 'shorts', '쇼트', '5부', '7부', '하프팬츠', '쿨링 반바지', '여름 바지'], parts: ['하의'] },
  '자켓': { keywords: ['자켓', 'jacket', '점퍼', 'jumper', '바람막이', '윈드브레이커', '후드집업', '작업복 자켓', '야상', '파카', '패딩', '코트', '블루종', '봄바'], parts: ['아우터'] },
  '조끼': { keywords: ['조끼', 'vest', '베스트', '방한조끼', '패딩조끼', '안전조끼', '경량 조끼', '작업조끼', '기능성 조끼', '쿨링 조끼', '에어 조끼', '팬조끼'], parts: ['아우터'] },
  '워크부츠': { keywords: ['부츠', 'boots', '워크부츠', '안전화', '작업화', '스틸토', '강철', '방수화', '등산화', '발목화', '미끄럼방지'], parts: ['풋웨어'] },
  '슬리퍼': { keywords: ['슬리퍼', 'slipper', '샌들', 'sandal', '실내화', '작업용 슬리퍼', '가벼운 신발', '사무실화'], parts: ['풋웨어'] },
  '액세서리': { keywords: ['액세서리', '모자', '캡', '비니', '장갑', '벨트', '넥워머', '마스크', '안전모', '귀마개', '토시', '팔토시', '선글라스', '가방', '파우치', '지갑', '멀티포켓', '공구가방', '허리벨트', '탈부착'], parts: ['액세서리'] },
  '에이프런': { keywords: ['에이프런', 'apron', '앞치마', '작업앞치마', '캔버스 에이프런'], parts: ['액세서리'] },
};

function aiAutoCategory(product) {
  const parsed = product.parsed || {};
  // 이미 카테고리가 지정되어 있으면 건너뛰기
  if (parsed.category && Array.isArray(parsed.category) && parsed.category.length > 0) {
    return parsed.category;
  }

  // 분석 텍스트 구성
  const texts = [
    product.title || '',
    parsed.kr || '',
    parsed.name || '',
    product.body || '',
    parsed.description || '',
    Array.isArray(parsed.parts) ? parsed.parts.join(' ') : (parsed.parts || ''),
    Array.isArray(parsed.colors_kr) ? parsed.colors_kr.join(' ') : (parsed.colors_kr || ''),
    parsed.code || '',
    parsed.season_tag || '',
  ].join(' ').toLowerCase();

  const scores = {};
  const allCats = WU_DATA.categories.filter(c => c !== '전체' && c !== '신상');

  // 키워드 매칭 점수 계산
  for (const [cat, rule] of Object.entries(_CATEGORY_RULES)) {
    if (!allCats.includes(cat)) continue;
    let score = 0;
    for (const kw of rule.keywords) {
      if (texts.includes(kw.toLowerCase())) {
        // 정확한 카테고리명 매칭은 높은 점수
        score += (kw === cat) ? 10 : 5;
      }
    }
    // parts 기반 보너스
    if (rule.parts && parsed.parts) {
      const partsArr = Array.isArray(parsed.parts) ? parsed.parts : [parsed.parts];
      for (const p of rule.parts) {
        if (partsArr.includes(p)) score += 8;
      }
    }
    if (score > 0) scores[cat] = score;
  }

  // 점수순 정렬 후 상위 결과 반환
  const sorted = Object.entries(scores).sort((a, b) => b[1] - a[1]);
  if (sorted.length === 0) {
    // 매칭 실패 시 parts 기반으로 최선 추정
    const fallbackParts = Array.isArray(parsed.parts) ? parsed.parts : parsed.parts ? [parsed.parts] : [];
    if (fallbackParts.length > 0) {
      const partMap = { '상의': '긴팔', '하의': '긴바지', '아우터': '자켓', '풋웨어': '워크부츠', '액세서리': '액세서리' };
      const guess = fallbackParts.map(p => partMap[p]).filter(Boolean);
      return guess.length > 0 ? guess : [];
    }
    return [];
  }

  // 최고 점수의 50% 이상인 카테고리만 포함 (복수 카테고리 가능)
  const topScore = sorted[0][1];
  const result = sorted.filter(([, s]) => s >= topScore * 0.5).map(([c]) => c);
  return result.slice(0, 3); // 최대 3개
}

// ─── Firebase Auth 회원가입 (이메일 인증 메일 발송) ───
async function firebaseSignup(email, password) {
  const cred = await wu_auth.createUserWithEmailAndPassword(email, password);
  // 이메일 인증 메일 발송
  if (cred.user) {
    await cred.user.sendEmailVerification({
      url: window.location.origin,
      handleCodeInApp: false
    });
  }
  return cred.user;
}

// ─── Firebase Auth 로그인 ───
async function firebaseLogin(email, password) {
  const cred = await wu_auth.signInWithEmailAndPassword(email, password);
  return cred.user;
}

// ─── Firebase Auth 비밀번호 재설정 메일 ───
async function firebaseResetPassword(email) {
  await wu_auth.sendPasswordResetEmail(email, {
    url: window.location.origin,
    handleCodeInApp: false
  });
}

// ─── Firebase Auth 로그아웃 ───
async function firebaseLogout() {
  await wu_auth.signOut();
}

// ─── Firebase Auth 이메일 인증 여부 확인 ───
function isEmailVerified() {
  const user = wu_auth.currentUser;
  return user ? user.emailVerified : false;
}

// ─── Firebase Auth Google 로그인 ───
async function firebaseGoogleLogin() {
  const provider = new firebase.auth.GoogleAuthProvider();
  const cred = await wu_auth.signInWithPopup(provider);
  return cred.user;
}

// ─── 카카오 로그인 (REST API 직접 사용 — SDK 불필요) ───
function initKakaoSDK() { return true; } // 호환용 stub

async function firebaseKakaoLogin() {
  const restKey = localStorage.getItem('wu-kakao-rest-key');
  if (!restKey) throw new Error('카카오 REST API 키가 설정되지 않았습니다.\nHQ 관리 → 매장 관리에서 REST API 키를 등록하세요.');

  const redirectUri = window.location.origin + window.location.pathname;
  const authUrl = 'https://kauth.kakao.com/oauth/authorize?client_id=' + restKey
    + '&redirect_uri=' + encodeURIComponent(redirectUri)
    + '&response_type=code&scope=profile_nickname,account_email';

  // 팝업 열기
  const popup = window.open(authUrl, 'kakao_login', 'width=480,height=700,scrollbars=yes');
  if (!popup) throw new Error('팝업이 차단되었습니다. 팝업 차단을 해제해주세요.');

  return new Promise((resolve, reject) => {
    const timer = setInterval(() => {
      try {
        if (popup.closed) { clearInterval(timer); reject({ code: 'auth/popup-closed-by-user' }); return; }
        // 팝업이 우리 도메인으로 리다이렉트 되었는지 확인
        if (popup.location.origin === window.location.origin) {
          const params = new URLSearchParams(popup.location.search);
          const code = params.get('code');
          const error = params.get('error');
          clearInterval(timer);
          popup.close();
          if (error || !code) { reject({ code: 'auth/popup-closed-by-user' }); return; }
          // 인가 코드 → 토큰 교환 → 사용자 정보
          _exchangeKakaoToken(code, restKey, redirectUri).then(resolve).catch(reject);
        }
      } catch(e) { /* cross-origin — 아직 kakao.com에 있음, 대기 */ }
    }, 300);
    // 5분 타임아웃
    setTimeout(() => { clearInterval(timer); try { popup.close(); } catch(e) {} reject(new Error('로그인 시간 초과')); }, 300000);
  });
}

async function _exchangeKakaoToken(code, restKey, redirectUri) {
  // 1) 인가 코드 → 액세스 토큰
  const tokenRes = await fetch('https://kauth.kakao.com/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: 'grant_type=authorization_code&client_id=' + restKey
      + '&redirect_uri=' + encodeURIComponent(redirectUri)
      + '&code=' + code,
  });
  const tokenData = await tokenRes.json();
  if (!tokenData.access_token) throw new Error('카카오 토큰 발급 실패: ' + (tokenData.error_description || ''));

  // 2) 액세스 토큰 → 사용자 정보
  const userRes = await fetch('https://kapi.kakao.com/v2/user/me', {
    headers: { 'Authorization': 'Bearer ' + tokenData.access_token },
  });
  const userData = await userRes.json();
  const kakaoAccount = userData.kakao_account || {};
  const profile = kakaoAccount.profile || {};
  return {
    kakaoId: userData.id,
    email: kakaoAccount.email || '',
    name: profile.nickname || '',
    profileImage: profile.profile_image_url || '',
  };
}

// ─── 관리자 계정 Firebase Auth에 초기화 ───
async function ensureAdminAuth() {
  try {
    await wu_auth.signInWithEmailAndPassword(DEFAULT_ADMIN.email, DEFAULT_ADMIN.password);
    await wu_auth.signOut();
  } catch(e) {
    if (e.code === 'auth/user-not-found') {
      try {
        await wu_auth.createUserWithEmailAndPassword(DEFAULT_ADMIN.email, DEFAULT_ADMIN.password);
        await wu_auth.signOut();
      } catch(e2) { console.warn('Admin auth init:', e2.message); }
    }
  }
}
// 관리자 계정 보장 (앱 시작 시)
ensureAdminAuth();

// 앱 시작 시 커스텀 카테고리 + 브랜드 로드
loadCustomCategories();
loadCustomBrands();

// 모든 함수를 window에 등록 (다른 파일에서 사용)
Object.assign(window, {
  wu_db, wu_storage, wu_auth,
  getUsers, saveUsers, addUser, updateUserByEmail,
  getAuth, setAuth, clearAuth,
  getAllStores, saveStoresBulk, deleteStore, clearAllStores,
  getStoreInfo, saveStoreInfo,
  getPublished, publishProduct, updatePublished, deletePublished,
  uploadImageToStorage, _uploadProductImages,
  getManagedProducts, saveManagedProduct, deleteManagedProduct,
  getSettingFromCloud, saveSettingToCloud,
  loadCustomCategories, saveCustomCategories,
  loadCustomBrands, saveCustomBrands,
  getNotices, publishNotice, updateNotice, deleteNotice,
  aiAutoCategory,
  firebaseSignup, firebaseLogin, firebaseGoogleLogin, firebaseKakaoLogin, initKakaoSDK, firebaseResetPassword, firebaseLogout, isEmailVerified,
});
