/* ===== 양푸른 게임 사운드 디자인 포트폴리오 — App ===== */
const { useState, useEffect, useRef, useMemo } = React;

const LS_SETTINGS = "yp_settings_v4";
const LS_PROJECTS = "yp_projects_v4";

function load(key, fb) { try { const r = localStorage.getItem(key); return r ? JSON.parse(r) : fb; } catch (e) { return fb; } }
function save(key, v) { try { localStorage.setItem(key, JSON.stringify(v)); } catch (e) {} }

const ytThumb = (id) => `https://img.youtube.com/vi/${id}/hqdefault.jpg`;
const ytEmbed = (id) => `https://www.youtube.com/embed/${id}`;
const ytWatch = (id) => `https://youtu.be/${id}`;

const CAT_STYLE = {
  "사운드 디자인": "text-accent border-accent/50",
  "BGM": "text-emerald-300 border-emerald-400/40",
  "Foley": "text-orange-300 border-orange-400/40",
  "Engine": "text-sky-300 border-sky-400/40",
  "Voice": "text-fuchsia-300 border-fuchsia-400/40",
};

function Tag({ children, className = "" }) {
  return <span className={"inline-flex items-center rounded-full border border-line px-2.5 py-1 text-[11px] tracking-wider text-neutral-300 " + className}>{children}</span>;
}

function Collapsible({ title, subtitle, defaultOpen = false, children }) {
  const [open, setOpen] = useState(defaultOpen);
  return (
    <div className="overflow-hidden rounded-xl border border-line bg-ink-2">
      <button onClick={() => setOpen((o) => !o)}
        className="flex w-full items-center justify-between gap-3 px-5 py-4 text-left transition hover:bg-white/[0.02]">
        <div>
          <div className="text-sm font-bold text-white">{title}</div>
          {subtitle && <div className="mt-0.5 text-xs text-neutral-500">{subtitle}</div>}
        </div>
        <span className={"shrink-0 text-accent transition-transform " + (open ? "rotate-180" : "")}>▾</span>
      </button>
      {open && <div className="border-t border-line px-5 py-4">{children}</div>}
    </div>
  );
}

/* ---------- DSP 비주얼라이저 ---------- */
function Visualizer({ live }) {
  const ref = useRef(null);
  const st = useRef({ bars: [], t: 0 });
  useEffect(() => {
    const c = ref.current; if (!c) return;
    const ctx = c.getContext("2d"); let raf; const N = 64;
    if (st.current.bars.length !== N) st.current.bars = Array.from({ length: N }, () => Math.random());
    const resize = () => { const r = c.getBoundingClientRect(); c.width = r.width * devicePixelRatio; c.height = r.height * devicePixelRatio; };
    resize(); window.addEventListener("resize", resize);
    const draw = () => {
      const w = c.width, h = c.height; ctx.clearRect(0, 0, w, h);
      const b = st.current.bars; st.current.t += 0.05; const t = st.current.t; const bw = w / b.length;
      for (let i = 0; i < b.length; i++) {
        const tg = live ? (0.25 + 0.75 * Math.abs(Math.sin(i * 0.35 + t) * Math.cos(i * 0.12 - t * 0.7))) : (0.06 + 0.10 * Math.abs(Math.sin(i * 0.3 + t * 0.4)));
        b[i] += (tg - b[i]) * 0.2;
        const bh = Math.max(2 * devicePixelRatio, b[i] * h * 0.92), x = i * bw, y = h - bh;
        const g = ctx.createLinearGradient(0, y, 0, h);
        g.addColorStop(0, `rgba(204,255,0,${live ? 0.9 : 0.5})`); g.addColorStop(1, "rgba(204,255,0,0.05)");
        ctx.fillStyle = g; ctx.fillRect(x + 1, y, bw - 2, bh);
      }
      raf = requestAnimationFrame(draw);
    };
    draw();
    return () => { cancelAnimationFrame(raf); window.removeEventListener("resize", resize); };
  }, [live]);
  return <canvas ref={ref} className="block h-full w-full" />;
}

/* ---------- 헤더 ---------- */
function Header({ settings }) {
  const nav = [["#about", "소개"], ["#works", "포트폴리오"], ["#career", "경력·자격"], ["#contact", "연락처"]];
  return (
    <header className="sticky top-0 z-40 border-b border-line/70 bg-ink/85 backdrop-blur">
      <div className="mx-auto flex max-w-7xl items-center justify-between gap-4 px-5 py-3">
        <a href="#/" className="flex items-baseline gap-2">
          <span className="hidden text-[10px] font-semibold uppercase tracking-[0.25em] text-neutral-500 sm:inline">{settings.role}</span>
          <span className="text-xl font-extrabold tracking-tight text-white">{settings.brandKr}</span>
        </a>
        <nav className="hidden items-center gap-7 md:flex">
          {nav.map(([href, label]) => (
            <a key={href} href={href} className="text-sm text-neutral-400 transition-colors hover:text-accent">{label}</a>
          ))}
        </nav>
        <div className="flex items-center gap-2">
          <a href="#works" className="rounded-full bg-accent px-3.5 py-1.5 text-xs font-bold text-black transition hover:brightness-110">작업물 보기</a>
          {/* ADMIN 진입은 헤더에 노출하지 않는다 — 주소창에 #/admin 으로 직접 접근 */}
        </div>
      </div>
    </header>
  );
}

