/* ============================================================
   shell.jsx — single-document integrated shell (index2.html)
   Login (배너1) → tab chrome → home tab = Studio2App (배너2, .s2 scope)
   "가이드 편집" (window.postMessage) → named editor tab = AdminEditor (배너1) seeded
   Uses hooks from the global declaration in admin-editor.jsx (no re-declare).
   ============================================================ */

const HomeIcon = ({ size = 17 }) =>
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
    <path d="M3 10.5 12 3l9 7.5" /><path d="M5 9.5V20a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9.5" />
  </svg>;

const PlusIcon = ({ size = 17 }) =>
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"><path d="M12 5v14M5 12h14" /></svg>;

const CloseIcon = ({ size = 13 }) =>
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>;

const GearIcon = ({ size = 15 }) =>
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
    <circle cx="12" cy="12" r="3" />
    <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
  </svg>;

const SparkIcon = ({ size = 15 }) =>
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
    <path d="M9.5 3.5 10.8 7l3.5 1.3-3.5 1.3L9.5 13 8.2 9.6 4.7 8.3 8.2 7z" />
    <path d="M17.5 13.5l.8 2 2 .8-2 .8-.8 2-.8-2-2-.8 2-.8z" />
  </svg>;


function EditorView({ brand, blank, name, category, persist, editorId }) {
  const cats = window.SEED_CATEGORIES || [];
  const seeds = window.SEED_GUIDES || [];
  const cat = category ? cats.find((c) => c.name === category) : null;
  const match = !blank && (
    (cat && seeds.find((g) => g.category === cat.id && g.name === name)) ||
    seeds.find((g) => g.name === name) || null);
  const activeCat = blank ? null : (match ? match.category : (cat ? cat.id : "ap"));
  const activeGid = blank ? null : (match ? match.id : "ap-0");
  return (
    <AdminEditor
      tweaks={{ platform: "cj", mode: "admin", showGrid: false, accentColor: "#4E4CDB" }}
      brand={brand}
      onToggleGrid={() => {}}
      initialCategories={blank ? [] : SEED_CATEGORIES}
      initialGuides={blank ? [] : SEED_GUIDES}
      initialActiveCategory={activeCat}
      initialActiveGuideId={activeGid}
      persistKey={persist}
      editorId={editorId} />);


}

// 초대/비밀번호 재설정 링크 진입 시 새 비밀번호 설정 화면
const EyeIcon = ({ off }) => off ?
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" /><path d="M1 1l22 22" /></svg> :
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" /><circle cx="12" cy="12" r="3" /></svg>;

