/* ==========================================================
   CheerWall — 응원 메시지 작성 + 미니 리스트 + 롤링 스트립
   ========================================================== */

const MAX_NAME = 40;
const MAX_MESSAGE = 300;
/** 롤링 스트립: 좋아요 상위 N개만 */
const ROLLING_TOP_N = 10;
/** 우측 미니 리스트: 최신 글 N개 */
const MINI_RECENT_N = 4;

/* ── 좋아요 헬퍼 ─────────────────────────────────────── */
// 연속 클릭 방지용 모듈 레벨 쿨다운 Set (컴포넌트 재마운트 무관하게 유지)
const likeInProgress = new Set();
const LIKE_COOLDOWN_MS = 8000; // 8초 쿨다운

function getLikedSet() {
  try { return new Set(JSON.parse(localStorage.getItem("ck_liked") || "[]")); }
  catch { return new Set(); }
}
function persistLiked(id) {
  try {
    const arr = JSON.parse(localStorage.getItem("ck_liked") || "[]");
    localStorage.setItem("ck_liked", JSON.stringify([...new Set([...arr, id])]));
  } catch {}
}
function removePersisted(id) {
  try {
    const arr = JSON.parse(localStorage.getItem("ck_liked") || "[]");
    localStorage.setItem("ck_liked", JSON.stringify(arr.filter((x) => x !== id)));
  } catch {}
}

function formatRelative(dateStr, rel) {
  try {
    const t = new Date(dateStr).getTime();
    if (!Number.isFinite(t)) return "";
    const diff = Math.max(0, Date.now() - t);
    const m = Math.floor(diff / 60000);
    if (m < 1) return rel.now;
    if (m < 60) return rel.minutes(m);
    const h = Math.floor(m / 60);
    if (h < 24) return rel.hours(h);
    return rel.days(Math.floor(h / 24));
  } catch (_) { return ""; }
}

const AVATAR_PALETTE = [
  "#1b3d8f","#c8102e","#19c28d","#ff9f1c","#6f4ec2",
  "#2e86ab","#e07a5f","#3d5a80","#52b788","#ef476f",
];
function avatarColor(seed) {
  let h = 0;
  for (let i = 0; i < (seed||"").length; i++) h = (h*31 + seed.charCodeAt(i)) >>> 0;
  return AVATAR_PALETTE[h % AVATAR_PALETTE.length];
}
function initial(name) {
  const s = (name||"").trim();
  if (!s) return "·";
  return Array.from(s)[0].toUpperCase();
}

/* ── 응원 작성 폼 ─────────────────────────────────────── */
function CheerForm({ onPosted }) {
  const { t, lang } = useApp();
  const L = t.cheer.form;
  const [name, setName] = React.useState("");
  const [message, setMessage] = React.useState("");
  const [state, setState] = React.useState("idle");
  const [errorMsg, setErrorMsg] = React.useState("");

  const submit = async (e) => {
    e.preventDefault();
    const n = name.trim(), m = message.trim();
    if (!n || !m)                                   { setErrorMsg(L.errorRequired); setState("error"); return; }
    if (n.length > MAX_NAME || m.length > MAX_MESSAGE) { setErrorMsg(L.errorTooLong);  setState("error"); return; }
    if (/(https?:\/\/|www\.)/i.test(n+" "+m))      { setErrorMsg(L.errorLinks);    setState("error"); return; }
    setState("sending"); setErrorMsg("");
    try {
      const res = await fetch("/api/cheers", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name: n, message: m, lang }),
      });
      if (!res.ok) {
        const j = await res.json().catch(()=>({}));
        setErrorMsg(j.error || L.errorGeneric); setState("error"); return;
      }
      const j = await res.json();
      setState("ok"); setName(""); setMessage("");
      if (typeof onPosted === "function" && j.item) onPosted(j.item);
      setTimeout(() => setState("idle"), 2200);
    } catch (_) { setErrorMsg(L.errorGeneric); setState("error"); }
  };

  return (
    <form className="cheer-form" onSubmit={submit} noValidate>
      <div className="cheer-row">
        <label className="cheer-label" htmlFor="cheer-name">{L.nameLabel}</label>
        <input
          id="cheer-name" type="text" className="cheer-input"
          placeholder={L.namePh} value={name} maxLength={MAX_NAME}
          onChange={(e) => setName(e.target.value)} autoComplete="off"
        />
      </div>
      <div className="cheer-row">
        <div className="cheer-label-row">
          <label className="cheer-label" htmlFor="cheer-msg">{L.messageLabel}</label>
          <span className="cheer-counter" aria-hidden="true">{L.counter(message.length, MAX_MESSAGE)}</span>
        </div>
        <textarea
          id="cheer-msg" className="cheer-textarea"
          placeholder={L.messagePh} value={message} maxLength={MAX_MESSAGE}
          onChange={(e) => setMessage(e.target.value)} rows={3}
        />
      </div>
      <div className="cheer-footer">
        <div className="cheer-privacy">{L.privacy}</div>
        <button
          type="submit"
          className={`btn-primary ${state==="ok" ? "is-ok" : ""}`}
          disabled={state==="sending"}
        >
          {state==="sending" ? L.submitting : state==="ok" ? L.submitted : L.submit}
        </button>
      </div>
      {state==="error" && errorMsg
        ? <div className="cheer-error" role="alert">{errorMsg}</div>
        : null}
    </form>
  );
}