/* ---------- 히어로 ---------- */
function Hero({ settings }) {
  const [live, setLive] = useState(false);
  return (
    <section className="bg-grid border-b border-line/60">
      <div className="mx-auto grid max-w-7xl gap-10 px-5 py-14 lg:grid-cols-2 lg:py-20">
        <div className="fade-up">
          <div className="mb-4 flex items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-neutral-400">
            <span className="inline-block h-2 w-2 rounded-full bg-accent dot-live" />{settings.role} · {settings.brandEn}
          </div>
          <h1 className="text-5xl font-extrabold tracking-tight text-white sm:text-6xl">{settings.brandKr}</h1>
          <p className="mt-5 max-w-xl text-[15px] leading-relaxed text-neutral-400">{settings.heroDesc}</p>
          <dl className="mt-6 space-y-1.5 text-sm">
            <div className="flex gap-3"><dt className="w-24 shrink-0 text-neutral-600">FOCUSED ON</dt><dd className="text-neutral-300">{settings.focusedOn.join(" · ")}</dd></div>
            <div className="flex gap-3"><dt className="w-24 shrink-0 text-neutral-600">TOOLS</dt><dd className="text-neutral-300">{settings.tools.join(", ")}</dd></div>
            <div className="flex gap-3"><dt className="w-24 shrink-0 text-neutral-600">BASED IN</dt><dd className="text-neutral-300">{settings.location}</dd></div>
          </dl>
          <div className="mt-6 rounded-xl border border-accent/40 bg-accent/10 p-4">
            <div className="flex items-center gap-2 text-[10px] font-bold uppercase tracking-[0.2em] text-accent">
              <span className="inline-block h-1.5 w-1.5 rounded-full bg-accent dot-live" />{settings.statusLabel}
            </div>
            <div className="mt-1.5 text-sm leading-relaxed text-neutral-100">{settings.status}</div>
          </div>
        </div>

        <div className="fade-up">
          <div className="rounded-2xl border border-line bg-ink-2 p-4">
            <div className="mb-3 flex items-center justify-between">
              <div className="text-[11px] font-semibold uppercase tracking-wider text-neutral-400"><span className="text-accent">▚</span> 실시간 사운드 스펙트럼 · DSP VISUALIZER</div>
              <div className="flex items-center gap-3 text-[10px] font-mono text-neutral-500">
                <span>96kHz / 24bit</span><span>−14.0 LUFS</span>
                <span className={live ? "text-accent" : ""}>{live ? "● LIVE" : "○ STANDBY"}</span>
              </div>
            </div>
            <div className="h-40 w-full overflow-hidden rounded-lg border border-line bg-black/60"><Visualizer live={live} /></div>
            <div className="mt-4 flex flex-col gap-2">
              {settings.playlistUrl && (
                <a href={settings.playlistUrl} target="_blank" rel="noreferrer"
                  className="rounded-lg bg-accent px-4 py-2.5 text-center text-sm font-bold text-black transition hover:brightness-110">
                  ▶ 포트폴리오 재생목록 보기 (YouTube)
                </a>
              )}
              <div className="flex gap-2">
                <button onClick={() => setLive((v) => !v)} className="flex-1 rounded-lg border border-line px-4 py-2.5 text-sm font-semibold text-neutral-300 transition hover:border-accent/60 hover:text-accent">
                  {live ? "■ 정지" : "▶ 스펙트럼 (데모)"}
                </button>
                <a href="#works" className="flex-1 rounded-lg border border-line px-4 py-2.5 text-center text-sm font-semibold text-neutral-200 transition hover:border-accent/60 hover:text-accent">개별 작업 보기 ↓</a>
              </div>
            </div>
            <div className="mt-5">
              <div className="mb-2 text-[10px] font-bold uppercase tracking-[0.2em] text-neutral-600">Pipeline & Middleware</div>
              <div className="flex flex-wrap gap-2">{settings.pipeline.map((p) => <Tag key={p} className="border-line/80">{p}</Tag>)}</div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---------- 스탯 ---------- */
function Stats({ stats }) {
  return (
    <section className="border-b border-line/60">
      <div className="mx-auto grid max-w-7xl grid-cols-2 gap-px bg-line/50 px-5 sm:grid-cols-4">
        {stats.map((s, i) => (
          <div key={i} className="bg-ink px-4 py-8">
            <div className="text-3xl font-extrabold text-accent">{s.value}</div>
            <div className="mt-2 text-sm font-semibold text-neutral-200">{s.label}</div>
            <div className="text-xs text-neutral-500">{s.sub}</div>
          </div>
        ))}
      </div>
    </section>
  );
}

/* ---------- 소개 / 강점 / 역량 ---------- */
function About() {
  return (
    <section id="about" className="mx-auto max-w-7xl px-5 py-16">
      <div className="mb-2 text-[11px] font-bold uppercase tracking-[0.25em] text-accent">◈ About & Strengths</div>
      <h2 className="text-3xl font-extrabold tracking-tight text-white sm:text-4xl">왜 양푸른인가</h2>
      <p className="mt-3 max-w-2xl text-sm leading-relaxed text-neutral-400">
        소리를 ‘만드는 것’에서 끝나지 않고, 게임 엔진 안에서 ‘작동하게’ 만드는 사운드 디자이너입니다.
        녹음·디자인·구현·현장 운영까지 오디오의 전 과정을 스스로 책임집니다.
      </p>

      <div className="mt-8 grid gap-4 sm:grid-cols-2">
        {window.STRENGTHS.map((s, i) => (
          <div key={i} className="rounded-xl border border-line bg-ink-2 p-5 transition hover:border-accent/40">
            <div className="text-2xl text-accent">{s.icon}</div>
            <h3 className="mt-2 text-lg font-bold text-white">{s.title}</h3>
            <p className="mt-1.5 text-sm leading-relaxed text-neutral-400">{s.desc}</p>
          </div>
        ))}
      </div>

      <div className="mt-10 grid gap-8 lg:grid-cols-2">
        <div>
          <h3 className="mb-4 text-sm font-bold uppercase tracking-wider text-neutral-300">역량 · Skills</h3>
          <div className="space-y-3">
            {window.SKILLS.map((s) => (
              <div key={s.group} className="flex flex-col gap-2 border-b border-line/60 pb-3 sm:flex-row sm:items-start">
                <div className="w-32 shrink-0 text-xs font-semibold uppercase tracking-wider text-accent">{s.group}</div>
                <div className="flex flex-wrap gap-1.5">
                  {s.items.map((it) => <span key={it} className="rounded bg-ink-3 px-2 py-1 text-xs text-neutral-300">{it}</span>)}
                </div>
              </div>
            ))}
          </div>
        </div>
        <div>
          <h3 className="mb-4 text-sm font-bold uppercase tracking-wider text-neutral-300">자격증 · Certifications</h3>
          <ul className="space-y-2">
            {window.CERTS.map((c, i) => (
              <li key={i} className="flex items-baseline gap-3 rounded-lg border border-line bg-ink-2 px-4 py-2.5">
                <span className="w-16 shrink-0 font-mono text-xs text-neutral-500">{c.date}</span>
                <span className="flex-1 text-sm text-neutral-100">{c.name}</span>
                <span className="hidden text-xs text-neutral-500 sm:inline">{c.org}</span>
              </li>
            ))}
          </ul>
        </div>
      </div>
    </section>
  );
}

/* ---------- 작업물 카드 ---------- */
function WorkCard({ p, onOpen }) {
  const [imgOk, setImgOk] = useState(true);
  return (
    <button onClick={() => onOpen(p)} className="work-card group flex flex-col overflow-hidden rounded-xl border border-line bg-ink-2 text-left">
      <div className="relative h-44 overflow-hidden" style={{ background: p.cover }}>
        {imgOk && (
          <img src={ytThumb(p.yt)} alt="" onError={() => setImgOk(false)}
            className="work-cover absolute inset-0 h-full w-full object-cover opacity-90" />
        )}
        <div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/10 to-transparent" />
        <span className="absolute left-1/2 top-1/2 flex h-11 w-11 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-accent/90 text-black opacity-0 transition group-hover:opacity-100">▶</span>
        <div className="absolute right-3 top-3 flex max-w-[80%] flex-wrap justify-end gap-1">
          {(p.cats || []).map((c) => (
            <span key={c} className={"rounded border bg-black/55 px-1.5 py-0.5 text-[9px] font-bold uppercase tracking-wide " + (CAT_STYLE[c] || "text-white border-white/30")}>{c}</span>
          ))}
        </div>
      </div>
      <div className="flex flex-1 flex-col p-4">
        <div className="text-[11px] uppercase tracking-wider text-neutral-500">{p.kind}</div>
        <h3 className="mt-1 text-base font-bold text-white group-hover:text-accent">{p.title}</h3>
        <p className="mt-1 text-sm text-neutral-400">{p.summary}</p>
        <div className="mt-3 flex flex-wrap gap-1.5">
          {(p.tools || []).slice(0, 3).map((t) => <span key={t} className="rounded bg-ink-3 px-2 py-0.5 text-[10px] text-neutral-400">{t}</span>)}
        </div>
      </div>
    </button>
  );
}

/* ---------- 작업물 섹션 ---------- */
function Works({ projects, onOpen }) {
  const [cat, setCat] = useState("ALL");
  const [q, setQ] = useState("");
  const [tag, setTag] = useState(null);
  const [tagsOpen, setTagsOpen] = useState(false);
  const cats = window.CATEGORIES;
  const TAG_PREVIEW = 8;
  // 사용 빈도순 정렬 — 자주 쓰인 태그가 앞에 오도록
  const allTags = useMemo(() => {
    const count = new Map();
    projects.forEach((p) => (p.tags || []).forEach((t) => count.set(t, (count.get(t) || 0) + 1)));
    return Array.from(count.entries()).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([t]) => t);
  }, [projects]);
  // 접혀 있어도 선택된 태그는 항상 보이게
  const shownTags = useMemo(() => {
    if (tagsOpen) return allTags;
    const head = allTags.slice(0, TAG_PREVIEW);
    return tag && !head.includes(tag) ? [...head, tag] : head;
  }, [allTags, tagsOpen, tag]);
  const filtered = useMemo(() => {
    const query = q.trim().toLowerCase();
    return projects.filter((p) => {
      if (cat !== "ALL" && !(p.cats || []).includes(cat)) return false;
      if (tag && !(p.tags || []).includes(tag)) return false;
      if (!query) return true;
      return [p.title, p.kind, p.summary, p.desc, ...(p.tags || []), ...(p.tools || [])].join(" ").toLowerCase().includes(query);
    });
  }, [projects, cat, tag, q]);

  return (
    <section id="works" className="border-t border-line/60 bg-ink-2/30">
      <div className="mx-auto max-w-7xl px-5 py-16">
        <div className="mb-2 text-[11px] font-bold uppercase tracking-[0.25em] text-accent">◈ Selected Works</div>
        <h2 className="text-3xl font-extrabold tracking-tight text-white sm:text-4xl">게임 사운드 포트폴리오</h2>
        <p className="mt-3 max-w-2xl text-sm text-neutral-400">
          상용 게임 사운드 작업부터 트레일러·컷신 사운드 리디자인, Unreal·Wwise 기반 인터랙티브 오디오까지. 카드를 클릭하면 실제 영상이 재생됩니다.
        </p>

        <div className="mt-6 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
          <div className="flex flex-wrap gap-2">
            {cats.map((c) => (
              <button key={c.key} onClick={() => setCat(c.key)}
                className={"rounded-full border px-3.5 py-1.5 text-xs font-semibold transition " + (cat === c.key ? "chip-active" : "border-line text-neutral-400 hover:border-accent/50 hover:text-white")}>
                {c.label}
              </button>
            ))}
          </div>
          <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="제목, 미들웨어(Wwise, Reaper) 등…"
            className="w-full rounded-full border border-line bg-ink-2 px-4 py-2 text-sm text-neutral-200 outline-none focus:border-accent/60 sm:w-72" />
        </div>

        <div className="mt-3 flex flex-wrap items-center gap-x-3 gap-y-1">
          {shownTags.map((t) => (
            <button key={t} onClick={() => setTag(tag === t ? null : t)} className={"text-xs transition " + (tag === t ? "text-accent" : "text-neutral-500 hover:text-neutral-300")}>#{t.replace(/\s+/g, "")}</button>
          ))}
          {allTags.length > TAG_PREVIEW && (
            <button onClick={() => setTagsOpen((o) => !o)}
              className="text-xs font-semibold text-neutral-400 underline-offset-4 transition hover:text-accent hover:underline">
              {tagsOpen ? "태그 접기" : `태그 더보기 +${allTags.length - TAG_PREVIEW}`}
            </button>
          )}
          {tag && (
            <button onClick={() => setTag(null)} className="text-xs text-neutral-500 transition hover:text-white">× 태그 해제</button>
          )}
        </div>

        <div className="mt-8 grid gap-5 sm:grid-cols-2 lg:grid-cols-3">
          {filtered.map((p) => <WorkCard key={p.id} p={p} onOpen={onOpen} />)}
        </div>
        {filtered.length === 0 && <div className="mt-12 text-center text-sm text-neutral-500">일치하는 작업물이 없습니다.</div>}
      </div>
    </section>
  );
}

/* ---------- 상세 모달 ---------- */
function ProjectModal({ p, onClose }) {
  useEffect(() => {
    const k = (e) => e.key === "Escape" && onClose();
    window.addEventListener("keydown", k); document.body.style.overflow = "hidden";
    return () => { window.removeEventListener("keydown", k); document.body.style.overflow = ""; };
  }, [onClose]);
  if (!p) return null;
  return (
    <div className="modal-backdrop fixed inset-0 z-50 flex items-start justify-center overflow-y-auto p-4 sm:p-8" onClick={onClose}>
      <div className="fade-up w-full max-w-3xl rounded-2xl border border-line bg-ink-2" onClick={(e) => e.stopPropagation()}>
        <div className="relative aspect-video overflow-hidden rounded-t-2xl bg-black">
          <iframe className="h-full w-full" src={ytEmbed(p.yt)} title={p.title} frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />
          <button onClick={onClose} className="absolute right-3 top-3 z-10 rounded-full border border-white/20 bg-black/60 px-3 py-1 text-sm text-white hover:bg-black/80">✕</button>
        </div>
        <div className="p-6">
          <div className="flex flex-wrap items-center gap-2">
            {(p.cats || []).map((c) => (
              <span key={c} className={"rounded border bg-black/40 px-2 py-0.5 text-[10px] font-bold uppercase " + (CAT_STYLE[c] || "text-white border-white/30")}>{c}</span>
            ))}
            <span className="text-[11px] uppercase tracking-wider text-neutral-500">{p.kind} · {p.platform} · {p.year}</span>
          </div>
          <h3 className="mt-2 text-2xl font-extrabold text-white">{p.title}</h3>
          <p className="mt-4 text-[15px] leading-relaxed text-neutral-300">{p.desc}</p>
          <div className="mt-6 grid gap-4 sm:grid-cols-2">
            <div>
              <div className="mb-2 text-[10px] font-bold uppercase tracking-[0.2em] text-neutral-600">사용 툴 · 미들웨어</div>
              <div className="flex flex-wrap gap-1.5">{(p.tools || []).map((t) => <Tag key={t}>{t}</Tag>)}</div>
            </div>
            <div>
              <div className="mb-2 text-[10px] font-bold uppercase tracking-[0.2em] text-neutral-600">태그</div>
              <div className="flex flex-wrap gap-1.5">{(p.tags || []).map((t) => <Tag key={t} className="text-accent border-accent/40">#{t.replace(/\s+/g, "")}</Tag>)}</div>
            </div>
          </div>
          <a href={ytWatch(p.yt)} target="_blank" rel="noreferrer" className="mt-6 inline-block text-sm text-accent hover:underline">유튜브에서 보기 ↗</a>
        </div>
      </div>
    </div>
  );
}

/* ---------- 참여 프로젝트 (접힘) ---------- */
function Participation() {
  const rows = window.PARTICIPATION;
  return (
    <section className="mx-auto max-w-7xl px-5 pb-4">
      <Collapsible title={`사운드 작업 · 현장 참여 이력 (${rows.length}건)`} subtitle="게임 제작 · 공연음향(PA) · 레코딩 · 믹스 — 펼쳐서 전체 보기">
        <div className="divide-y divide-line/60">
          {rows.map((r, i) => (
            <div key={i} className="flex flex-col gap-1 py-3 sm:flex-row sm:items-center sm:gap-4">
              <div className="flex-1 text-sm text-neutral-100">
                {r.url ? <a href={r.url} target="_blank" rel="noreferrer" className="hover:text-accent hover:underline">{r.name} ↗</a> : r.name}
              </div>
              <div className="w-32 shrink-0 text-xs font-semibold text-accent">{r.role}</div>
              <div className="w-28 shrink-0 text-xs text-neutral-500">{r.note}</div>
            </div>
          ))}
        </div>
      </Collapsible>
    </section>
  );
}

/* ---------- 경력 · 학력 (접힘) ---------- */
function Career() {
  return (
    <section id="career" className="mx-auto max-w-7xl px-5 py-16">
      <div className="mb-2 text-[11px] font-bold uppercase tracking-[0.25em] text-accent">◈ Career & Education</div>
      <h2 className="text-3xl font-extrabold tracking-tight text-white sm:text-4xl">경력 · 학력</h2>

      <div className="mt-8 grid gap-8 lg:grid-cols-2">
        <div>
          <h3 className="mb-4 text-sm font-bold uppercase tracking-wider text-neutral-300">경력 · 병역</h3>
          <div className="space-y-4">
            {window.CAREER.map((c, i) => (
              <div key={i} className="relative border-l border-line pl-5">
                <span className="absolute -left-1 top-1.5 h-2 w-2 rounded-full bg-accent" />
                <div className="font-mono text-xs text-neutral-500">{c.period}</div>
                <div className="mt-0.5 text-sm font-bold text-white">{c.org}</div>
                <ul className="mt-1 space-y-0.5">
                  {c.bullets.map((b, j) => <li key={j} className="text-sm text-neutral-400">· {b}</li>)}
                </ul>
              </div>
            ))}
          </div>
        </div>
        <div>
          <h3 className="mb-4 text-sm font-bold uppercase tracking-wider text-neutral-300">학력</h3>
          <div className="space-y-4">
            {window.EDUCATION.map((e, i) => (
              <div key={i} className="relative border-l border-line pl-5">
                <span className="absolute -left-1 top-1.5 h-2 w-2 rounded-full bg-accent" />
                <div className="font-mono text-xs text-neutral-500">{e.period}</div>
                <div className="mt-0.5 text-sm font-bold text-white">{e.org}</div>
                <div className="text-sm text-neutral-400">{e.detail}</div>
              </div>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---------- 연락처 / 푸터 ---------- */
function CopyPill({ value, icon, primary }) {
  const [copied, setCopied] = useState(false);
  const copy = () => {
    const done = () => { setCopied(true); setTimeout(() => setCopied(false), 1500); };
    if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(value).then(done).catch(done);
    else { const t = document.createElement("textarea"); t.value = value; document.body.appendChild(t); t.select(); try { document.execCommand("copy"); } catch (e) {} document.body.removeChild(t); done(); }
  };
  const base = "rounded-full px-6 py-3 text-sm font-semibold transition ";
  const cls = primary
    ? base + "bg-accent text-black font-bold hover:brightness-110"
    : base + "border border-line text-neutral-200 hover:border-accent/60 hover:text-accent";
  return (
    <button onClick={copy} className={cls}>
      {copied ? "✓ 복사되었습니다" : `${icon} ${value}`}
    </button>
  );
}

function Contact({ settings }) {
  return (
    <section id="contact" className="border-t border-line/60 bg-ink-2/40">
      <div className="mx-auto max-w-7xl px-5 py-16 text-center">
        <div className="mb-2 text-[11px] font-bold uppercase tracking-[0.25em] text-accent">◈ Contact</div>
        <h2 className="text-3xl font-extrabold tracking-tight text-white sm:text-4xl">함께 만들 준비가 되어 있습니다</h2>
        <p className="mt-3 text-sm text-neutral-400">게임 사운드 디자이너 포지션 · 협업 · 문의를 환영합니다.</p>
        <div className="mt-8 flex flex-wrap items-center justify-center gap-3">
          <CopyPill value={settings.contactEmail} icon="✉" primary />
          <CopyPill value={settings.contactPhone} icon="☎" />
        </div>
      </div>
      <div className="border-t border-line/40 py-5 text-center text-xs text-neutral-600">
        © {new Date().getFullYear()} {settings.brandKr} ({settings.brandEn}). All rights reserved. · Built with sound & code.
      </div>
    </section>
  );
}

/* ---------- 어드민 ---------- */
const inputCls = "w-full rounded-lg border border-line bg-ink-2 px-3 py-2 text-sm text-white outline-none focus:border-accent/60";
function Field({ label, children }) {
  return <label className="block"><span className="mb-1.5 block text-sm font-semibold text-neutral-300">{label}</span>{children}</label>;
}

/* 비밀번호를 코드에 평문으로 두지 않기 위해 SHA-256 해시로만 비교한다.
   (정적 사이트라 클라이언트 검증이 완벽한 보안은 아니지만, 공개 저장소에
    비밀번호 원문이 노출되는 것은 막아준다.) */
async function sha256Hex(text) {
  const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
  return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("");
}

function Admin({ settings, setSettings, projects, setProjects }) {
  const [authed, setAuthed] = useState(false);
  const [pw, setPw] = useState("");
  const [tab, setTab] = useState("site");
  const [msg, setMsg] = useState("");
  const flash = (m) => { setMsg(m); setTimeout(() => setMsg(""), 1800); };
  const upd = (patch) => setSettings({ ...settings, ...patch });

  const tryLogin = async () => {
    const expected = settings.adminPasswordHash || window.DEFAULT_SETTINGS.adminPasswordHash;
    try {
      if ((await sha256Hex(pw)) === expected) { setAuthed(true); return; }
    } catch (e) { /* crypto.subtle 미지원(비보안 컨텍스트) */ }
    flash("비밀번호가 올바르지 않습니다.");
  };

  if (!authed) {
    return (
      <div className="mx-auto flex min-h-screen max-w-md flex-col justify-center px-6">
        <a href="#/" className="mb-6 text-sm text-neutral-500 hover:text-accent">← 사이트로 돌아가기</a>
        <h1 className="text-2xl font-extrabold text-white">관리자 로그인</h1>
        <input type="password" value={pw} onChange={(e) => setPw(e.target.value)}
          onKeyDown={(e) => e.key === "Enter" && tryLogin()}
          placeholder="비밀번호" className="mt-6 w-full rounded-lg border border-line bg-ink-2 px-4 py-2.5 text-sm text-white outline-none focus:border-accent/60" />
        <button onClick={tryLogin}
          className="mt-3 w-full rounded-lg bg-accent py-2.5 text-sm font-bold text-black hover:brightness-110">로그인</button>
        {msg && <div className="mt-3 text-sm text-red-400">{msg}</div>}
        <div className="mt-4 text-xs text-neutral-600">※ 어드민 수정은 이 브라우저에만 저장됩니다(미리보기용). 모두에게 반영하려면 코드 배포가 필요합니다.</div>
      </div>
    );
  }

  return (
    <div className="mx-auto max-w-4xl px-5 py-10">
      <div className="flex items-center justify-between">
        <h1 className="text-2xl font-extrabold text-white">관리자 대시보드</h1>
        <a href="#/" className="rounded-full border border-line px-3 py-1.5 text-xs text-neutral-300 hover:border-accent/60 hover:text-accent">사이트 보기 →</a>
      </div>
      <div className="mt-6 flex gap-2 border-b border-line">
        {[["site", "사이트 설정"], ["works", "작업물 관리"], ["danger", "초기화"]].map(([k, l]) => (
          <button key={k} onClick={() => setTab(k)} className={"px-4 py-2 text-sm font-semibold " + (tab === k ? "border-b-2 border-accent text-accent" : "text-neutral-500 hover:text-neutral-300")}>{l}</button>
        ))}
      </div>
      {msg && <div className="mt-4 rounded-lg border border-accent/40 bg-accent/10 px-4 py-2 text-sm text-accent">{msg}</div>}

      {tab === "site" && (
        <div className="mt-6 space-y-5">
          <div className="grid gap-4 sm:grid-cols-2">
            <Field label="이름 (한글)"><input className={inputCls} value={settings.brandKr} onChange={(e) => upd({ brandKr: e.target.value })} /></Field>
            <Field label="이름 (영문)"><input className={inputCls} value={settings.brandEn} onChange={(e) => upd({ brandEn: e.target.value })} /></Field>
          </div>
          <Field label="직함 (Role)"><input className={inputCls} value={settings.role} onChange={(e) => upd({ role: e.target.value })} /></Field>
          <Field label="소개글"><textarea rows="3" className={inputCls} value={settings.heroDesc} onChange={(e) => upd({ heroDesc: e.target.value })} /></Field>
          <div className="grid gap-4 sm:grid-cols-2">
            <Field label="상태 라벨"><input className={inputCls} value={settings.statusLabel} onChange={(e) => upd({ statusLabel: e.target.value })} /></Field>
            <Field label="위치 (BASED IN)"><input className={inputCls} value={settings.location} onChange={(e) => upd({ location: e.target.value })} /></Field>
          </div>
          <Field label="상태 문구 (Current Status)"><textarea rows="2" className={inputCls} value={settings.status} onChange={(e) => upd({ status: e.target.value })} /></Field>
          <Field label="유튜브 재생목록 URL"><input className={inputCls} value={settings.playlistUrl || ""} onChange={(e) => upd({ playlistUrl: e.target.value })} /></Field>
          <div className="grid gap-4 sm:grid-cols-2">
            <Field label="이메일"><input className={inputCls} value={settings.contactEmail} onChange={(e) => upd({ contactEmail: e.target.value })} /></Field>
            <Field label="전화번호"><input className={inputCls} value={settings.contactPhone} onChange={(e) => upd({ contactPhone: e.target.value })} /></Field>
          </div>
          <div className="grid gap-4 sm:grid-cols-2">
            <Field label="주력 분야 (쉼표)"><input className={inputCls} value={settings.focusedOn.join(", ")} onChange={(e) => upd({ focusedOn: e.target.value.split(",").map((s) => s.trim()).filter(Boolean) })} /></Field>
            <Field label="주요 툴 (쉼표)"><input className={inputCls} value={settings.tools.join(", ")} onChange={(e) => upd({ tools: e.target.value.split(",").map((s) => s.trim()).filter(Boolean) })} /></Field>
          </div>
          <Field label="파이프라인 (쉼표)"><input className={inputCls} value={settings.pipeline.join(", ")} onChange={(e) => upd({ pipeline: e.target.value.split(",").map((s) => s.trim()).filter(Boolean) })} /></Field>
          <div className="grid gap-4 sm:grid-cols-2">
            <Field label="포인트 컬러"><input type="color" value={settings.accent} onChange={(e) => upd({ accent: e.target.value })} className="h-10 w-20 rounded border border-line bg-ink-2" /></Field>
            <Field label="관리자 비밀번호 변경">
              <input className={inputCls} type="password" placeholder="새 비밀번호 입력 후 Enter"
                onKeyDown={async (e) => {
                  if (e.key !== "Enter") return;
                  const v = e.target.value.trim();
                  if (v.length < 6) { flash("6자 이상으로 입력해 주세요."); return; }
                  upd({ adminPasswordHash: await sha256Hex(v) });
                  e.target.value = ""; flash("비밀번호가 변경되었습니다(이 브라우저 기준).");
                }} />
            </Field>
          </div>
          <button onClick={() => flash("자동 저장되었습니다.")} className="rounded-lg bg-accent px-5 py-2.5 text-sm font-bold text-black hover:brightness-110">저장 확인</button>
        </div>
      )}

      {tab === "works" && <WorksAdmin projects={projects} setProjects={setProjects} flash={flash} />}

      {tab === "danger" && (
        <div className="mt-6">
          <p className="text-sm text-neutral-400">모든 변경을 지우고 기본 데이터로 되돌립니다.</p>
          <button onClick={() => { if (confirm("정말 초기화할까요?")) { setSettings(JSON.parse(JSON.stringify(DEFAULT_SETTINGS))); setProjects(JSON.parse(JSON.stringify(DEFAULT_PROJECTS))); flash("초기화되었습니다."); } }}
            className="mt-4 rounded-lg border border-red-500/50 px-5 py-2.5 text-sm font-semibold text-red-400 hover:bg-red-500/10">기본값으로 초기화</button>
        </div>
      )}
    </div>
  );
}

function WorksAdmin({ projects, setProjects, flash }) {
  const [editing, setEditing] = useState(null);
  const blank = () => ({ id: "p" + Date.now(), title: "", kind: "", platform: "", year: String(new Date().getFullYear()), cats: ["사운드 디자인"], summary: "", desc: "", tags: [], tools: [], yt: "", cover: "linear-gradient(135deg,#1b1e29,#3a1d4a)" });
  const saveP = (p) => { const ex = projects.some((x) => x.id === p.id); setProjects(ex ? projects.map((x) => (x.id === p.id ? p : x)) : [p, ...projects]); setEditing(null); flash("작업물이 저장되었습니다."); };

  if (editing) {
    const p = editing; const set = (patch) => setEditing({ ...p, ...patch });
    return (
      <div className="mt-6 space-y-4">
        <div className="grid gap-4 sm:grid-cols-2">
          <Field label="제목"><input className={inputCls} value={p.title} onChange={(e) => set({ title: e.target.value })} /></Field>
          <Field label="작업 성격 (kind)"><input className={inputCls} value={p.kind} onChange={(e) => set({ kind: e.target.value })} /></Field>
          <Field label="플랫폼"><input className={inputCls} value={p.platform} onChange={(e) => set({ platform: e.target.value })} /></Field>
          <Field label="연도"><input className={inputCls} value={p.year} onChange={(e) => set({ year: e.target.value })} /></Field>
          <Field label="카테고리 (쉼표 · 사운드 디자인/BGM/Foley/Engine/Voice)"><input className={inputCls} value={(p.cats || []).join(", ")} onChange={(e) => set({ cats: e.target.value.split(",").map((s) => s.trim()).filter(Boolean) })} /></Field>
          <Field label="YouTube 영상 ID (예: EV8owgleEKc)"><input className={inputCls} value={p.yt} onChange={(e) => set({ yt: e.target.value })} /></Field>
        </div>
        <Field label="한 줄 요약"><input className={inputCls} value={p.summary} onChange={(e) => set({ summary: e.target.value })} /></Field>
        <Field label="상세 설명"><textarea rows="4" className={inputCls} value={p.desc} onChange={(e) => set({ desc: e.target.value })} /></Field>
        <div className="grid gap-4 sm:grid-cols-2">
          <Field label="사용 툴 (쉼표)"><input className={inputCls} value={p.tools.join(", ")} onChange={(e) => set({ tools: e.target.value.split(",").map((s) => s.trim()).filter(Boolean) })} /></Field>
          <Field label="태그 (쉼표)"><input className={inputCls} value={p.tags.join(", ")} onChange={(e) => set({ tags: e.target.value.split(",").map((s) => s.trim()).filter(Boolean) })} /></Field>
        </div>
        <div className="flex gap-2">
          <button onClick={() => saveP(p)} className="rounded-lg bg-accent px-5 py-2.5 text-sm font-bold text-black hover:brightness-110">저장</button>
          <button onClick={() => setEditing(null)} className="rounded-lg border border-line px-5 py-2.5 text-sm text-neutral-300 hover:text-white">취소</button>
        </div>
      </div>
    );
  }

  const move = (i, dir) => {
    const j = i + dir; if (j < 0 || j >= projects.length) return;
    const a = [...projects]; const t = a[i]; a[i] = a[j]; a[j] = t; setProjects(a);
  };
  return (
    <div className="mt-6">
      <div className="mb-4 flex items-center justify-between">
        <button onClick={() => setEditing(blank())} className="rounded-lg bg-accent px-4 py-2 text-sm font-bold text-black hover:brightness-110">+ 새 작업물 추가</button>
        <span className="text-xs text-neutral-500">▲▼ 로 순서 변경 · 위에 있을수록 먼저 노출</span>
      </div>
      <div className="space-y-2">
        {projects.map((p, i) => (
          <div key={p.id} className="flex items-center justify-between gap-3 rounded-lg border border-line bg-ink-2 px-3 py-3">
            <div className="flex shrink-0 flex-col">
              <button onClick={() => move(i, -1)} disabled={i === 0} className="px-1 text-xs text-neutral-500 hover:text-accent disabled:opacity-20">▲</button>
              <button onClick={() => move(i, 1)} disabled={i === projects.length - 1} className="px-1 text-xs text-neutral-500 hover:text-accent disabled:opacity-20">▼</button>
            </div>
            <div className="min-w-0 flex-1"><div className="truncate text-sm font-semibold text-white">{i + 1}. {p.title || "(제목 없음)"}</div><div className="truncate text-xs text-neutral-500">{(p.cats || []).join(" · ")} · {p.year}</div></div>
            <div className="flex shrink-0 gap-2">
              <button onClick={() => setEditing(p)} className="rounded border border-line px-3 py-1 text-xs text-neutral-300 hover:text-accent">수정</button>
              <button onClick={() => { if (confirm("삭제할까요?")) { setProjects(projects.filter((x) => x.id !== p.id)); flash("삭제되었습니다."); } }} className="rounded border border-red-500/40 px-3 py-1 text-xs text-red-400 hover:bg-red-500/10">삭제</button>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ---------- 라우팅 + 루트 ---------- */
function useHashRoute() {
  const [route, setRoute] = useState(window.location.hash || "#/");
  useEffect(() => { const on = () => setRoute(window.location.hash || "#/"); window.addEventListener("hashchange", on); return () => window.removeEventListener("hashchange", on); }, []);
  return route;
}

function App() {
  const [settings, setS] = useState(() => ({ ...DEFAULT_SETTINGS, ...load(LS_SETTINGS, {}) }));
  const [projects, setP] = useState(() => load(LS_PROJECTS, DEFAULT_PROJECTS));
  const [modal, setModal] = useState(null);
  const route = useHashRoute();
  const setSettings = (s) => { setS(s); save(LS_SETTINGS, s); };
  const setProjects = (p) => { setP(p); save(LS_PROJECTS, p); };
  useEffect(() => { document.documentElement.style.setProperty("--accent", settings.accent); }, [settings.accent]);

  if (route.startsWith("#/admin")) return <Admin settings={settings} setSettings={setSettings} projects={projects} setProjects={setProjects} />;

  return (
    <div>
      <Header settings={settings} />
      <Hero settings={settings} />
      <Stats stats={settings.stats} />
      <About />
      <Works projects={projects} onOpen={setModal} />
      <Participation />
      <Career />
      <Contact settings={settings} />
      {modal && <ProjectModal p={modal} onClose={() => setModal(null)} />}
    </div>
  );
}

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