function SetPasswordScreen({ onDone }) {
  const [pw, setPw] = useState("");
  const [pw2, setPw2] = useState("");
  const [show, setShow] = useState(false);
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState("");
  const submit = async (e) => {
    e && e.preventDefault();
    setErr("");
    if (pw.length < 6) {setErr("비밀번호는 6자 이상이어야 해요");return;}
    if (pw !== pw2) {setErr("비밀번호가 일치하지 않아요");return;}
    setBusy(true);
    const r = window.__auth && window.__auth.updatePassword ? await window.__auth.updatePassword(pw) : { ok: false, error: "서버 설정이 없습니다" };
    setBusy(false);
    if (r && r.ok) onDone && onDone();else setErr((r && r.error) || "설정에 실패했어요. 링크가 만료되었을 수 있어요.");
  };
  const field = (val, set, ph, auto) =>
  <div style={{ position: "relative", marginBottom: 10 }}>
      <input className="login-input" type={show ? "text" : "password"} placeholder={ph} value={val} autoFocus={auto}
        onChange={(e) => set(e.target.value)} style={{ width: "100%", boxSizing: "border-box", paddingRight: 42 }} />
      <button type="button" onClick={() => setShow((s) => !s)} title={show ? "숨기기" : "보기"}
        style={{ position: "absolute", right: 10, top: "50%", transform: "translateY(-50%)", border: "none", background: "none", cursor: "pointer", color: "#8a8a96", padding: 4, lineHeight: 0 }}>
        <EyeIcon off={show} />
      </button>
    </div>;
  return (
    <div style={{ position: "fixed", inset: 0, background: "#f4f4f6", display: "grid", placeItems: "center", fontFamily: '"Pretendard Variable", Pretendard, system-ui, sans-serif', zIndex: 100 }}>
      <div style={{ width: 380, maxWidth: "92vw", background: "#fff", borderRadius: 18, padding: 32, boxShadow: "0 16px 48px rgba(0,0,0,.14)" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 22 }}>
          <div style={{ width: 30, height: 30, borderRadius: 8, background: "linear-gradient(135deg,#4E4CDB,#7c6df0)", display: "grid", placeItems: "center" }}><BannerMark size={16} /></div>
          <span style={{ fontSize: 16, fontWeight: 700, letterSpacing: "-0.02em", color: "#1e1e1e" }}>Bannerly</span>
        </div>
        <div style={{ fontSize: 20, fontWeight: 800, marginBottom: 6, color: "#1c1c22" }}>비밀번호 설정</div>
        <div style={{ fontSize: 13, color: "#8a8a96", marginBottom: 20, lineHeight: 1.5 }}>Bannerly 사용을 위해 새 비밀번호를 설정해 주세요.</div>
        <form onSubmit={submit}>
          {field(pw, setPw, "새 비밀번호", true)}
          {field(pw2, setPw2, "새 비밀번호 확인", false)}
          <div style={{ fontSize: 11.5, color: "#8a8a96", margin: "2px 2px 14px" }}>· 6자 이상 입력해 주세요.</div>
          {err && <div style={{ margin: "0 0 12px", padding: "9px 12px", borderRadius: 8, background: "#fdecec", color: "#c0392b", fontSize: 12.5 }}>{err}</div>}
          <button type="submit" className="login-submit" disabled={busy} style={{ width: "100%" }}>{busy ? "설정 중…" : "비밀번호 설정하고 시작하기"}</button>
        </form>
      </div>
    </div>);

}

