/* FURY FIST — app.jsx
   React shell: login, title, HUD, end screen, leaderboard.
   Auth via Cloudflare KV/D1 API. Local fallback for guests.
*/
const { useState, useEffect, useRef, useCallback } = React;
const E = window.FuryEngine;

// ─── Auth helpers ──────────────────────────────────────────────────────────────
const API = '/api';

async function apiPost(path, body, token) {
  const headers = { 'Content-Type': 'application/json' };
  if (token) headers['Authorization'] = `Bearer ${token}`;
  try {
    const r = await fetch(API + path, { method: 'POST', headers, body: JSON.stringify(body) });
    return r.json();
  } catch { return { error: 'Network error' }; }
}

async function apiGet(path, token) {
  const headers = {};
  if (token) headers['Authorization'] = `Bearer ${token}`;
  try {
    const r = await fetch(API + path, { headers });
    return r.json();
  } catch { return { error: 'Network error' }; }
}

function getToken() { try { return localStorage.getItem('ff_token'); } catch { return null; } }
function getUser()  { try { return localStorage.getItem('ff_user');  } catch { return null; } }
function saveAuth(token, username) {
  try {
    localStorage.setItem('ff_token', token);
    localStorage.setItem('ff_user', username);
  } catch {}
}
function clearAuth() {
  try { localStorage.removeItem('ff_token'); localStorage.removeItem('ff_user'); } catch {}
}

// Local fallback scores (guests)
function loadLocalScores() {
  try { return JSON.parse(localStorage.getItem('ff_local_scores') || '[]'); } catch { return []; }
}
function saveLocalScore(entry) {
  const s = loadLocalScores();
  const next = [...s, entry].sort((a,b) => b.score - a.score).slice(0, 50);
  try { localStorage.setItem('ff_local_scores', JSON.stringify(next)); } catch {}
}

// ─── Input hook ───────────────────────────────────────────────────────────────
function useInput() {
  const stateRef = useRef({
    left:false, right:false, jump:false, punch:false, kick:false, sweep:false,
    block:false, duck:false,
  });
  const onStartRef = useRef(null);

  useEffect(() => {
    const down = e => {
      const k = e.key.toLowerCase();
      const s = stateRef.current;
      if (k === 'arrowleft')  s.left  = true;
      if (k === 'arrowright') s.right = true;
      if (k === 'arrowup' || k === 'w') s.jump = true;
      if (k === 'arrowdown' || k === 's') { s.duck = true; s.block = true; }
      if (k === 'a') s.punch = true;
      if (k === 'z') s.kick  = true;
      if (k === 'x') s.sweep = true;
      if (k === 'enter') { if (onStartRef.current) onStartRef.current(); }
      if (['arrowup','arrowdown','arrowleft','arrowright',' '].includes(k)) e.preventDefault();
    };
    const up = e => {
      const k = e.key.toLowerCase();
      const s = stateRef.current;
      if (k === 'arrowleft')  s.left  = false;
      if (k === 'arrowright') s.right = false;
      if (k === 'arrowup' || k === 'w') s.jump = false;
      if (k === 'arrowdown' || k === 's') { s.duck = false; s.block = false; }
      if (k === 'a') s.punch = false;
      if (k === 'z') s.kick  = false;
      if (k === 'x') s.sweep = false;
    };
    window.addEventListener('keydown', down);
    window.addEventListener('keyup', up);
    return () => { window.removeEventListener('keydown', down); window.removeEventListener('keyup', up); };
  }, []);

  return { stateRef, onStartRef };
}

