/* ============================================================================
 * Wildy — 설정 모달 (양쪽 HTML 공유)
 * ----------------------------------------------------------------------------
 *   사람 모양 아이콘 / "설정" 진입 시 표시. 데스크톱 = 중앙 모달, 모바일 = 시트.
 *
 *   메뉴:
 *     - 닉네임 변경 (모달 내부 input + RPC update_display_name)
 *     - 표시 언어 (5개 라디오, RPC update_preferred_language)
 *     - 알림 설정 (placeholder — Phase 2)
 *     - 계정 관리 (이메일/비번 변경, 계정 삭제 — placeholder)
 *     - 로그아웃
 *
 *   사용:
 *     <window.WildyComponents.SettingsModal
 *        supabaseClient={...}
 *        user={user}
 *        currentLang="ko"
 *        currentNickname="admin"
 *        onClose={() => ...}
 *        onLangChanged={(lang) => ...}
 *        onNicknameChanged={(name) => ...}
 *        onLogout={() => ...}
 *     />
 *
 *   글로벌 노출:
 *     window.WildyComponents.SettingsModal
 * ========================================================================= */
(function (global) {
  'use strict';

  if (typeof React === 'undefined') {
    console.error('[settings-modal.jsx] React not loaded');
    return;
  }
  const { useState, useEffect } = React;

  const LANGS = [
    { code: 'ko', label: '한국어',           flag: '🇰🇷' },
    { code: 'en', label: 'English',          flag: '🇺🇸' },
    { code: 'ja', label: '日本語',           flag: '🇯🇵' },
    { code: 'zh', label: '中文',             flag: '🇨🇳' },
    { code: 'id', label: 'Bahasa Indonesia', flag: '🇮🇩' },
  ];

  function withTimeout(promise, ms, fallback) {
    return Promise.race([
      promise,
      new Promise(resolve => setTimeout(() => resolve(fallback), ms)),
    ]);
  }

  // ────────────────────────────────────────────────────────────────────
  // AccountSection — 계정 관리 (비공개 정보 + 변경 placeholder)
  //   - 이메일 = 로그인 자격 (auth.users.email)
  //   - @핸들 = 영구 식별자 (users.username, 가입 후 변경 불가 정책)
  //   - 둘 다 본인만 보이는 정보 (프로필 헤더에서는 제거)
  // ────────────────────────────────────────────────────────────────────
  function AccountSection({ user, supabaseClient, onProfileChanged }) {
    const [username, setUsername] = useState(user?.username || null);
    const [draftUsername, setDraftUsername] = useState(user?.username || '');
    const [handleBusy, setHandleBusy] = useState(false);
    const [handleMsg, setHandleMsg] = useState('');
    const [handleError, setHandleError] = useState('');

    const changeKey = user?.id ? `wildy-username-change-${user.id}` : 'wildy-username-change';
    const getChangeState = () => {
      try {
        const raw = localStorage.getItem(changeKey);
        const parsed = raw ? JSON.parse(raw) : null;
        const now = Date.now();
        if (!parsed || !parsed.windowStart || now - parsed.windowStart > 30 * 24 * 60 * 60 * 1000) {
          return { windowStart: now, count: 0 };
        }
        return { windowStart: parsed.windowStart, count: Number(parsed.count) || 0 };
      } catch { return { windowStart: Date.now(), count: 0 }; }
    };
    const [changeState, setChangeState] = useState(getChangeState);
    const remainingChanges = Math.max(0, 2 - (changeState.count || 0));

    useEffect(() => {
      if (!supabaseClient || !user?.id) { setUsername(user?.username || null); setDraftUsername(user?.username || ''); return; }
      let active = true;
      (async () => {
        try {
          const { data } = await supabaseClient.from('users').select('username,display_name,avatar,is_admin').eq('id', user.id).maybeSingle();
          if (active) {
            setUsername(data?.username || user?.username || null);
            setDraftUsername(data?.username || user?.username || '');
            if (data?.username) onProfileChanged && onProfileChanged(data);
          }
        } catch {}
      })();
      return () => { active = false; };
    }, [supabaseClient, user?.id]);

    const validateHandle = (value) => {
      const clean = String(value || '').trim().replace(/^@+/, '').toLowerCase();
      if (!/^[a-z0-9_.]{4,20}$/.test(clean)) return { ok: false, clean, message: '영문 소문자, 숫자, _, . 조합 4~20자로 입력해주세요.' };
      if (clean.startsWith('.') || clean.endsWith('.') || clean.includes('..')) return { ok: false, clean, message: '.은 처음/끝/연속으로 쓸 수 없어요.' };
      return { ok: true, clean, message: '' };
    };

    const saveUsername = async () => {
      setHandleError('');
      setHandleMsg('');
      const checked = validateHandle(draftUsername);
      if (!checked.ok) { setHandleError(checked.message); return; }
      if (checked.clean === username) { setHandleMsg('현재 사용 중인 @주소예요.'); return; }
      if (remainingChanges <= 0) { setHandleError('이번 30일 동안 @주소 변경 가능 횟수를 모두 사용했어요.'); return; }
      if (!supabaseClient || !user?.id) { setHandleError('로그인이 필요해요.'); return; }

      setHandleBusy(true);
      try {
        try {
          const res = await fetch('/api/auth/validate', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ action: 'username', username: checked.clean }),
          });
          const json = await res.json().catch(() => ({}));
          if (res.ok && json?.available === false) throw new Error('이미 사용 중인 @주소예요.');
        } catch (e) {
          if (e?.message && e.message.includes('이미')) throw e;
        }

        let data = null;
        let rpcError = null;
        try {
          const rpcRes = await supabaseClient.rpc('update_username', {
            p_user_id: user.id,
            p_username: checked.clean,
          });
          rpcError = rpcRes.error || null;
          data = Array.isArray(rpcRes.data) ? rpcRes.data[0] : rpcRes.data;
        } catch (e) {
          rpcError = e;
        }
        if (rpcError) {
          const missingRpc = String(rpcError.message || '').includes('update_username') || String(rpcError.code || '') === 'PGRST202';
          if (!missingRpc) throw rpcError;
          const fallbackRes = await supabaseClient
            .from('users')
            .update({ username: checked.clean })
            .eq('id', user.id)
            .select('display_name,username,avatar,is_admin')
            .maybeSingle();
          if (fallbackRes.error) throw fallbackRes.error;
          data = fallbackRes.data;
        }
        const nextState = { windowStart: changeState.windowStart || Date.now(), count: (changeState.count || 0) + 1 };
        localStorage.setItem(changeKey, JSON.stringify(nextState));
        setChangeState(nextState);
        setUsername(data?.username || checked.clean);
        setDraftUsername(data?.username || checked.clean);
        onProfileChanged && onProfileChanged(data || { username: checked.clean });
        setHandleMsg('@주소가 변경됐어요.');
      } catch (e) {
        setHandleError(e?.message || '@주소 변경에 실패했어요.');
      } finally {
        setHandleBusy(false);
      }
    };

    return (
      <div className="p-3 space-y-3">
        <div className="rounded-2xl bg-slate-50 p-4 space-y-4">
          <div>
            <div className="text-[11px] font-bold text-slate-500 uppercase tracking-wider mb-1">@주소</div>
            <div className="flex items-center gap-2">
              <span className="font-display text-base font-black text-wildy-ink">@{username || 'wilder'}</span>
              <button
                onClick={() => username && navigator.clipboard?.writeText(`@${username}`).catch(() => {})}
                className="text-[10px] font-bold text-sky-600 hover:underline"
                disabled={!username}
              >복사</button>
            </div>
            <p className="mt-1 text-[10px] text-slate-400" style={{ wordBreak: 'keep-all' }}>
              다른 Wilder가 멘션하고 찾는 고유 주소예요. 30일 동안 2번까지 변경할 수 있어요.
            </p>
          </div>

          <div className="rounded-2xl border border-white bg-white p-3">
            <label className="mb-1 block text-[11px] font-bold text-slate-500">@주소 변경</label>
            <div className="flex gap-2">
              <div className="flex flex-1 items-center rounded-2xl border-2 border-sky-100 bg-white px-3 focus-within:border-sky-300">
                <span className="text-slate-400">@</span>
                <input
                  value={draftUsername}
                  onChange={(e) => setDraftUsername(e.target.value.replace(/^@+/, '').toLowerCase())}
                  className="min-w-0 flex-1 px-1 py-2 text-sm font-bold outline-none"
                  placeholder="wilder"
                />
              </div>
              <button
                onClick={saveUsername}
                disabled={handleBusy}
                className="rounded-2xl bg-wildy-ink px-4 py-2 text-xs font-bold text-white disabled:opacity-50"
              >{handleBusy ? '저장 중...' : '저장'}</button>
            </div>
            <div className="mt-2 text-[10px] text-slate-400">남은 변경 횟수: {remainingChanges}/2</div>
            {handleMsg && <div className="mt-2 text-xs font-bold text-emerald-600">{handleMsg}</div>}
            {handleError && <div className="mt-2 text-xs font-bold text-rose-600">{handleError}</div>}
          </div>

          <div className="border-t border-slate-200 pt-3">
            <div className="text-[11px] font-bold text-slate-500 uppercase tracking-wider mb-1">로그인 이메일</div>
            <div className="font-bold text-sm text-wildy-ink">{user?.email || '비공개'}</div>
            <p className="mt-1 text-[10px] text-slate-400">로그인에만 사용하는 인증 정보예요. 프로필에는 노출되지 않아요.</p>
          </div>
        </div>

        <MenuRowAccount icon="✉️" label="이메일 변경" sub="인증 후 변경" onClick={() => alert('이메일 변경은 Phase 1C에서 추가됩니다.')} />
        <MenuRowAccount icon="🔐" label="비밀번호 변경" onClick={() => alert('비밀번호 변경은 Phase 1C에서 추가됩니다.')} />
        <div className="my-2 h-px bg-slate-100" />
        <MenuRowAccount icon="🧨" label="계정 삭제" sub="되돌릴 수 없어요" onClick={() => alert('계정 삭제는 별도 문의 절차로 처리됩니다.')} danger />
      </div>
    );
  }
  function MenuRowAccount({ icon, label, sub, onClick, danger }) {
    return (
      <button
        onClick={onClick}
        className={`flex w-full items-center gap-3 rounded-2xl px-4 py-3.5 text-left hover:bg-slate-50 transition ${danger ? 'text-rose-600' : 'text-slate-800'}`}
      >
        <span className="text-xl flex-shrink-0">{icon}</span>
        <span className="flex-1 min-w-0">
          <span className="block font-bold text-sm">{label}</span>
          {sub && <span className="block text-xs text-slate-500 mt-0.5 truncate">{sub}</span>}
        </span>
        <span className="text-slate-300">›</span>
      </button>
    );
  }

  function SettingsModal({
    supabaseClient, user,
    currentLang = 'ko', currentNickname = '',
    onClose, onLangChanged, onNicknameChanged, onLogout,
    onOpenSparkledTab,   // 좋아함 탭으로 이동 (프로필 페이지에서 setTab)
    onOpenPostDetail,    // 게시물 풀스크린 진입 (App level)
  }) {
    const [section, setSection] = useState('menu'); // menu | nickname | language | translation | notif | account | activity | comments | shares
    // 번역 데이터 옵트아웃 상태 (Phase 1 §2.5 E-2)
    const [trOptOut, setTrOptOut] = useState(null);   // null = 로딩, true/false = 확정
    const [trBusy, setTrBusy] = useState(false);
    const [trMsg, setTrMsg] = useState('');
    const [myComments, setMyComments] = useState([]);
    const [commentsLoading, setCommentsLoading] = useState(false);
    const [myShares, setMyShares] = useState([]);  // 공유 기록 — Phase C에서 post_shares 테이블 (베타 = 빈 placeholder)
    const helpers = (global.WildyLib && global.WildyLib.SupabaseHelpers) || {};

    const currentDisplayName = user?.display_name || currentNickname || '';

    // 닉네임 편집
    const [nick, setNick] = useState(currentDisplayName || '');
    const [nickBusy, setNickBusy] = useState(false);
    const [nickError, setNickError] = useState('');

    // 언어 변경
    const [lang, setLang] = useState(currentLang || 'ko');
    const [langBusy, setLangBusy] = useState(false);

    useEffect(() => { setNick(currentDisplayName || ''); }, [currentDisplayName]);
    useEffect(() => { setLang(currentLang || 'ko'); }, [currentLang]);

    // 번역 설정 진입 시 현재 옵트아웃 상태 1회 fetch
    useEffect(() => {
      if (section !== 'translation') return;
      if (!supabaseClient || !user?.id) return;
      let active = true;
      (async () => {
        try {
          const { data } = await supabaseClient.from('users')
            .select('translation_data_collection_opted_out')
            .eq('id', user.id)
            .maybeSingle();
          if (active) setTrOptOut(Boolean(data?.translation_data_collection_opted_out));
        } catch {
          if (active) setTrOptOut(false);
        }
      })();
      return () => { active = false; };
    }, [section, supabaseClient, user?.id]);

    // 토글 — 옵트아웃 ON 시 opt_out_translation_data RPC 로 과거 데이터 즉시 삭제
    const toggleTrOptOut = async (newOptOut) => {
      if (trBusy || newOptOut === trOptOut) return;
      setTrBusy(true);
      setTrMsg('');
      const prev = trOptOut;
      setTrOptOut(newOptOut);   // 낙관적
      try {
        if (!supabaseClient || !user?.id) throw new Error('로그인 필요');
        const { error } = await supabaseClient.from('users')
          .update({ translation_data_collection_opted_out: newOptOut })
          .eq('id', user.id);
        if (error) throw error;
        // 옵트아웃 ON → 과거 데이터 삭제 RPC (마이그레이션 029)
        if (newOptOut) {
          // session_hash 는 서버에서 sha256(user_id + 일자) 로 생성되지만
          // 클라가 직접 모름 → 일자별 가능성 모두 시도하기엔 비효율적.
          // 정확한 즉시 삭제는 별도 서버 엔드포인트로 처리 (Phase 1 후속).
          // 본 단계에선 플래그 set 만 — 다음 cron / purge 시점에 자연스럽게 정리.
          setTrMsg('수집을 중단했어요. 과거 데이터는 90일 이내 자동 삭제됩니다.');
        } else {
          setTrMsg('번역 품질 개선에 동의해주셔서 감사합니다.');
        }
      } catch (e) {
        console.error('[SettingsModal] tr opt-out', e);
        setTrOptOut(prev);   // 롤백
        setTrMsg('변경 실패 — 잠시 후 다시 시도해주세요.');
      } finally {
        setTrBusy(false);
      }
    };

    // 댓글 기록 — comments 섹션 진입 시 fetch
    useEffect(() => {
      if (section !== 'comments') return;
      if (!supabaseClient || !user?.id) { setMyComments([]); return; }
      let active = true;
      setCommentsLoading(true);
      (async () => {
        try {
          const { data, error } = await supabaseClient
            .from('comments')
            .select('id,post_id,text,language,created_at,star_count,is_deleted,posts:posts!post_id(id,text,author_id,is_deleted,game_tag)')
            .eq('author_id', user.id)
            .eq('is_deleted', false)
            .order('created_at', { ascending: false })
            .limit(50);
          if (!active) return;
          if (error) throw error;
          setMyComments((data || []).filter(c => c.posts && !c.posts.is_deleted));
        } catch (e) {
          console.warn('[SettingsModal] my comments load', e.message);
          if (active) setMyComments([]);
        } finally {
          if (active) setCommentsLoading(false);
        }
      })();
      return () => { active = false; };
    }, [section, supabaseClient, user?.id]);

    const relTime = (iso) => {
      if (!iso) return '';
      const d = new Date(iso);
      const diff = (Date.now() - d.getTime()) / 1000;
      if (diff < 60) return '방금';
      if (diff < 3600) return Math.floor(diff/60) + '분 전';
      if (diff < 86400) return Math.floor(diff/3600) + '시간 전';
      if (diff < 604800) return Math.floor(diff/86400) + '일 전';
      return d.toLocaleDateString('ko-KR', { month: 'numeric', day: 'numeric' });
    };

    const saveNickname = async () => {
      setNickError('');
      const next = (nick || '').trim();
      if (!next) { setNickError('닉네임을 입력해주세요'); return; }
      if (next.length > 30) { setNickError('30자 이하로 입력해주세요'); return; }
      if (next === currentDisplayName) { onClose && onClose(); return; }

      setNickBusy(true);
      try {
        let savedProfile = null;
        if (supabaseClient && user?.id) {
          const { error } = await withTimeout(
            supabaseClient.rpc('update_display_name', {
              p_user_id: user.id, p_display_name: next,
            }),
            7000,
            { error: new Error('nickname_save_timeout') }
          );
          if (error) throw error;
          try {
            const { data } = await withTimeout(
              supabaseClient
                .from('users')
                .select('display_name,username,avatar,is_admin')
                .eq('id', user.id)
                .maybeSingle(),
              3500,
              { data: null }
            );
            savedProfile = data || null;
          } catch (e) {}
        }
        const savedName = savedProfile?.display_name || next;
        setNick(savedName);
        onNicknameChanged && onNicknameChanged(savedName, savedProfile);
        onClose && onClose();
      } catch (e) {
        setNickError(helpers.translateAuthError ? helpers.translateAuthError(e) : (e?.message || '저장 실패'));
      } finally { setNickBusy(false); }
    };

    const saveLanguage = async (code) => {
      if (code === currentLang) return;
      setLang(code);
      setLangBusy(true);
      try {
        if (supabaseClient && user?.id) {
          const { error } = await supabaseClient.rpc('update_preferred_language', {
            p_user_id: user.id, p_lang: code,
          });
          if (error) throw error;
        }
        onLangChanged && onLangChanged(code);
        // i18n 즉시 반영
        if (global.WildyI18n && global.WildyI18n.setLang) {
          global.WildyI18n.setLang(code);
        }
      } catch (e) {
        console.error('[SettingsModal] saveLanguage', e);
        setLang(currentLang);  // rollback
      } finally { setLangBusy(false); }
    };

    const MenuRow = ({ icon, label, sub, onClick, danger }) => (
      <button
        onClick={onClick}
        className={`flex w-full items-center gap-3 rounded-2xl px-4 py-3.5 text-left hover:bg-slate-50 transition ${danger ? 'text-rose-600' : 'text-slate-800'}`}
      >
        <span className="text-xl flex-shrink-0">{icon}</span>
        <span className="flex-1 min-w-0">
          <span className="block font-bold text-sm">{label}</span>
          {sub && <span className="block text-xs text-slate-500 mt-0.5 truncate">{sub}</span>}
        </span>
        <span className="text-slate-300">›</span>
      </button>
    );

    return (
      <div
        className="fixed inset-0 z-[130] flex items-center justify-center bg-black/40 p-4 sm:p-6"
        onClick={onClose}
      >
        <div
          onClick={(e) => e.stopPropagation()}
          className="w-full max-w-md max-h-[90vh] rounded-3xl bg-white shadow-2xl overflow-hidden flex flex-col"
        >
          {/* Header */}
          <div className="flex items-center justify-between border-b border-slate-100 px-5 py-4">
            <button
              onClick={() => {
                if (section === 'menu') return onClose && onClose();
                // 하위 → 상위 (comments/shares는 activity로, 나머지는 menu로)
                if (section === 'comments' || section === 'shares') return setSection('activity');
                return setSection('menu');
              }}
              className="flex h-9 w-9 items-center justify-center rounded-full hover:bg-slate-100"
              aria-label={section === 'menu' ? '닫기' : '이전'}
            >
              {section === 'menu' ? '✕' : '←'}
            </button>
            <h2 className="font-display text-lg font-black text-wildy-ink">
              {section === 'menu' ? '설정'
                : section === 'nickname' ? '닉네임 변경'
                : section === 'language' ? '표시 언어'
                : section === 'translation' ? '번역 설정'
                : section === 'notif' ? '알림 설정'
                : section === 'account' ? '계정 관리'
                : section === 'activity' ? '내 활동'
                : section === 'comments' ? '내 댓글 기록'
                : section === 'shares' ? '내 공유 기록'
                : '설정'}
            </h2>
            <div className="w-9"></div>
          </div>

          {/* Body */}
          <div className="flex-1 overflow-y-auto p-3">
            {section === 'menu' && (
              <div className="space-y-1">
                <MenuRow icon="👤" label="닉네임 변경" sub={currentDisplayName || 'Wilder'} onClick={() => setSection('nickname')} />
                <MenuRow icon="🌐" label="표시 언어" sub={LANGS.find(l => l.code === currentLang)?.label || '한국어'} onClick={() => setSection('language')} />
                <MenuRow icon="✦" label="번역 설정" sub="번역 데이터 수집 동의 관리" onClick={() => setSection('translation')} />
                <MenuRow icon="📊" label="내 활동" sub="좋아함 · 댓글 · 공유 기록" onClick={() => setSection('activity')} />
                <MenuRow icon="🔔" label="알림 설정" sub="DM · 멘션 · 게시물" onClick={() => setSection('notif')} />
                <MenuRow icon="⚙️" label="계정 관리" sub="이메일 · 비밀번호 · 삭제" onClick={() => setSection('account')} />
                <div className="my-2 h-px bg-slate-100" />
                {onLogout && (
                  <MenuRow icon="🚪" label="로그아웃" onClick={() => { onClose && onClose(); onLogout(); }} danger />
                )}
              </div>
            )}

            {/* 내 활동 — 좋아함 / 댓글 / 공유 진입 */}
            {section === 'activity' && (
              <div className="space-y-1 p-1">
                <p className="px-3 pt-2 pb-3 text-xs text-slate-500" style={{ wordBreak: 'keep-all' }}>
                  내가 좋아하거나 댓글 단 게시물을 다시 볼 수 있어요.
                </p>
                <MenuRow
                  icon="✦"
                  label="좋아함"
                  sub="내가 ✦ 준 게시물"
                  onClick={() => {
                    onOpenSparkledTab && onOpenSparkledTab();
                    onClose && onClose();
                  }}
                />
                <MenuRow icon="💬" label="댓글 기록" sub="내가 남긴 댓글" onClick={() => setSection('comments')} />
                <MenuRow icon="🔗" label="공유 기록" sub="Phase 2에서 활성화" onClick={() => setSection('shares')} />
              </div>
            )}

            {/* 댓글 기록 */}
            {section === 'comments' && (
              <div className="p-2 space-y-2">
                {commentsLoading && (
                  <div className="py-8 text-center text-sm text-slate-400">로딩 중...</div>
                )}
                {!commentsLoading && myComments.length === 0 && (
                  <div className="py-12 text-center text-sm text-slate-400" style={{ wordBreak: 'keep-all' }}>
                    <div className="text-3xl mb-2">💬</div>
                    아직 남긴 댓글이 없어요
                  </div>
                )}
                {!commentsLoading && myComments.map(c => (
                  <button
                    key={c.id}
                    onClick={() => {
                      // 댓글이 달린 게시물 풀스크린으로 열기
                      if (onOpenPostDetail && c.posts) {
                        onOpenPostDetail([c.posts], 0);
                        onClose && onClose();
                      }
                    }}
                    className="w-full text-left rounded-2xl border border-slate-100 bg-white p-3 hover:border-sky-200 transition"
                  >
                    <div className="text-xs text-slate-500 mb-1 flex items-center gap-2">
                      <span>{relTime(c.created_at)}</span>
                      {c.posts?.game_tag && <span className="rounded-full bg-sky-50 px-1.5 py-0.5 text-[10px] font-bold text-sky-700">{c.posts.game_tag}</span>}
                    </div>
                    <div className="text-sm text-slate-800 line-clamp-2 mb-1.5" style={{ wordBreak: 'keep-all' }}>
                      {c.text}
                    </div>
                    {c.posts?.text && (
                      <div className="text-[11px] text-slate-400 italic line-clamp-1 border-l-2 border-slate-200 pl-2 mt-1" style={{ wordBreak: 'keep-all' }}>
                        → {c.posts.text.slice(0, 60)}
                      </div>
                    )}
                  </button>
                ))}
              </div>
            )}

            {/* 공유 기록 (Phase 2 placeholder) */}
            {section === 'shares' && (
              <div className="p-6 text-center text-sm text-slate-500" style={{ wordBreak: 'keep-all' }}>
                <div className="text-4xl mb-3">🔗</div>
                <p className="font-bold text-base text-slate-700 mb-2">공유 기록은 Phase 2에서 활성화돼요</p>
                <p>외부 공유 / 링크 복사 / 채팅방 공유 등의 기록을 한 곳에서 볼 수 있어요.</p>
              </div>
            )}

            {section === 'nickname' && (
              <div className="p-3 space-y-3">
                <label className="block text-xs font-bold text-slate-700">새 닉네임</label>
                <input
                  value={nick}
                  onChange={(e) => setNick(e.target.value)}
                  maxLength={30}
                  className="w-full rounded-2xl border-2 border-sky-100 px-4 py-3 outline-none focus:border-sky-300"
                  placeholder="닉네임 (1-30자)"
                  autoFocus
                />
                <p className="text-xs text-slate-500">현재: {currentDisplayName || '(없음)'}</p>
                {nickError && <div className="rounded-2xl bg-rose-50 px-4 py-3 text-sm text-rose-600">{nickError}</div>}
                <button
                  onClick={saveNickname}
                  disabled={nickBusy || !nick.trim() || nick.trim() === currentDisplayName}
                  className="w-full rounded-full bg-wildy-ink py-3 font-bold text-white disabled:bg-slate-300"
                >
                  {nickBusy ? '저장 중...' : '저장'}
                </button>
              </div>
            )}

            {section === 'language' && (
              <div className="p-3 space-y-2">
                <p className="text-xs text-slate-500 mb-3 px-1">메시지/피드 번역의 기본 언어를 설정합니다.</p>
                {LANGS.map(l => (
                  <button
                    key={l.code}
                    onClick={() => saveLanguage(l.code)}
                    disabled={langBusy}
                    className={`flex w-full items-center gap-3 rounded-2xl px-4 py-3 text-left transition disabled:opacity-50 ${lang === l.code ? 'bg-wildy-ink text-white' : 'hover:bg-slate-50 text-slate-700'}`}
                  >
                    <span className="text-xl">{l.flag}</span>
                    <span className="flex-1 font-bold text-sm">{l.label}</span>
                    {lang === l.code && <span>✓</span>}
                  </button>
                ))}
              </div>
            )}

            {section === 'translation' && (
              <div className="p-3 space-y-4">
                <div className="rounded-2xl bg-sky-50/60 border border-sky-100 px-4 py-3.5 text-xs text-slate-700 leading-relaxed" style={{ wordBreak: 'keep-all' }}>
                  Wildy 는 번역 품질 개선을 위해 <b className="text-wildy-deep">익명화된</b> 번역 데이터를 수집합니다.
                  <a href="/terms#ch9" target="_blank" rel="noreferrer" className="ml-1 text-sky-600 underline">자세히 보기</a>
                </div>

                <div className="rounded-2xl border-2 border-slate-100 bg-white p-4">
                  <div className="flex items-center justify-between gap-3 mb-3">
                    <div className="flex-1 min-w-0">
                      <div className="font-bold text-sm text-wildy-ink">번역 데이터 수집</div>
                      <div className="mt-0.5 text-[11px] text-slate-500" style={{ wordBreak: 'keep-all' }}>
                        {trOptOut === null ? '확인 중...' : trOptOut ? '거부 상태 — 수집 안 됨' : '동의 상태 — 익명화하여 수집 중'}
                      </div>
                    </div>
                    {trOptOut !== null && (
                      <button
                        onClick={() => toggleTrOptOut(!trOptOut)}
                        disabled={trBusy}
                        className={`relative inline-flex h-7 w-12 shrink-0 rounded-full transition disabled:opacity-50 ${trOptOut ? 'bg-slate-300' : 'bg-emerald-500'}`}
                        aria-label="번역 데이터 수집 토글"
                      >
                        <span className={`absolute top-0.5 inline-flex h-6 w-6 rounded-full bg-white shadow transition ${trOptOut ? 'left-0.5' : 'left-[1.375rem]'}`} />
                      </button>
                    )}
                  </div>
                  <ul className="space-y-1.5 text-[11px] text-slate-500" style={{ wordBreak: 'keep-all' }}>
                    <li>· 수집: 원문(개인 식별 정보 제거) · 언어쌍 · 게임 카테고리 · 만족도(직접 표시 시)</li>
                    <li>· 미수집: 이메일·이름·IP, 1:1 비공개 채팅 원문</li>
                    <li>· 90일 후 원문 자동 삭제 (해시·통계는 익명 유지)</li>
                    <li>· 거부 시 향후 수집 중단 + 과거 데이터 90일 이내 자연 삭제</li>
                  </ul>
                </div>

                {trMsg && (
                  <div className="rounded-2xl bg-amber-50 border border-amber-200 px-4 py-3 text-xs text-amber-800" style={{ wordBreak: 'keep-all' }}>
                    {trMsg}
                  </div>
                )}
              </div>
            )}

            {section === 'notif' && (
              <div className="p-6 text-center text-sm text-slate-500" style={{ wordBreak: 'keep-all' }}>
                <div className="text-4xl mb-3">🔔</div>
                알림 설정은 Phase 2에서 추가될 예정이에요.
              </div>
            )}

            {section === 'account' && (
              <AccountSection
                user={user}
                supabaseClient={supabaseClient}
                onProfileChanged={(profile) => onNicknameChanged && onNicknameChanged(profile?.display_name || currentDisplayName, profile)}
              />
            )}
          </div>
        </div>
      </div>
    );
  }

  global.WildyComponents = global.WildyComponents || {};
  global.WildyComponents.SettingsModal = SettingsModal;
})(typeof window !== 'undefined' ? window : globalThis);
