// Road to Glory — Phase 1 vertical slice
//
// One playable moment: a shot at goal.
// User has ~4 seconds to either pass to a teammate or swipe to shoot.
// No match flow, no scoring, no persistence — just the mechanic for feel-testing.
//
// Coordinates: pitch is rendered as a 100x100 logical box, all positions in %.
// Top of screen = goal line. Bottom = our half. Player attacks UP.

(function () {
  const T = () => window.T;

  // ─── Constants ─────────────────────────────────────────────────
  const MOMENT_DURATION_MS = 4000;        // user has this long to act
  const PASS_ANIM_MS = 360;               // ball pass animation duration
  const SHOT_ANIM_MS = 520;               // ball flight duration
  const OUTCOME_FREEZE_MS = 1100;         // pause showing result before reset
  const KEEPER_REACH_PCT = 14;            // x-units of goal line keeper covers around their pos
  const GOAL_X_LEFT = 32;                 // goal posts in pitch %
  const GOAL_X_RIGHT = 68;
  const GOAL_LINE_Y = 4;                  // y of goal line in pitch %
  const SWIPE_MIN_PX = 30;                // min swipe length to register as action
  const SWIPE_START_RADIUS_PCT = 14;       // swipe must START within this many pitch% of ball

  // Initial scenario layout (% of pitch). Same every moment in v1.
  const INITIAL = {
    carrier: { x: 50, y: 65, role: 'ours_carrier' },
    teammate: { x: 75, y: 50, role: 'ours_teammate' },
    defender: { x: 50, y: 35, role: 'theirs_defender' },
    keeper:   { x: 50, y: 8,  role: 'theirs_keeper' },
  };

  // ─── Math helpers ──────────────────────────────────────────────
  // Convert a swipe (dx, dy in px) into a pitch landing point given the
  // swiper's starting position, scaled by the pitch's pixel height so it's
  // device-resolution-independent. Returns landing coords in pitch %.
  function computeSwipeLanding(carrier, dx, dy, pitchHeightPx) {
    const swipeLen = Math.hypot(dx, dy) || 1;
    // Empirical scale: a swipe equal to ~3/4 the pitch height should reach
    // the goal from the carrier's start position. We give a touch of overshoot
    // headroom for very fast swipes so users CAN dispossess themselves.
    const kickDistancePct = Math.min(95, (swipeLen / pitchHeightPx) * 82);
    const dxNorm = dx / swipeLen;
    const dyNorm = dy / swipeLen;
    return {
      x: carrier.x + dxNorm * kickDistancePct,
      // Note: dy is in screen-down-positive coords. Pitch y is the same
      // (top = 0, bottom = 100). So dy carries directly.
      y: carrier.y + dyNorm * kickDistancePct,
      kickDistancePct,
    };
  }

  // Decide what the swipe means: pass, shot, or lost ball.
  // Returns { kind: 'pass'|'shot'|'lost', ...details }.
  function resolveSwipe(landing, carrier, teammate) {
    // Distances
    const distToTeammate = Math.hypot(landing.x - teammate.x, landing.y - teammate.y);
    const goalCenter = { x: (GOAL_X_LEFT + GOAL_X_RIGHT) / 2, y: GOAL_LINE_Y };
    const distToGoal = Math.hypot(landing.x - goalCenter.x, landing.y - goalCenter.y);
    const reachedGoalLine = landing.y <= GOAL_LINE_Y + 3;

    // Pass thresholds
    const PASS_PERFECT = 5;       // pitch units: spot-on
    const PASS_GOOD = 11;          // good pass, accuracy hit but receivable
    const PASS_LOOSE = 18;         // through-ball-ish, generous receive zone

    // If the swipe clearly aimed at the teammate (closer to them than to goal)
    // and within reachable range, treat as a pass.
    if (distToTeammate < distToGoal && distToTeammate <= PASS_LOOSE) {
      // Success probability scales with accuracy
      let successChance = 1.0;
      if (distToTeammate > PASS_PERFECT) {
        // Linear falloff: from 1.0 at PASS_PERFECT to 0.4 at PASS_LOOSE
        const t = (distToTeammate - PASS_PERFECT) / (PASS_LOOSE - PASS_PERFECT);
        successChance = 1.0 - t * 0.6;
      }
      return { kind: 'pass', landing, distToTeammate, successChance };
    }

    // If the swipe was clearly toward goal AND reached it, it's a shot.
    if (reachedGoalLine || (distToGoal < distToTeammate && distToGoal <= 30)) {
      return { kind: 'shot', landing };
    }

    // Otherwise: ball goes nowhere useful → lost
    return { kind: 'lost', landing, distToTeammate, distToGoal };
  }

  // Given shot endpoint, classify outcome.
  function classifyShot(end, keeper, defender) {
    // Crosses goal line? (we treat "goes past" as <= GOAL_LINE_Y after travel)
    const crossesLine = end.y <= GOAL_LINE_Y + 2;
    const inGoalWidth = end.x >= GOAL_X_LEFT && end.x <= GOAL_X_RIGHT;

    if (!crossesLine) return { kind: 'short', label: 'TOO SHORT' };

    // Defender block: if shot path passes near defender's spot on its way up
    // We only check for clearly blocked shots (defender between carrier & goal).
    // Simple test: did the line from carrier to end pass within 6 units of defender?
    // For v1 simplicity skip the line-segment math and just check if endpoint
    // and defender are on similar x AND defender is roughly between.
    // (A real version would do segment-circle distance.)
    // Skipping for now — keeper save is the dominant gate.

    if (!inGoalWidth) return { kind: 'wide', label: 'OFF TARGET' };

    // Keeper save? Compute keeper's effective save range, including a small dive.
    const keeperX = keeper.x + (keeper.dive || 0); // dive offset added
    if (Math.abs(end.x - keeperX) <= KEEPER_REACH_PCT) {
      return { kind: 'save', label: 'SAVED' };
    }
    return { kind: 'goal', label: 'GOAL' };
  }

  // ─── Component ─────────────────────────────────────────────────
  function RtgShotMoment({ onExit }) {
    const t = T();
    const pitchRef = React.useRef(null);
    const dragRef = React.useRef(null); // {startX, startY, points: [{x,y,t}]}
    const timeoutRef = React.useRef(null);

    const [carrier, setCarrier] = React.useState(INITIAL.carrier);
    const [teammate, setTeammate] = React.useState(INITIAL.teammate);
    const [defender] = React.useState(INITIAL.defender);
    const [keeper, setKeeper] = React.useState({ ...INITIAL.keeper, dive: 0 });
    const [phase, setPhase] = React.useState('aim'); // 'aim' | 'pass' | 'shoot' | 'result'
    const [ball, setBall] = React.useState({ x: INITIAL.carrier.x, y: INITIAL.carrier.y });
    const [outcome, setOutcome] = React.useState(null);
    const [timeLeft, setTimeLeft] = React.useState(MOMENT_DURATION_MS);
    const [stats, setStats] = React.useState({ goals: 0, saves: 0, misses: 0, blocked: 0, total: 0 });

    // Reset to initial
    const reset = React.useCallback(() => {
      clearTimers();
      setCarrier(INITIAL.carrier);
      setTeammate(INITIAL.teammate);
      setKeeper({ ...INITIAL.keeper, dive: 0 });
      setBall({ x: INITIAL.carrier.x, y: INITIAL.carrier.y });
      setOutcome(null);
      setPhase('aim');
      setTimeLeft(MOMENT_DURATION_MS);
    }, []);

    function clearTimers() {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
        timeoutRef.current = null;
      }
    }

    // Countdown tick (display only — actual timeout below uses a single timeout)
    React.useEffect(() => {
      if (phase !== 'aim') return;
      const start = Date.now();
      const id = setInterval(() => {
        const elapsed = Date.now() - start;
        setTimeLeft(Math.max(0, MOMENT_DURATION_MS - elapsed));
      }, 50);
      return () => clearInterval(id);
    }, [phase]);

    // Time-up handler: if user hasn't acted within the window, defender closes.
    React.useEffect(() => {
      if (phase !== 'aim') return;
      timeoutRef.current = setTimeout(() => {
        // Time up → tackled
        setOutcome({ kind: 'tackled', label: 'DEFENDER TACKLE' });
        setPhase('result');
        setStats(s => ({ ...s, blocked: s.blocked + 1, total: s.total + 1 }));
      }, MOMENT_DURATION_MS);
      return clearTimers;
    }, [phase]);

    // After result, schedule reset
    React.useEffect(() => {
      if (phase !== 'result') return;
      timeoutRef.current = setTimeout(reset, OUTCOME_FREEZE_MS);
      return clearTimers;
    }, [phase, reset]);

    // ─── Pointer handlers (swipe + tap) ─────────────────────────
    // We capture both touch and mouse so it works in dev preview too.

    // Convert client coords to pitch % using pitchRef bounding box
    const toPct = (clientX, clientY) => {
      const rect = pitchRef.current?.getBoundingClientRect();
      if (!rect) return { x: 50, y: 50 };
      return {
        x: ((clientX - rect.left) / rect.width) * 100,
        y: ((clientY - rect.top) / rect.height) * 100,
      };
    };

    const onPointerDownOnPitch = (e) => {
      if (phase !== 'aim') return;
      const point = e.touches?.[0] || e;
      dragRef.current = {
        startX: point.clientX,
        startY: point.clientY,
        startTime: Date.now(),
        points: [{ x: point.clientX, y: point.clientY, t: 0 }],
        moved: false,
      };
    };
    const onPointerMoveOnPitch = (e) => {
      if (phase !== 'aim') return;
      const d = dragRef.current;
      if (!d) return;
      const point = e.touches?.[0] || e;
      const dx = point.clientX - d.startX;
      const dy = point.clientY - d.startY;
      const len = Math.hypot(dx, dy);
      if (len > 8) d.moved = true;
      d.points.push({
        x: point.clientX, y: point.clientY,
        t: Date.now() - d.startTime,
      });
      // No on-screen preview — skill-based feel test.
      if (e.cancelable) e.preventDefault();
    };
    const onPointerUpOnPitch = (e) => {
      if (phase !== 'aim') return;
      const d = dragRef.current;
      dragRef.current = null;
      if (!d) return;

      // Reject swipes that didn't start near the ball — must "swipe from" the ball.
      const startPct = toPct(d.startX, d.startY);
      const distFromBall = Math.hypot(startPct.x - carrier.x, startPct.y - carrier.y);
      if (distFromBall > SWIPE_START_RADIUS_PCT) {
        return; // Ignore swipe entirely
      }

      const dx = (d.points[d.points.length - 1].x) - d.startX;
      const dy = (d.points[d.points.length - 1].y) - d.startY;
      const len = Math.hypot(dx, dy);

      if (!d.moved || len < SWIPE_MIN_PX) {
        return; // Tap or tiny swipe — ignore
      }

      executeSwipe(dx, dy);
    };

    const executeSwipe = (dx, dy) => {
      clearTimers();
      const rect = pitchRef.current?.getBoundingClientRect();
      const pitchH = rect?.height || 600;
      const landing = computeSwipeLanding(carrier, dx, dy, pitchH);
      const resolution = resolveSwipe(landing, carrier, teammate);

      if (resolution.kind === 'pass') {
        executePass(resolution);
      } else if (resolution.kind === 'shot') {
        executeShot(resolution);
      } else {
        executeLost(resolution);
      }
    };

    const executePass = (res) => {
      setPhase('pass');
      // Animate ball toward landing, not directly to teammate — feels more like a real pass
      setTimeout(() => setBall({ x: res.landing.x, y: res.landing.y }), 20);

      setTimeout(() => {
        const success = Math.random() < res.successChance;
        if (success) {
          // Teammate "collects" the ball — snap to landing if pass was off-line
          const newCarrier = {
            // If the pass was perfect, carrier becomes teammate at their original spot.
            // If imperfect, the receiver moves to where the ball landed (within reach).
            x: res.distToTeammate < 5 ? teammate.x : (teammate.x + res.landing.x) / 2,
            y: res.distToTeammate < 5 ? teammate.y : (teammate.y + res.landing.y) / 2,
            role: 'ours_carrier',
          };
          const newTeammate = { ...carrier, role: 'ours_teammate' };
          setCarrier(newCarrier);
          setTeammate(newTeammate);
          setBall({ x: newCarrier.x, y: newCarrier.y });
          setPhase('aim');
          setTimeLeft(MOMENT_DURATION_MS);
        } else {
          // Ball loose, possession lost
          setOutcome({ kind: 'lost', label: 'POSSESSION LOST' });
          setPhase('result');
          setStats(s => ({ ...s, blocked: s.blocked + 1, total: s.total + 1 }));
        }
      }, PASS_ANIM_MS);
    };

    const executeShot = (res) => {
      const end = res.landing;
      // Keeper dive: pick a side, biased toward where the ball is going
      // but with random error so it's not deterministic.
      const ballSide = end.x - keeper.x;
      const correctDiveDir = Math.sign(ballSide);
      const willGuessRight = Math.random() < 0.55; // 55% chance keeper reads correctly
      const diveDir = willGuessRight ? correctDiveDir : -correctDiveDir;
      const diveAmount = 8 + Math.random() * 6;
      const newKeeper = { ...keeper, dive: diveDir * diveAmount };
      setKeeper(newKeeper);

      setPhase('shoot');
      setTimeout(() => setBall({ x: end.x, y: end.y }), 20);

      timeoutRef.current = setTimeout(() => {
        const out = classifyShot(end, newKeeper, defender);
        setOutcome(out);
        setPhase('result');
        setStats(s => {
          const next = { ...s, total: s.total + 1 };
          if (out.kind === 'goal') next.goals++;
          else if (out.kind === 'save') next.saves++;
          else next.misses++;
          return next;
        });
      }, SHOT_ANIM_MS);
    };

    const executeLost = (res) => {
      setPhase('shoot'); // reuse shoot phase for animation
      setTimeout(() => setBall({ x: res.landing.x, y: res.landing.y }), 20);
      timeoutRef.current = setTimeout(() => {
        setOutcome({ kind: 'lost', label: 'POSSESSION LOST' });
        setPhase('result');
        setStats(s => ({ ...s, blocked: s.blocked + 1, total: s.total + 1 }));
      }, SHOT_ANIM_MS);
    };

    // ─── Render ─────────────────────────────────────────────────
    const TT = T();

    const Dot = ({ pos, color, label, glow, onClick, size = 30 }) => (
      <div
        onClick={onClick}
        style={{
          position: 'absolute', left: `${pos.x}%`, top: `${pos.y}%`,
          width: size, height: size,
          marginLeft: -size / 2, marginTop: -size / 2,
          borderRadius: '50%',
          background: color,
          border: '2px solid rgba(255,255,255,0.6)',
          boxShadow: glow
            ? `0 0 0 3px rgba(245,200,66,0.35), 0 2px 8px rgba(0,0,0,0.4)`
            : '0 2px 6px rgba(0,0,0,0.4)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          color: '#fff',
          fontFamily: 'DM Sans', fontSize: 11, fontWeight: 800,
          transition: 'left 360ms cubic-bezier(0.2,0.8,0.2,1), top 360ms cubic-bezier(0.2,0.8,0.2,1)',
          cursor: onClick ? 'pointer' : 'default',
          zIndex: 4,
          userSelect: 'none', WebkitUserSelect: 'none',
        }}
      >{label}</div>
    );

    const ballSize = 14;

    return (
      <div style={{
        position: 'absolute', inset: 0,
        background: TT.navy950,
        display: 'flex', flexDirection: 'column',
      }}>
        {/* Header */}
        <div style={{
          padding: '14px 16px 10px',
          display: 'flex', justifyContent: 'space-between', alignItems: 'center',
          borderBottom: `1px solid ${TT.border}`,
        }}>
          <button onClick={onExit} style={{
            background: 'transparent', border: 'none', color: TT.text,
            fontSize: 22, lineHeight: 1, cursor: 'pointer',
          }}>‹</button>
          <div style={{
            fontFamily: 'Bakbak One, sans-serif', fontSize: 15,
            color: TT.text, letterSpacing: '0.04em',
          }}>SHOT MOMENT</div>
          <div style={{
            fontSize: 11, color: TT.textSec, fontFamily: 'DM Sans',
            display: 'flex', gap: 10,
          }}>
            <span><b style={{ color: TT.gold400 }}>{stats.goals}</b> goals</span>
            <span><b>{stats.total}</b> total</span>
          </div>
        </div>

        {/* Timer bar */}
        <div style={{
          height: 4, background: TT.card, position: 'relative',
        }}>
          <div style={{
            position: 'absolute', left: 0, top: 0, bottom: 0,
            width: `${(timeLeft / MOMENT_DURATION_MS) * 100}%`,
            background: timeLeft < 1500 ? '#E87A7A' : TT.gold400,
            transition: 'width 50ms linear',
          }}/>
        </div>

        {/* Pitch */}
        <div
          ref={pitchRef}
          onTouchStart={onPointerDownOnPitch}
          onTouchMove={onPointerMoveOnPitch}
          onTouchEnd={onPointerUpOnPitch}
          onMouseDown={onPointerDownOnPitch}
          onMouseMove={onPointerMoveOnPitch}
          onMouseUp={onPointerUpOnPitch}
          style={{
            flex: 1, position: 'relative', overflow: 'hidden',
            background: 'linear-gradient(180deg, #2D8C4E 0%, #1F6638 100%)',
            touchAction: 'none',
          }}
        >
          {/* Pitch markings — attacking third + halfway band */}
          <div style={{
            position: 'absolute', left: 0, right: 0, top: 0,
            height: 4, background: 'rgba(255,255,255,0.45)', // goal line
          }}/>
          <div style={{
            position: 'absolute', left: '20%', right: '20%', top: 0,
            height: '24%', border: '2px solid rgba(255,255,255,0.35)', borderTop: 'none',
          }}/>
          {/* Six-yard box */}
          <div style={{
            position: 'absolute', left: '36%', right: '36%', top: 0,
            height: '10%', border: '2px solid rgba(255,255,255,0.3)', borderTop: 'none',
          }}/>
          {/* Goal */}
          <div style={{
            position: 'absolute',
            left: `${GOAL_X_LEFT}%`,
            right: `${100 - GOAL_X_RIGHT}%`,
            top: -3, height: 8,
            background: 'rgba(255,255,255,0.85)',
            borderRadius: 2,
          }}/>

          {/* Defender */}
          <Dot pos={defender} color="#E55353" label="" />

          {/* Keeper (with dive offset applied) */}
          <Dot
            pos={{ x: keeper.x + (keeper.dive || 0), y: keeper.y }}
            color="#5BC0EB" label="GK" size={32}
          />

          {/* Teammate — swipe toward them to pass */}
          <Dot
            pos={teammate} color={TT.gold500}
            label="" size={26}
            glow={phase === 'aim'}
          />

          {/* Carrier */}
          <Dot pos={carrier} color={TT.gold400} label="" size={32} glow />

          {/* Ball */}
          <div style={{
            position: 'absolute',
            left: `${ball.x}%`, top: `${ball.y}%`,
            width: ballSize, height: ballSize,
            marginLeft: -ballSize / 2, marginTop: -ballSize / 2,
            borderRadius: '50%',
            background: '#fff',
            border: '1.5px solid #1A1200',
            boxShadow: '0 1px 4px rgba(0,0,0,0.5)',
            transition:
              phase === 'shoot' ? `left ${SHOT_ANIM_MS}ms cubic-bezier(0.3,0.6,0.7,1), top ${SHOT_ANIM_MS}ms cubic-bezier(0.3,0.6,0.7,1)`
              : phase === 'pass' ? `left ${PASS_ANIM_MS}ms ease-out, top ${PASS_ANIM_MS}ms ease-out`
              : 'left 200ms ease-out, top 200ms ease-out',
            zIndex: 5,
            pointerEvents: 'none',
          }}/>

          {/* Outcome banner */}
          {phase === 'result' && outcome && (
            <div style={{
              position: 'absolute', inset: 0,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              pointerEvents: 'none',
            }}>
              <div style={{
                fontFamily: 'Bakbak One, sans-serif', fontSize: 56,
                letterSpacing: '0.06em',
                color: outcome.kind === 'goal' ? TT.gold400
                  : outcome.kind === 'save' ? '#5BC0EB'
                  : '#E87A7A',
                textShadow: '0 2px 14px rgba(0,0,0,0.6)',
                animation: 'rtgPop 280ms cubic-bezier(0.2,0.8,0.2,1)',
              }}>{outcome.label}</div>
            </div>
          )}
        </div>

        {/* Hint */}
        <div style={{
          padding: '10px 16px 14px',
          textAlign: 'center', fontSize: 11,
          color: TT.textSec, fontFamily: 'DM Sans',
          borderTop: `1px solid ${TT.border}`,
        }}>
          {phase === 'aim'
            ? 'Swipe from the ball — toward the teammate to pass, toward the goal to shoot'
            : phase === 'pass' ? 'Passing…'
            : phase === 'shoot' ? 'Going…'
            : 'Resetting…'}
        </div>

        <style>{`
          @keyframes rtgPop {
            0%   { transform: scale(0.6); opacity: 0; }
            60%  { transform: scale(1.1); opacity: 1; }
            100% { transform: scale(1.0); opacity: 1; }
          }
        `}</style>
      </div>
    );
  }

  window.RtgShotMoment = RtgShotMoment;
})();