/* ── 공통 좋아요 버튼 ─────────────────────────────────── */
function CheerLikeButton({ item, likeState, onLike, ariaLabel, compact }) {
  const liked = likeState?.liked ?? false;
  const count = likeState?.count ?? (item.like_count || 0);
  const [burst, setBurst] = React.useState(false);

  const handleLike = () => {
    if (liked || likeInProgress.has(item.id)) return;
    setBurst(true);
    setTimeout(() => setBurst(false), 500);
    onLike(item.id, item.like_count || 0);
  };

  const iconSize = compact ? 11 : 13;

  return (
    <button
      type="button"
      className={`cheer-like-btn${compact ? " cheer-like-btn--compact" : ""}${liked ? " is-liked" : ""}${burst ? " is-burst" : ""}`}
      onClick={handleLike}
      disabled={liked}
      aria-pressed={liked}
      aria-label={ariaLabel}
    >
      <svg width={iconSize} height={iconSize} viewBox="0 0 24 24" aria-hidden="true"
        fill={liked ? "currentColor" : "none"}
        stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
        <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
      </svg>
      {count > 0 && <span className="cheer-like-count">{count}</span>}
    </button>
  );
}

/* ── 미니 카드 리스트 (우측 컬럼) — 최신순 + 좋아요 ─────── */
function CheerMiniList({ items, t, likeMap, onLike }) {
  const rel = t.cheer.wall.relative;
  const likeLabel = t.cheer.wall.likeLabel || "Like";
  return (
    <div className="cheer-mini-list">
      {items.map((item, i) => {
        const bg = avatarColor(item.name);
        return (
          <div key={item.id || i} className="cheer-mini-item">
            <div className="cheer-mini-avatar" style={{ background: bg }} aria-hidden="true">
              {initial(item.name)}
            </div>
            <div className="cheer-mini-body">
              <div className="cheer-mini-top">
                <div className="cheer-mini-header">
                  <span className="cheer-mini-name">{item.name}</span>
                  <span className="cheer-mini-date">{formatRelative(item.created_at, rel)}</span>
                </div>
                <CheerLikeButton
                  item={item}
                  likeState={likeMap[item.id]}
                  onLike={onLike}
                  ariaLabel={likeLabel}
                  compact
                />
              </div>
              <p className="cheer-mini-msg">{item.message}</p>
            </div>
          </div>
        );
      })}
    </div>
  );
}