// ─── Game loop ─────────────────────────────────────────────────────────────────
function useGameLoop(canvasRef, gameRef, inputRef, onPhaseChange) {
  useEffect(() => {
    let raf;
    let last = performance.now();

    const loop = now => {
      const dt = Math.min(0.05, (now - last) / 1000);
      last = now;
      const game = gameRef.current;

      if (game && (game.phase === 'fighting')) {
        const inp = inputRef.current;
        // Edge-trigger punch/kick/sweep (single frame)
        const frameInput = {
          left:  inp.left,
          right: inp.right,
          jump:  inp.jump && game.player.onGround,  // detect rising edge via onGround
          punch: inp.punch,
          kick:  inp.kick,
          sweep: inp.sweep,
          block: inp.block,
          duck:  inp.duck,
        };
        // After consuming jump, suppress until released
        if (frameInput.jump) inp.jump = false;

        E.tick(game, dt, frameInput);

        if (game.phase !== 'fighting') {
          onPhaseChange(game.phase);
        }
      }

      const ctx = canvasRef.current?.getContext('2d');
      if (ctx && game) {
        E.render(game, ctx);
      }

      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, []);
}

// ─── Login Screen ──────────────────────────────────────────────────────────────
function LoginScreen({ onLogin, onGuest }) {
  const [mode, setMode] = useState('login'); // login | register
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');
  const [loading, setLoading] = useState(false);

  const submit = async () => {
    if (!username.trim() || !password.trim()) {
      setError('ENTER USERNAME AND PASSWORD');
      return;
    }
    setLoading(true);
    setError('');
    const path = mode === 'login' ? '/auth/login' : '/auth/register';
    const res = await apiPost(path, { username: username.trim().toUpperCase(), password });
    setLoading(false);
    if (res.error) {
      setError(res.error.toUpperCase());
    } else {
      saveAuth(res.token, res.username);
      onLogin(res.username, res.token);
    }
  };

  return (
    <div className="login-screen">
      <div className="login-box">
        <div className="title-mark" style={{fontSize:'clamp(30px,6vw,72px)'}}>FURY FIST</div>
        <div className="title-sub">RETRO NEON BRAWLER</div>

        <div className="login-tabs">
          <button className={mode === 'login' ? 'active' : ''} onClick={() => { setMode('login'); setError(''); }}>
            LOGIN
          </button>
          <button className={mode === 'register' ? 'active' : ''} onClick={() => { setMode('register'); setError(''); }}>
            REGISTER
          </button>
        </div>

        <div className="login-fields">
          <input
            className="login-input"
            type="text"
            placeholder="USERNAME"
            value={username}
            maxLength={16}
            onChange={e => setUsername(e.target.value.toUpperCase())}
            onKeyDown={e => e.key === 'Enter' && submit()}
            autoFocus
          />
          <input
            className="login-input"
            type="password"
            placeholder="PASSWORD"
            value={password}
            maxLength={64}
            onChange={e => setPassword(e.target.value)}
            onKeyDown={e => e.key === 'Enter' && submit()}
          />
        </div>

        {error && <div className="login-error">{error}</div>}

        <div className="login-buttons">
          <button className="btn-hot" onClick={submit} disabled={loading}>
            {loading ? 'CONNECTING...' : (mode === 'login' ? '► ENTER' : '► CREATE')}
          </button>
          <button className="btn-cool" onClick={onGuest}>
            PLAY AS GUEST
          </button>
        </div>

        <div className="login-hint">
          GUEST SCORES ARE STORED LOCALLY ONLY
        </div>
      </div>
    </div>
  );
}

// ─── Title Screen ──────────────────────────────────────────────────────────────
function TitleScreen({ username, onStart, onLeaderboard, onLogout, difficulty, setDifficulty }) {
  return (
    <div className="title-screen">
      <div className="title-mark">FURY FIST</div>
      <div className="title-sub">A RETRO NEON BRAWLER</div>
      <div className="title-meta">
        BY <b>RISINGBOB</b> ✦ UMEÅ, SWEDEN ✦ MMXXVI
      </div>

      {username && (
        <div className="title-user">
          LOGGED IN AS <span style={{color:'var(--gold)'}}>{username}</span>
        </div>
      )}

      <div className="press-start" onClick={onStart}>
        PRESS ENTER TO FIGHT
      </div>

      <div className="title-buttons">
        <button onClick={onStart}>► START GAME</button>
        <button className="hot" onClick={onLeaderboard}>✦ HALL OF FAME</button>
        {username && <button onClick={onLogout}>⇒ LOGOUT</button>}
      </div>

      <div className="diff-select">
        {['EASY','NORMAL','HARD','FURY'].map((d, i) => (
          <button
            key={d}
            className={difficulty === i ? 'active' : ''}
            onClick={() => setDifficulty(i)}
          >{d}</button>
        ))}
      </div>

      <div className="controls-box">
        <table><tbody>
          <tr><td className="key">← →</td><td>WALK</td></tr>
          <tr><td className="key">↑ / W</td><td>JUMP</td></tr>
          <tr><td className="key">↓ / S</td><td>BLOCK</td></tr>
          <tr><td className="key">A</td><td>PUNCH</td></tr>
          <tr><td className="key">Z</td><td>KICK</td></tr>
          <tr><td className="key">X</td><td>SWEEP</td></tr>
          <tr><td className="key">↑ + Z</td><td>FLYING KICK</td></tr>
        </tbody></table>
      </div>

      <div className="credit">© RISINGBOB ✦ UMEÅ ✦ SWEDEN</div>
    </div>
  );
}

// ─── HUD ──────────────────────────────────────────────────────────────────────
function Hud({ game }) {
  const p = game.player;
  const hpPct = (p.hp / p.maxHp) * 100;
  const stamPct = (p.stam / p.maxStam) * 100;
  const stage = E.STAGES[game.stageIdx];
  const enemies = game.enemies.filter(e => !e.dead);
  const enemyCount = enemies.length;

  return (
    <div className="hud">
      <div className="panel left">
        <div className="name">{p.name || 'PLAYER'}</div>
        <div className="bar">
          <div className="fill" style={{width: hpPct + '%',
            background: hpPct < 25 ? 'linear-gradient(to right, #ff2d8a, #ff6060)' : 'linear-gradient(to right, #ff2d8a, #ffe14d)'
          }} />
        </div>
        <div className="bar stam">
          <div className="fill" style={{width: stamPct + '%'}} />
        </div>
        <div className="meta">♥ {'♥'.repeat(p.lives || 0)}</div>
      </div>

      <div className="center-hud">
        <div className="round-pill">{stage?.name || ''}</div>
        <div className="score-display">{(p.score || 0).toLocaleString()}</div>
        {enemyCount > 0 && (
          <div className="enemy-count">
            {enemyCount} {enemyCount === 1 ? 'ENEMY' : 'ENEMIES'}
          </div>
        )}
      </div>

      <div className="panel right">
        <div className="name" style={{textAlign:'right'}}>ENEMIES</div>
        {enemies.slice(0,3).map((e, i) => (
          <div key={i} className="bar" style={{marginLeft:'auto'}}>
            <div className="fill" style={{
              width: ((e.hp / e.maxHp) * 100) + '%',
              background: 'linear-gradient(to right, #5cf2ff, #ff2d8a)',
              float: 'right'
            }} />
          </div>
        ))}
      </div>
    </div>
  );
}

// ─── End Screen ───────────────────────────────────────────────────────────────
function EndScreen({ game, finalScore, username, onContinue, onRestart }) {
  const won = game.phase === 'victory';
  const p = game.player;
  const acc = p.thrown > 0 ? Math.floor((p.landed / p.thrown) * 100) : 0;

  return (
    <div className="end-screen">
      <h1>{won ? 'VICTORY!' : 'GAME OVER'}</h1>
      <div className="verdict">{won ? 'YOU ARE THE FURY FIST CHAMPION' : 'BETTER LUCK NEXT TIME'}</div>
      <div className="end-score">
        {finalScore.toLocaleString()}
        <small>FINAL SCORE • STAGE {game.stageIdx + 1}</small>
      </div>
      <div className="stats">
        <div>COMBOS  <b>{p.biggestCombo || 0}</b> BEST</div>
        <div>ACCURACY  <b>{acc}%</b></div>
        <div>ENEMIES  <b>{p.killCount || 0}</b> DEFEATED</div>
        {!username && <div style={{color:'var(--hot)', marginTop:'0.5em'}}>LOGIN TO SAVE SCORE!</div>}
      </div>
      <div className="end-buttons">
        <button className="btn-hot" onClick={onContinue}>
          {won ? '► HALL OF FAME' : '► CONTINUE'}
        </button>
        <button className="btn-cool" onClick={onRestart}>
          ↺ PLAY AGAIN
        </button>
      </div>
    </div>
  );
}

// ─── Leaderboard ──────────────────────────────────────────────────────────────
function Leaderboard({ scores, currentUser, onBack, loading }) {
  return (
    <div className="leaderboard">
      <h2>HALL OF FAME</h2>
      <div className="sub">FURY FIST CHAMPIONS</div>

      {loading ? (
        <div className="empty" style={{color:'var(--cool)'}}>LOADING SCORES...</div>
      ) : scores.length === 0 ? (
        <div className="empty">NO SCORES YET. BE THE FIRST!</div>
      ) : (
        <table>
          <thead>
            <tr>
              <th>#</th>
              <th>FIGHTER</th>
              <th>SCORE</th>
              <th>STAGE</th>
              <th>DIFF</th>
            </tr>
          </thead>
          <tbody>
            {scores.slice(0,15).map((s, i) => (
              <tr key={s.id || i} className={s.username === currentUser ? 'self' : ''}>
                <td className={`rank ${i < 3 ? 'top' : ''}`}>{i < 3 ? ['①','②','③'][i] : `#${i+1}`}</td>
                <td className="name">{s.username || s.name || '???'}</td>
                <td className="score">{(s.score||0).toLocaleString()}</td>
                <td className="meta">ST.{s.stage||1}</td>
                <td className="meta">{(s.difficulty||'normal').toUpperCase().slice(0,4)}</td>
              </tr>
            ))}
          </tbody>
        </table>
      )}

      <div className="back" onClick={onBack}>[ PRESS ENTER TO RETURN ]</div>
    </div>
  );
}

// ─── Main App ─────────────────────────────────────────────────────────────────
const DIFF_VALS = [0.65, 1.0, 1.35, 1.7];
const DIFF_NAMES = ['easy', 'normal', 'hard', 'fury'];

function App() {
  const [screen, setScreen] = useState('login');  // login | title | fight | end | leaderboard
  const [username, setUsername] = useState(() => getUser());
  const [token, setToken]    = useState(() => getToken());
  const [difficulty, setDifficulty] = useState(1);
  const [finalScore, setFinalScore] = useState(0);
  const [scores, setScores] = useState([]);
  const [scoresLoading, setScoresLoading] = useState(false);

  const canvasRef = useRef(null);
  const gameRef   = useRef(null);
  const { stateRef: inputRef, onStartRef } = useInput();

  // Init canvas
  useEffect(() => {
    const canvas = canvasRef.current;
    if (canvas) { canvas.width = E.W; canvas.height = E.H; }
  }, []);

  // Check stored auth on mount
  useEffect(() => {
    if (getToken() && getUser()) {
      setUsername(getUser());
      setToken(getToken());
      setScreen('title');
    }
  }, []);

  const beginFight = useCallback(() => {
    const game = E.makeGame({
      playerName: username || 'PLAYER',
      difficulty: DIFF_VALS[difficulty],
    });
    gameRef.current = game;
    setScreen('fight');
  }, [username, difficulty]);

  const onPhaseChange = useCallback((phase) => {
    if (phase === 'gameOver' || phase === 'victory') {
      const score = E.calcFinalScore(gameRef.current);
      setFinalScore(score);
      setScreen('end');
    }
  }, []);

  const fetchScores = useCallback(async () => {
    setScoresLoading(true);
    const res = await apiGet('/scores');
    if (res.scores) {
      setScores(res.scores);
    } else {
      // Fallback: show local scores
      setScores(loadLocalScores());
    }
    setScoresLoading(false);
  }, []);

  const submitScore = useCallback(async (score) => {
    const game = gameRef.current;
    const entry = {
      id: Date.now().toString(36),
      username: username || 'GUEST',
      score,
      stage: game.stageIdx + 1,
      difficulty: DIFF_NAMES[difficulty],
      date: new Date().toISOString(),
    };

    if (token) {
      await apiPost('/scores', entry, token);
    } else {
      saveLocalScore(entry);
    }
  }, [username, token, difficulty]);

  const showLeaderboard = useCallback(async () => {
    await fetchScores();
    setScreen('leaderboard');
  }, [fetchScores]);

  onStartRef.current = useCallback(() => {
    if (screen === 'title') beginFight();
    else if (screen === 'leaderboard') setScreen('title');
  }, [screen, beginFight]);

  const handleLogin = (user, tok) => {
    setUsername(user);
    setToken(tok);
    setScreen('title');
  };

  const handleGuest = () => {
    setUsername(null);
    setToken(null);
    setScreen('title');
  };

  const handleLogout = () => {
    clearAuth();
    setUsername(null);
    setToken(null);
    setScreen('login');
  };

  const handleEndContinue = useCallback(async () => {
    // Submit score then show leaderboard
    await submitScore(finalScore);
    await showLeaderboard();
  }, [finalScore, submitScore, showLeaderboard]);

  useGameLoop(canvasRef, gameRef, inputRef, onPhaseChange);

  return (
    <div className="stage crt">
      <canvas id="game" ref={canvasRef} />
      <div className="overlay">

        {/* HUD */}
        {screen === 'fight' && gameRef.current && (
          <>
            <Hud game={gameRef.current} />
            {gameRef.current.banner && (
              <div className="banner">
                {gameRef.current.banner.text}
                {gameRef.current.banner.sub && <span className="sub">{gameRef.current.banner.sub}</span>}
              </div>
            )}
          </>
        )}

        {/* Screens */}
        {screen === 'login' && (
          <LoginScreen onLogin={handleLogin} onGuest={handleGuest} />
        )}

        {screen === 'title' && (
          <TitleScreen
            username={username}
            onStart={beginFight}
            onLeaderboard={showLeaderboard}
            onLogout={handleLogout}
            difficulty={difficulty}
            setDifficulty={setDifficulty}
          />
        )}

        {screen === 'end' && (
          <EndScreen
            game={gameRef.current}
            finalScore={finalScore}
            username={username}
            onContinue={handleEndContinue}
            onRestart={() => { setScreen('title'); }}
          />
        )}

        {screen === 'leaderboard' && (
          <Leaderboard
            scores={scores}
            currentUser={username}
            onBack={() => setScreen('title')}
            loading={scoresLoading}
          />
        )}

        <div className="credit" style={{zIndex:20}}>© RISINGBOB ✦ UMEÅ ✦ SWEDEN</div>
      </div>
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
