// ===== Teuanjai Radio — App root (state + time tracking) =====

function App() {
  // ----- session / tracking state -----
  const [booted, setBooted] = useState(false);
  const [session, setSession] = useState(null); // {code, memberName, checkInTime}
  const [totalMs, setTotalMs] = useState(0);
  const [perTrackMs, setPerTrackMs] = useState({});
  const [posByTrack, setPosByTrack] = useState({});
  const [log, setLog] = useState([]);
  const [currentTrackId, setCurrentTrackId] = useState(null);
  const [isPlaying, setIsPlaying] = useState(false);
  const [view, setView] = useState("library");
  const [nowTs, setNowTs] = useState(Date.now());
  const [muted, setMuted] = useState(false);
  const [streamError, setStreamError] = useState(false);
  const [streamLoading, setStreamLoading] = useState(false);
  const audioRef = useRef(null);

  // ----- overlays -----
  const inApp = useMemo(() => detectInApp(), []);
  const [showGuard, setShowGuard] = useState(!!inApp);
  const [showLogout, setShowLogout] = useState(false);

  const lastTick = useRef(0);
  const lastSave = useRef(0);
  const lastApiSync = useRef(0);
  const totalMsRef = useRef(0);
  const joinCountRef = useRef(0);
  useEffect(() => { totalMsRef.current = totalMs; }, [totalMs]);
  useEffect(() => { joinCountRef.current = log.filter((e) => e.type === "play").length; }, [log]);

  // restore on mount
  useEffect(() => {
    const s = loadState();
    if (s && s.session) {
      setSession(s.session);
      setTotalMs(s.totalMs || 0);
      setPerTrackMs(s.perTrackMs || {});
      setPosByTrack(s.posByTrack || {});
      setLog(s.log || []);
      setCurrentTrackId(s.currentTrackId || null);
    }
    setBooted(true);
  }, []);

  // persist helper
  const persist = (extra = {}) => {
    const snap = {
      session, totalMs, perTrackMs, posByTrack, log, currentTrackId, ...extra,
    };
    saveState(snap);
  };

  // ----- time-tracking loop -----
  useEffect(() => {
    if (!session) return;
    lastTick.current = Date.now();
    const id = setInterval(() => {
      const now = Date.now();
      const dt = now - lastTick.current;
      lastTick.current = now;
      setNowTs(now);

      if (isPlaying && currentTrackId) {
        const tr = trackById(currentTrackId);
        setTotalMs((v) => v + dt);
        setPerTrackMs((m) => ({ ...m, [currentTrackId]: (m[currentTrackId] || 0) + dt }));
        setPosByTrack((p) => {
          const cur = (p[currentTrackId] || 0) + dt;
          // Live สตรีม: เวลาเดินขึ้นเรื่อยๆ ไม่มีจุดจบ ไม่ข้ามคลิป
          if (!tr.live) {
            const durMs = tr.sec * 1000;
            if (cur >= durMs) {
              const idx = TRACKS.findIndex((t) => t.id === currentTrackId);
              const nextId = TRACKS[(idx + 1) % TRACKS.length].id;
              queueMicrotask(() => {
                addLog("pause", currentTrackId);
                setCurrentTrackId(nextId);
                addLog("play", nextId);
              });
              return { ...p, [currentTrackId]: durMs, [nextId]: 0 };
            }
          }
          return { ...p, [currentTrackId]: cur };
        });
      }

      if (now - lastSave.current > 1400) { lastSave.current = now; persist(); }

      // throttled sync to backend (~every 10s)
      if (window.Api && session && session.id && now - lastApiSync.current > 10000) {
        lastApiSync.current = now;
        Api.updateSession(session.id, {
          total_listen_ms: totalMsRef.current,
          join_count: joinCountRef.current,
        });
      }
    }, 500);
    return () => clearInterval(id);
  }, [session, isPlaying, currentTrackId]);

  // persist on important state changes
  useEffect(() => { if (session) persist(); }, [currentTrackId, log.length, session]);

  // save on tab hide / unload
  useEffect(() => {
    const h = () => persist();
    window.addEventListener("visibilitychange", h);
    window.addEventListener("pagehide", h);
    return () => { window.removeEventListener("visibilitychange", h); window.removeEventListener("pagehide", h); };
  });

  function addLog(type, trackId) {
    const now = Date.now();
    setLog((l) => [...l, { type, trackId: trackId || null, time: now }]);
    if (window.Api && session && session.id) {
      Api.logEvent({ session_id: session.id, type, track_id: trackId || null, at: now });
    }
  }

  // ----- audio: follow play state -----
  useEffect(() => {
    const tr = currentTrackId ? trackById(currentTrackId) : null;
    const useStream = tr && tr.src;
    if (isPlaying && tr) {
      if (useStream) {
        if (window.AudioEngine) AudioEngine.stop();
        const a = audioRef.current;
        if (a) {
          if (a.src !== tr.src) a.src = tr.src;
          a.muted = muted;
          setStreamError(false);
          setStreamLoading(true);
          const p = a.play();
          if (p && p.catch) p.catch(() => { setStreamError(true); setStreamLoading(false); });
        }
      } else if (window.AudioEngine) {
        AudioEngine.play(currentTrackId);
      }
    } else {
      if (audioRef.current) { try { audioRef.current.pause(); } catch (e) {} }
      if (window.AudioEngine) AudioEngine.stop();
      setStreamLoading(false);
    }
  }, [isPlaying, currentTrackId]);

  useEffect(() => {
    if (audioRef.current) audioRef.current.muted = muted;
    if (window.AudioEngine) AudioEngine.setMuted(muted);
  }, [muted]);

  // ----- actions -----
  const handleCheckIn = (code, memberName) => {
    const id = (window.crypto && crypto.randomUUID)
      ? crypto.randomUUID()
      : "s" + Date.now().toString(36) + Math.random().toString(36).slice(2, 10);
    const sess = { id, code, memberName, checkInTime: Date.now() };
    setSession(sess);
    setLog([{ type: "checkin", trackId: null, time: sess.checkInTime }]);
    setTotalMs(0); setPerTrackMs({}); setPosByTrack({}); setCurrentTrackId(null); setIsPlaying(false);
    setView("library");
    saveState({ session: sess, totalMs: 0, perTrackMs: {}, posByTrack: {}, log: [{ type: "checkin", trackId: null, time: sess.checkInTime }], currentTrackId: null });
    if (window.Api) {
      Api.startSession({ id, branch_code: code, member_name: memberName });
      Api.logEvent({ session_id: id, type: "checkin", at: sess.checkInTime });
    }
  };

  const selectTrack = (id) => {
    if (id === currentTrackId) {
      setView("now");
      if (!isPlaying) togglePlay();
      return;
    }
    setCurrentTrackId(id);
    setPosByTrack((p) => ({ ...p, [id]: p[id] && p[id] < trackById(id).sec * 1000 ? p[id] : 0 }));
    setIsPlaying(true);
    addLog("play", id);
    setView("now");
  };

  const togglePlay = () => {
    if (!currentTrackId) { if (TRACKS[0]) selectTrack(TRACKS[0].id); return; }
    setIsPlaying((p) => {
      const np = !p;
      addLog(np ? "play" : "pause", currentTrackId);
      return np;
    });
  };

  const step = (dir) => {
    const idx = TRACKS.findIndex((t) => t.id === currentTrackId);
    const nid = TRACKS[(idx + dir + TRACKS.length) % TRACKS.length].id;
    if (isPlaying) addLog("pause", currentTrackId);
    setCurrentTrackId(nid);
    setPosByTrack((p) => ({ ...p, [nid]: 0 }));
    setIsPlaying(true);
    addLog("play", nid);
  };

  const confirmLogout = () => {
    if (isPlaying) { setIsPlaying(false); addLog("pause", currentTrackId); }
    addLog("checkout", null);
    setShowLogout(false);
    if (window.Api && session && session.id) {
      Api.updateSession(session.id, {
        total_listen_ms: totalMs,
        join_count: log.filter((e) => e.type === "play").length,
        check_out: Date.now(),
      });
      Api.flushQueue();
    }
    setTimeout(() => {
      clearState();
      setSession(null); setTotalMs(0); setPerTrackMs({}); setPosByTrack({}); setLog([]);
      setCurrentTrackId(null); setIsPlaying(false); setView("library");
    }, 120);
  };

  // ----- render -----
  if (!booted) return null;

  if (!session) {
    return (
      <React.Fragment>
        <LoginScreen onCheckIn={handleCheckIn} />
        {showGuard && <BrowserGuard appName={inApp} onDismiss={() => setShowGuard(false)} />}
      </React.Fragment>
    );
  }

  const curTrack = currentTrackId ? trackById(currentTrackId) : null;
  const posMs = curTrack ? (posByTrack[currentTrackId] || 0) : 0;
  const isLive = !!(curTrack && curTrack.live);
  const progress = curTrack && !isLive ? posMs / (curTrack.sec * 1000) : 0;
  const sessionMs = nowTs - session.checkInTime;
  // จำนวนครั้งที่เข้าฟังสตรีม (นับ event "play")
  const joinCount = log.filter((e) => e.type === "play").length;
  const hasJoined = joinCount > 0;

  return (
    <React.Fragment>
      <audio ref={audioRef} preload="none" playsInline
        onPlaying={() => { setStreamLoading(false); setStreamError(false); }}
        onWaiting={() => setStreamLoading(true)}
        onError={() => { setStreamError(true); setStreamLoading(false); }}
        onStalled={() => setStreamError(true)}
        style={{ display: "none" }} />
      {view === "now" ? (
        <NowPlayingView
          track={curTrack} progress={progress} posMs={posMs} isPlaying={isPlaying} live={isLive}
          accMs={curTrack ? (perTrackMs[currentTrackId] || 0) : 0}
          streamError={streamError} streamLoading={streamLoading}
          onToggle={togglePlay} onNext={() => step(1)} onPrev={() => step(-1)}
          onClose={() => setView("library")}
          muted={muted} onToggleMute={() => setMuted((m) => !m)}
        />
      ) : (
        <div className="screen">
          <TopBar memberName={session.memberName} totalMs={totalMs} onLogout={() => setShowLogout(true)}
            subtitle={view === "history" ? "ประวัติการเข้าร่วม" : "สวัสดี"} />
          {view === "library" && (
            <LibraryView tracks={TRACKS} perTrackMs={perTrackMs} currentTrackId={currentTrackId}
              isPlaying={isPlaying} totalMs={totalMs} onSelect={selectTrack}
              greeting={greetingThai(nowTs)} memberName={session.memberName}
              hasJoined={hasJoined} />
          )}
          {view === "history" && (
            <HistoryView session={session} totalMs={totalMs} perTrackMs={perTrackMs} log={log} sessionMs={sessionMs} joinCount={joinCount} />
          )}
          {curTrack && (
            <MiniPlayer track={curTrack} progress={progress} isPlaying={isPlaying} live={isLive}
              onToggle={togglePlay} onExpand={() => setView("now")} />
          )}
          <BottomNav active={view} onNav={setView} />
        </div>
      )}

      {showLogout && (
        <LogoutSummary session={session} totalMs={totalMs} sessionMs={sessionMs} perTrackMs={perTrackMs}
          onConfirm={confirmLogout} onCancel={() => setShowLogout(false)} />
      )}
    </React.Fragment>
  );
}

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