/* ── 롤링 캐러셀용 카드 ───────────────────────────────── */
function CheerCard({ item, t, likeState, onLike }) {
  const rel = t.cheer.wall.relative;
  const bg = avatarColor(item.name);
  const likeLabel = t.cheer.wall.likeLabel || "Like";

  return (
    <article className="cheer-card" aria-label={item.name}>
      <div className="cheer-card-head">
        <div className="cheer-avatar" style={{ background: bg }} aria-hidden="true">{initial(item.name)}</div>
        <div className="cheer-meta">
          <div className="cheer-name">{item.name}</div>
          <div className="cheer-date">{formatRelative(item.created_at, rel)}</div>
        </div>
        <div className="cheer-card-like">
          <CheerLikeButton
            item={item}
            likeState={likeState}
            onLike={onLike}
            ariaLabel={likeLabel}
            compact
          />
        </div>
      </div>
      <p className="cheer-message">{item.message}</p>
    </article>
  );
}

/* ── 메인 CheerWall ───────────────────────────────────── */
function CheerWall() {
  const { t } = useApp();
  const L = t.cheer.wall;
  const [items, setItems] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [paused, setPaused] = React.useState(false);
  // { [id]: { count: number, liked: boolean } }
  const [likeMap, setLikeMap] = React.useState({});
  const trackRef = React.useRef(null);
  const rafRef = React.useRef(0);
  const lastTsRef = React.useRef(0);

  const load = React.useCallback(async () => {
    try {
      const res = await fetch("/api/cheers?limit=60", { cache: "no-store" });
      const j = await res.json();
      setItems(Array.isArray(j.items) ? j.items : []);
    } catch (_) { setItems([]); }
    finally { setLoading(false); }
  }, []);

  React.useEffect(() => { load(); }, [load]);

  // 로드 후 localStorage 반영
  React.useEffect(() => {
    if (!items.length) return;
    const liked = getLikedSet();
    if (!liked.size) return;
    setLikeMap((prev) => {
      const next = { ...prev };
      items.forEach((item) => {
        if (liked.has(item.id)) {
          next[item.id] = { count: item.like_count ?? 0, liked: true };
        }
      });
      return next;
    });
  }, [items]);

  const onPosted = (item) => setItems((prev) => [item, ...prev]);

  /** 좋아요 수(로컬 likeMap 반영) 내림차순, 동점이면 최신순 — 롤링 상위 N 선별용 */
  const sortedByLikes = React.useMemo(() => {
    if (!items.length) return [];
    const eff = (it) => likeMap[it.id]?.count ?? it.like_count ?? 0;
    return [...items].sort((a, b) => {
      const ca = eff(a);
      const cb = eff(b);
      if (cb !== ca) return cb - ca;
      const ta = new Date(a.created_at).getTime();
      const tb = new Date(b.created_at).getTime();
      return tb - ta;
    });
  }, [items, likeMap]);

  /** 롤링: 좋아요 Top N만 */
  const rollingTopItems = React.useMemo(
    () => sortedByLikes.slice(0, ROLLING_TOP_N),
    [sortedByLikes]
  );

  /** 미니 리스트: 최신 글 순(작성 시각 내림차순) */
  const recentMiniItems = React.useMemo(() => {
    if (!items.length) return [];
    return [...items]
      .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
      .slice(0, MINI_RECENT_N);
  }, [items]);

  const handleLike = React.useCallback(async (id, baseCount) => {
    // 이중 방어: 쿨다운 중이거나 이미 좋아요
    if (likeInProgress.has(id)) return;
    const liked = getLikedSet();
    if (liked.has(id)) return;

    likeInProgress.add(id);

    // 낙관적 업데이트
    setLikeMap((prev) => ({
      ...prev,
      [id]: { count: (prev[id]?.count ?? baseCount) + 1, liked: true },
    }));
    persistLiked(id);

    try {
      const res = await fetch("/api/cheers", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ id }),
      });
      if (!res.ok) throw new Error("api error");
      const j = await res.json();
      // 서버 값으로 동기화
      setLikeMap((prev) => ({
        ...prev,
        [id]: { count: j.like_count ?? (prev[id]?.count ?? baseCount + 1), liked: true },
      }));
    } catch {
      // 롤백
      removePersisted(id);
      setLikeMap((prev) => ({
        ...prev,
        [id]: { count: Math.max(0, (prev[id]?.count ?? baseCount + 1) - 1), liked: false },
      }));
    } finally {
      // 쿨다운 해제 (8초)
      setTimeout(() => likeInProgress.delete(id), LIKE_COOLDOWN_MS);
    }
  }, []);

  const loopItems = React.useMemo(() => {
    if (!rollingTopItems.length) return [];
    return rollingTopItems.length < 6
      ? [...rollingTopItems, ...rollingTopItems, ...rollingTopItems]
      : [...rollingTopItems, ...rollingTopItems];
  }, [rollingTopItems]);

  React.useEffect(() => {
    const track = trackRef.current;
    if (!track || !rollingTopItems.length || paused) { cancelAnimationFrame(rafRef.current); return; }
    let offset = track.scrollLeft;
    const PX_PER_SEC = 28;
    const step = (ts) => {
      if (!lastTsRef.current) lastTsRef.current = ts;
      const dt = (ts - lastTsRef.current) / 1000;
      lastTsRef.current = ts;
      offset += PX_PER_SEC * dt;
      const half = track.scrollWidth / 2;
      if (half > 0 && offset >= half) offset -= half;
      track.scrollLeft = offset;
      rafRef.current = requestAnimationFrame(step);
    };
    rafRef.current = requestAnimationFrame(step);
    return () => { cancelAnimationFrame(rafRef.current); lastTsRef.current = 0; };
  }, [rollingTopItems, paused]);

  return (
    <section className="cheerwall" id="cheer">
      <div className="container">

        {/* ── 섹션 헤더: 좌/우 2열 ───────────────────────── */}
        <div className="cheer-section-head reveal">
          <div className="cheer-section-title-group">
            <div className="eyebrow" style={{ marginBottom: "10px" }}>{t.cheer.eyebrow}</div>
            <h2 className="h-section" style={{ whiteSpace: "pre-line" }}>{t.cheer.title}</h2>
          </div>
          <p className="cheer-section-lede">{t.cheer.lede}</p>
        </div>

        {/* ── 2컬럼: 폼 | 미니 리스트 ───────────────────── */}
        <div className="cheer-layout">

          {/* 왼쪽: 폼 */}
          <div className="cheer-form-wrap reveal delay-1" aria-label={t.a11y?.cheerFormSection}>
            <CheerForm onPosted={onPosted} />
          </div>

          {/* 오른쪽: 미니 리스트 */}
          <div className="cheer-wall-wrap reveal delay-2" aria-label={t.a11y?.cheerWallSection}>
            <div className="cheer-wall-head">
              <div className="cheer-wall-title">{L.title}</div>
              <div className="cheer-wall-meta">
                <span className="cheer-wall-count">{L.count(items.length)}</span>
                {rollingTopItems.length > 1 && (
                  <button
                    type="button" className="cheer-pause"
                    onClick={() => setPaused((p) => !p)} aria-pressed={paused}
                  >
                    {paused ? L.play : L.pause}
                  </button>
                )}
              </div>
            </div>

            {loading ? (
              <div className="cheer-placeholder">{L.loading}</div>
            ) : items.length === 0 ? (
              <div className="cheer-placeholder">{L.empty}</div>
            ) : (
              <CheerMiniList items={recentMiniItems} t={t} likeMap={likeMap} onLike={handleLike} />
            )}
          </div>
        </div>

        {/* ── 전체 너비 롤링 스트립 ───────────────────────── */}
        {!loading && rollingTopItems.length > 0 && (
          <div
            className={`cheer-rolling cheer-rolling-fullwidth ${paused ? "is-paused" : ""}`}
            onMouseEnter={() => setPaused(true)}
            onMouseLeave={() => setPaused(false)}
            onTouchStart={() => setPaused(true)}
            onTouchEnd={() => setPaused(false)}
          >
            <div className="cheer-rolling-fade" aria-hidden="true" />
            <div className="cheer-track" ref={trackRef}>
              {loopItems.map((it, i) => (
                <CheerCard
                  key={`${it.id}-${i}`}
                  item={it}
                  t={t}
                  likeState={likeMap[it.id]}
                  onLike={handleLike}
                />
              ))}
            </div>
          </div>
        )}

        <div className="share-hashtag">
          <b>{t.cheer.hashtag}</b>
        </div>
      </div>
    </section>
  );
}

window.CheerWall = CheerWall;