function IntegratedApp() {
  // 인증 상태: authReady=세션 확인 완료 여부, user=로그인 사용자(없으면 로그인 화면)
  const [authReady, setAuthReady] = useState(false);
  const [user, setUser] = useState(null);
  const [needPwSet, setNeedPwSet] = useState(!!window.__BANNERLY_PWSET);
  const loggedIn = !!user;
  const [tabs, setTabs] = useState([]); // editor tabs: { id, name }
  const [active, setActive] = useState("home"); // "home" | tab.id
  // [보류] 관리자 영역을 임시로 숨김: 기본 권한을 "user"로 고정하고 관리자/사용자 토글 버튼을 제거함.
  // 관리자 코드·진입로(canCreate 게이팅)는 삭제하지 않고 그대로 둠 — role 을 "admin"으로 되돌리고
  // 아래 imode-toggle 블록을 복원하면 관리자 영역이 다시 노출된다.
  const [role, setRole] = useState("user"); // "admin" | "user" — 실제 권한(프로필)
  const [viewAsUser, setViewAsUser] = useState(false); // 관리자가 '사용자 화면'으로 전환
  const [brandGuides, setBrandGuides] = useState(window.BRAND_GUIDES);
  const [brandOpen, setBrandOpen] = useState(false);
  const [homeNav, setHomeNav] = useState(null); // Studio2App 이 발행하는 워크스페이스 네비 상태
  const [publishConfirm, setPublishConfirm] = useState(false);
  const [importConfirm, setImportConfirm] = useState(null); // 불러오기 확인 대기 데이터
  const [showAccountSettings, setShowAccountSettings] = useState(false);
  const fileRef = useRef(null);
  const [toast, setToast] = useState(null);
  const showToast = (m) => {setToast(m);setTimeout(() => setToast(null), 2200);};

  // ---- 백업 내보내기 / 불러오기 ----
  const handleExport = () => {
    const api = window.__bannerlyEditors && window.__bannerlyEditors[active];
    if (!api) {showToast("내보낼 편집기가 없습니다");return;}
    const res = api.exportBackup();
    if (res && res.ok) showToast(`백업 파일을 내보냈습니다 (가이드 ${res.counts.guides}개)`);
  };
  const handleImportFile = (e) => {
    const file = e.target.files && e.target.files[0];
    e.target.value = ""; // 같은 파일 다시 선택 허용
    if (!file) return;
    const reader = new FileReader();
    reader.onload = () => {
      let data = null;
      try {data = JSON.parse(reader.result);} catch (err) {showToast("파일을 읽을 수 없습니다");return;}
      if (!data || !Array.isArray(data.categories) || !Array.isArray(data.guides)) {
        showToast("백업 파일 형식이 올바르지 않습니다");return;
      }
      setImportConfirm(data); // 덮어쓰기 확인 다이얼로그
    };
    reader.readAsText(file);
  };
  const applyImport = () => {
    const data = importConfirm;
    setImportConfirm(null);
    const api = window.__bannerlyEditors && window.__bannerlyEditors[active];
    if (!api) {showToast("불러올 편집기가 없습니다");return;}
    const res = api.importBackup(data);
    if (res && res.ok) showToast(`백업을 불러왔습니다 (가이드 ${res.counts.guides}개)`);else
    showToast(res && res.error || "불러오기에 실패했습니다");
  };

  useEffect(() => {
    const onMsg = (e) => {
      const d = e.data || {};
      if (d.type === "bannerly-open-editor") {
        const name = d.name || "가이드";
        const category = d.category || null;
        const blank = !!d.blank;
        setTabs((prev) => {
          const ex = prev.find((t) => t.name === name && (t.category || null) === category);
          if (ex) {setActive(ex.id);return prev;}
          const id = "ed-" + Date.now();
          // 가이드 정체성(카테고리+이름) 기반의 안정적 저장 키 — 같은 가이드를 다시 열면 작업이 복원되고,
          // 리로드 시에도 캔버스 작업이 사라지지 않는다. (blank 새 가이드는 저장하지 않음)
          const persist = blank ? undefined : "bannerly:editor:" + (category || "") + "::" + name;
          setActive(id);
          return [...prev, { id, name, category, blank, persist }];
        });
      }
    };
    window.addEventListener("message", onMsg);
    return () => window.removeEventListener("message", onMsg);
  }, []);

  // ---- 인증 부팅: 저장된 세션 복원 + 로컬 개발 우회 ----
  useEffect(() => {
    let cancelled = false;
    let unsub = () => {};
    const boot = async () => {
      // 로컬(localhost) 개발 편의: 로그인 화면을 건너뛴다 (배포에선 실제 로그인)
      if (window.__BANNERLY_DEV_BYPASS) {
        window.__bannerlyUser = "개발자";
        window.__bannerlyRole = "user";
        if (!cancelled) {setUser({ email: "dev@local", dev: true });setRole("user");setAuthReady(true);}
        return;
      }
      // supabase 모듈(module script)이 늦게 로드될 수 있어 __auth 준비를 잠시 대기
      for (let i = 0; i < 100 && !window.__auth; i++) {await new Promise((r) => setTimeout(r, 50));}
      if (!window.__auth || !window.__auth.hasConfig()) {
        if (!cancelled) setAuthReady(true); // 설정 없음 → 로그인 화면 노출
        return;
      }
      const res = await window.__auth.currentUser();
      if (cancelled) return;
      if (res) {setUser(res.user);setRole((res.profile && res.profile.role) || "user");}
      setAuthReady(true);
      // 세션 만료/외부 로그아웃 반영
      unsub = window.__authSubscribe((u) => {
        if (cancelled) return;
        setUser(u);
        if (!u) setRole("user");
      });
    };
    boot();
    return () => {cancelled = true;unsub();};
  }, []);

  const handleLogout = useCallback(async () => {
    try {
      if (window.__auth) await window.__auth.signOut();
    } catch (e) {}
    // Supabase 세션 키를 직접 제거해 재로드 후 로그인 화면이 나오도록
    try {
      Object.keys(localStorage).forEach((k) => {
        if (k.startsWith('bannerly-auth') || k.startsWith('sb-') || k === 'supabase.auth.token') {
          localStorage.removeItem(k);
        }
      });
    } catch (e) {}
    setUser(null);
    setRole("user");
    setActive("home");
    setTabs([]);
    // 깨끗한 상태를 보장하기 위해 페이지 재로드
    window.location.href = window.location.origin + '/';
  }, []);

  // when a tab becomes visible, let the editor re-measure & fit
  useEffect(() => {window.dispatchEvent(new Event("resize"));}, [active]);

  const closeTab = useCallback((id, e) => {
    e && e.stopPropagation();
    setTabs((prev) => prev.filter((t) => t.id !== id));
    setActive((cur) => cur === id ? "home" : cur);
  }, []);

  // 모드 전환 토글: 권한 전환. 사용자는 관리자 권한이 없어 편집기에 진입할 수 없고 홈(가이드)만 볼 수 있음
  const goAdmin = useCallback(() => {setRole("admin");setActive("home");}, []);
  const goUser = useCallback(() => {
    setRole("user");
    setActive("home");
  }, []);
  if (!authReady) {
    return (
      <div className="login-shell" style={{ display: "grid", placeItems: "center" }}>
        <div className="spinner" style={{ width: 30, height: 30 }} />
      </div>);

  }
  if (needPwSet) {
    return <SetPasswordScreen onDone={() => {location.href = location.origin + "/";}} />;
  }
  if (!loggedIn) {
    return <LoginScreen onLogin={(u, profile) => {setUser(u);setRole((profile && profile.role) || "user");}} />;
  }

  const platform = (window.PLATFORMS || []).find((p) => p.id === "cj") || (window.PLATFORMS || [])[0];
  const brand = brandGuides.cj;
  const setBrand = (patch) => setBrandGuides((bg) => ({ ...bg, cj: { ...bg.cj, ...patch } }));
  const isEditor = active !== "home";
  // 관리자가 '사용자 화면으로 전환'하면 화면(메뉴)만 사용자로. 실제 권한(role)은 그대로.
  const effRole = (role === "admin" && viewAsUser) ? "user" : role;
  const toggleViewAsUser = () => {setViewAsUser((v) => !v);setActive("home");setTabs([]);};
  const activeTab = tabs.find((t) => t.id === active);
  const guideName = activeTab ? activeTab.name : "";

  return (
    <div className="ishell">
      {/* 전역 상단바 (B): 로고 + 계정 — 탭 스트립은 추후 이 바에 추가 예정 */}
      <header className="iglobalbar">
        <button className="iglobal-brand" onClick={() => {setActive("home");if (homeNav && homeNav.onNav) homeNav.onNav('dashboard');}} title="홈으로">
          <div className="brand-mark"><BannerMark size={15} /></div>
          <span className="brand-name">Bannerly</span>
        </button>

        {active === "home" && homeNav &&
        <div className="s2 s2-navhost">
            <WorkspaceNav {...homeNav} />
          </div>
        }

        {/* [보류] 관리자/사용자 권한 토글 — 관리자 영역을 임시로 숨기며 제거함. 복원 시 아래 블록을 되살릴 것:
        <div className="imode-toggle" role="tablist" aria-label="권한 전환">
          <button className={"imode-seg" + (role === "admin" ? " on" : "")} role="tab" aria-selected={role === "admin"} onClick={goAdmin}>
            <GearIcon size={15} /> 관리자
          </button>
          <button className={"imode-seg" + (role === "user" ? " on" : "")} role="tab" aria-selected={role === "user"} onClick={goUser}>
            <SparkIcon size={15} /> 사용자
          </button>
        </div>
        */}

        <div className="iglobal-spacer" />

        <div className="iglobal-right">
          <div className="s2 s2-navhost"><AccountMenu role={role} email={user && user.email} onLogout={handleLogout} onSettings={() => setShowAccountSettings(true)} canSwitchView={role === "admin"} viewAsUser={viewAsUser} onToggleView={toggleViewAsUser} /></div>
        </div>
      </header>

      <div className="istage">
        {effRole === "admin" && isEditor && tabs.length > 0 &&
        <div className="ieditor-tabbar">
            {tabs.map((t) =>
          <div key={t.id} className={"iglobal-file" + (active === t.id ? " on" : "")} title={t.name} onClick={() => setActive(t.id)} style={{ borderRadius: "6px", height: "30px", borderStyle: "none" }}>
                <span className="iglobal-file-name" style={{ fontSize: "12px" }}>{t.name}</span>
                <button className="iglobal-file-close" onClick={(e) => closeTab(t.id, e)} title="편집기 닫기">
                  <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
                </button>
              </div>
          )}
            {/* 편집기 헤더 우측 액션: 브랜드 가이드 · 임시 저장하기 · 배포하기 · 백업 */}
            <div style={{ marginLeft: "auto", display: "flex", alignItems: "center", gap: "8px", flexShrink: 0 }}>
              <button className="btn icon-only brand-icon-btn" onClick={() => setBrandOpen(true)} title="브랜드 가이드" style={{ borderRadius: "6px" }}>
                <I.Palette size={15} />
              </button>
              <button className="btn dark" style={{ fontWeight: 700, borderRadius: "6px" }} onClick={handleExport} title="현재 편집 내용을 JSON 파일로 저장">
                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /><path d="M7 10l5 5 5-5" /><path d="M12 15V3" /></svg>
                임시 저장하기
              </button>
              <button className="btn primary" style={{ fontWeight: 700, borderRadius: "6px" }} onClick={() => setPublishConfirm(true)} title="가이드를 사용자에게 배포">
                <I.Check size={12} />
                배포하기
              </button>
              <input ref={fileRef} type="file" accept="application/json,.json" style={{ display: "none" }} onChange={handleImportFile} />
            </div>
          </div>
        }
        <div className="iviews">
          <div className="iview" style={{ display: active === "home" ? "block" : "none" }}>
            <div className="s2"><Studio2App role={effRole} publishNav={setHomeNav} /></div>
          </div>
          {tabs.map((t) =>
          <div key={t.id} className="iview" style={{ display: active === t.id ? "block" : "none" }}>
              <EditorView brand={brand} blank={t.blank} name={t.name} category={t.category} persist={t.persist} editorId={t.id} />
            </div>
          )}
        </div>
      </div>

      {brandOpen && <BrandGuideManager platform={platform} brand={brand} onChange={setBrand} onClose={() => setBrandOpen(false)} />}
      <ConfirmDialog
        open={publishConfirm}
        title="가이드를 배포하시겠습니까?"
        message="배포하면 현재 가이드가 모든 사용자에게 즉시 적용됩니다."
        confirmLabel="배포하기"
        onConfirm={() => {
          setPublishConfirm(false);
          const t = tabs.find((x) => x.id === active);
          if (t && window.__guideStore) {
            window.__guideStore.upsert({
              id: (t.category ? t.category + '::' : '') + t.name,
              category: t.category || t.name, name: t.name,
              published: true, updatedAt: new Date().toISOString(),
              author: window.__bannerlyName || null,
            }).catch(() => {});
          }
          showToast("가이드가 배포되었습니다");
        }}
        onCancel={() => setPublishConfirm(false)} />
      <ConfirmDialog
        open={!!importConfirm}
        title="백업을 불러오시겠습니까?"
        message={importConfirm ? `현재 편집 중인 내용이 백업 파일의 내용으로 대체됩니다 (카테고리 ${importConfirm.categories.length}개 · 가이드 ${importConfirm.guides.length}개). 이 작업은 되돌리기(⌘Z)로 취소할 수 있습니다.` : ""}
        confirmLabel="불러오기"
        onConfirm={applyImport}
        onCancel={() => setImportConfirm(null)} />
      
      {showAccountSettings && (() => {
        const M = window.AccountSettingsModal;
        return M ? <div className="s2"><M email={user && user.email} onClose={() => setShowAccountSettings(false)} /></div> : null;
      })()}
      {toast && <div className="save-toast"><I.Check size={13} stroke="#fff" /> {toast}</div>}
    </div>);

}

ReactDOM.createRoot(document.getElementById("root")).render(<IntegratedApp />);