// atelier-screens-f.jsx — Ghost Routes interactive piece routing.
//
// Reads window.LESSON.heroRoute (computed by tools/route-analysis.js).
// The user attempts to route the hero piece from its starting square to the
// trajectory's target square, hop by hop. Squares attacked by enemy pieces
// are flagged unsafe.
//
// Per INV-005: the "best path" is BFS over legal piece moves with attacker
// counts, not engine recommendation. The UI labels it "shortest safe path."

const { useState: useGR, useEffect: useGRE, useMemo: useGRM } = React;

const GR_GLYPH = {
  wP: '♙', wN: '♘', wB: '♗', wR: '♖', wQ: '♕', wK: '♔',
  bP: '♟', bN: '♞', bB: '♝', bR: '♜', bQ: '♛', bK: '♚',
};

function grSqXY(sq, sqPx) {
  const f = sq.charCodeAt(0) - 'a'.charCodeAt(0);
  const r = 8 - parseInt(sq[1], 10);
  return { x: f * sqPx + sqPx / 2, y: r * sqPx + sqPx / 2 };
}
function fileRank(sq) {
  return [sq.charCodeAt(0) - 'a'.charCodeAt(0), 8 - parseInt(sq[1], 10)];
}

// Knight reachable squares from `from` in one hop (does not check legality)
function knightHops(from) {
  const [f, r] = [from.charCodeAt(0) - 'a'.charCodeAt(0), parseInt(from[1], 10) - 1];
  const deltas = [[-2,-1],[-2,1],[-1,-2],[-1,2],[1,-2],[1,2],[2,-1],[2,1]];
  const out = [];
  for (const [df, dr] of deltas) {
    const nf = f + df, nr = r + dr;
    if (nf < 0 || nf > 7 || nr < 0 || nr > 7) continue;
    out.push(String.fromCharCode(97 + nf) + (nr + 1));
  }
  return out;
}

// ── Board ────────────────────────────────────────────────────────
function GhostRouteBoard({ palette, position, hero, target, route, userPath, enemyAttacks, onSquareClick, size = 520 }) {
  const C = palette;
  const SQ = size / 8;

  const reachableSet = new Set(userPath.length > 0
    ? knightHops(userPath[userPath.length - 1]).filter((sq) => {
        const occ = position[sq];
        if (occ && occ[0] === position[hero][0] && sq !== hero) return false;
        return true;
      })
    : []);

  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ display: 'block' }}>
      {/* squares */}
      {[...Array(8)].flatMap((_, rank) => [...Array(8)].map((__, file) => {
        const sq = 'abcdefgh'[file] + (8 - rank);
        const isLight = (file + rank) % 2 === 0;
        return (
          <rect key={sq}
            x={file * SQ} y={rank * SQ}
            width={SQ} height={SQ}
            fill={isLight ? C.squareLight : C.squareDark || C.boneDeep}
            onClick={onSquareClick ? () => onSquareClick(sq) : undefined}
            style={{ cursor: onSquareClick ? 'pointer' : 'default' }}
          />
        );
      }))}

      {/* reachable next-hop hints (filled disc, low opacity) */}
      {Array.from(reachableSet).map((sq) => {
        const [f, r] = fileRank(sq);
        const safe = !enemyAttacks.has(sq);
        return (
          <circle key={'r-' + sq}
            cx={f * SQ + SQ / 2} cy={r * SQ + SQ / 2} r={SQ * 0.16}
            fill={safe ? (C.celadon || '#9bbf9b') : (C.terracotta || C.sienna)}
            opacity={0.45}
            pointerEvents="none"
          />
        );
      })}

      {/* target glow */}
      {target && (() => {
        const [f, r] = fileRank(target);
        return (
          <rect key={'tg'}
            x={f * SQ + 4} y={r * SQ + 4}
            width={SQ - 8} height={SQ - 8}
            fill="none" stroke={C.brass || C.umber} strokeWidth={2.5}
            strokeDasharray="4 4"
            opacity={0.9}
            rx={3}
            pointerEvents="none"
          />
        );
      })()}

      {/* user's traversed path — connect dots */}
      {userPath.slice(0, -1).map((sq, i) => {
        const a = grSqXY(sq, SQ);
        const b = grSqXY(userPath[i + 1], SQ);
        return (
          <line key={'p-' + i}
            x1={a.x} y1={a.y} x2={b.x} y2={b.y}
            stroke={C.sienna} strokeWidth={2} opacity={0.75}
            strokeDasharray="3 3"
            pointerEvents="none"
          />
        );
      })}

      {/* pieces (except the moving hero) */}
      {Object.entries(position).map(([sq, code]) => {
        if (sq === hero && userPath.length > 0) return null; // hero drawn at its current ghost square
        const { x, y } = grSqXY(sq, SQ);
        return (
          <text key={'p-' + sq}
            x={x} y={y + SQ * 0.32}
            fontSize={SQ * 0.82}
            textAnchor="middle"
            fontFamily='"Noto Sans Symbols 2","Segoe UI Symbol",sans-serif'
            fill={code[0] === 'w' ? C.umber : C.umberSoft}
            pointerEvents="none"
          >{GR_GLYPH[code] || '?'}</text>
        );
      })}

      {/* hero ghost at current end of userPath */}
      {userPath.length > 0 && (() => {
        const at = userPath[userPath.length - 1];
        const { x, y } = grSqXY(at, SQ);
        const heroCode = position[hero];
        return (
          <text key={'ghost'}
            x={x} y={y + SQ * 0.32}
            fontSize={SQ * 0.82}
            textAnchor="middle"
            fontFamily='"Noto Sans Symbols 2","Segoe UI Symbol",sans-serif'
            fill={heroCode[0] === 'w' ? C.umber : C.umberSoft}
            opacity={0.9}
            pointerEvents="none"
          >{GR_GLYPH[heroCode] || '?'}</text>
        );
      })()}

      {/* shortest route hint (dotted line through BFS path) */}
      {route && route.path && route.path.length > 1 && route.path.slice(0, -1).map((sq, i) => {
        const a = grSqXY(sq, SQ);
        const b = grSqXY(route.path[i + 1], SQ);
        return (
          <line key={'h-' + i}
            x1={a.x} y1={a.y} x2={b.x} y2={b.y}
            stroke={C.brass || C.umber} strokeWidth={1.5} opacity={0.18}
            strokeDasharray="2 4"
            pointerEvents="none"
          />
        );
      })}
    </svg>
  );
}

// ── Screen ──────────────────────────────────────────────────────
function GhostRoutesScreen({ palette, tweaks, setRoute }) {
  const C = palette;
  const T = window.COPY.ghostRoutes;

  const [lesson, setLesson] = useGR(window.LESSON || null);
  useGRE(() => {
    const handler = (e) => setLesson(e.detail);
    window.addEventListener('lessonLoaded', handler);
    return () => window.removeEventListener('lessonLoaded', handler);
  }, []);

  const route = lesson && lesson.heroRoute;
  const hero = lesson && lesson.hero;
  const trajectory = lesson && lesson.trajectories && hero ? lesson.trajectories[hero] : null;
  const target = trajectory && trajectory.length > 1 ? trajectory[trajectory.length - 1] : null;

  const [userPath, setUserPath] = useGR(hero ? [hero] : []);
  const [feedback, setFeedback] = useGR(null);

  useGRE(() => {
    setUserPath(hero ? [hero] : []);
    setFeedback(null);
  }, [lesson && lesson.id, hero]);

  // Compute enemy attack map for safety hints
  const enemyAttacks = useGRM(() => {
    const out = new Set();
    if (!lesson || !lesson.position || !hero) return out;
    const heroCode = lesson.position[hero];
    if (!heroCode) return out;
    const enemy = heroCode[0] === 'w' ? 'b' : 'w';
    for (const [sq, code] of Object.entries(lesson.position)) {
      if (code[0] !== enemy) continue;
      // Inline knight attack expansion — for non-knight enemies we just
      // copy from the lesson's influence map if present.
    }
    // Easier: rebuild from existing data — derive from per-piece influence map.
    const inf = lesson.influenceByPiece || {};
    for (const [from, code] of Object.entries(lesson.position)) {
      if (code[0] === heroCode[0]) continue;
      const sqMap = inf[from];
      if (sqMap) for (const sq of Object.keys(sqMap)) out.add(sq);
    }
    return out;
  }, [lesson, hero]);

  if (!lesson || !route || !route.found || !hero || !target) {
    return (
      <div style={{ flex: 1, height: '100%', overflow: 'auto', background: C.bone, padding: 40 }}>
        <window.Topbar palette={C} kicker={T.topbarKicker} title={T.topbarTitle} rightSlot={null} />
        <div style={{ padding: 40, textAlign: 'center', color: C.umberSoft, fontFamily: window.ATELIER_TYPE.display, fontSize: 16 }}>
          {T.emptyState}
        </div>
      </div>
    );
  }

  const position = lesson.position;
  const optimalHops = route.hops;
  const userHops = userPath.length - 1;
  const atTarget = userPath[userPath.length - 1] === target;

  const handleSquareClick = (sq) => {
    if (atTarget) return;
    const cur = userPath[userPath.length - 1];
    const valid = knightHops(cur).includes(sq);
    if (!valid) {
      setFeedback({ kind: 'invalid', text: T.invalidHop(sq) });
      return;
    }
    const occ = position[sq];
    if (occ && occ[0] === position[hero][0]) {
      setFeedback({ kind: 'invalid', text: T.blockedByOwn(sq) });
      return;
    }
    const newPath = [...userPath, sq];
    setUserPath(newPath);
    if (sq === target) {
      const userN = newPath.length - 1;
      if (userN === optimalHops) {
        setFeedback({ kind: 'correct', text: T.correctOptimal(userN) });
      } else {
        setFeedback({ kind: 'close', text: T.correctNotOptimal(userN, optimalHops, route.path) });
      }
    } else if (enemyAttacks.has(sq)) {
      setFeedback({ kind: 'warn', text: T.steppedOnUnsafe(sq) });
    } else {
      setFeedback({ kind: 'ok', text: T.safeStep(sq) });
    }
  };

  const reset = () => { setUserPath([hero]); setFeedback(null); };

  return (
    <div style={{
      flex: 1, height: '100%', overflow: 'hidden', display: 'grid',
      gridTemplateColumns: '340px minmax(0, 1fr) 340px',
      background: C.bone,
    }}>
      <aside style={{
        padding: '24px 22px', borderRight: `0.6px solid ${C.umberHair}`,
        background: C.bone, overflow: 'auto',
        display: 'flex', flexDirection: 'column', gap: 16,
      }}>
        <window.SectionHeading palette={C} kicker={T.listKicker} title={T.listTitle} small />

        <div style={{
          padding: '14px 16px',
          background: C.cream, borderRadius: 10,
          border: `0.6px solid ${C.umberHair}`,
          fontFamily: window.ATELIER_TYPE.display, fontSize: 14, color: C.umber, lineHeight: 1.55,
        }}>
          {T.prompt(hero, target)}
        </div>

        <div style={{
          padding: '12px 14px',
          background: C.bone, borderRadius: 10,
          border: `0.6px solid ${C.umberHair}`,
          display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8,
        }}>
          <div>
            <div style={{ fontFamily: window.ATELIER_TYPE.ui, fontSize: 9, letterSpacing: 2, color: C.umberFaint }}>{T.optimalLabel}</div>
            <div style={{ fontFamily: window.ATELIER_TYPE.display, fontSize: 20, color: C.umber }}>{optimalHops} {optimalHops === 1 ? 'hop' : 'hops'}</div>
          </div>
          <div>
            <div style={{ fontFamily: window.ATELIER_TYPE.ui, fontSize: 9, letterSpacing: 2, color: C.umberFaint }}>{T.yoursLabel}</div>
            <div style={{ fontFamily: window.ATELIER_TYPE.display, fontSize: 20, color: C.umber }}>{userHops}</div>
          </div>
        </div>

        {feedback && (
          <div style={{
            padding: '12px 14px', borderRadius: 10,
            border: `0.6px solid ${
              feedback.kind === 'correct' ? (C.celadon || C.umber)
              : feedback.kind === 'warn' ? (C.terracotta || C.sienna)
              : feedback.kind === 'invalid' ? (C.terracotta || C.sienna)
              : C.umberHair
            }`,
            background: feedback.kind === 'correct'
              ? window.withAlpha(C.celadon || C.umber, 0.12)
              : feedback.kind === 'warn'
              ? window.withAlpha(C.terracotta || C.sienna, 0.08)
              : feedback.kind === 'invalid'
              ? window.withAlpha(C.terracotta || C.sienna, 0.06)
              : C.cream,
            fontFamily: window.ATELIER_TYPE.display, fontSize: 13, color: C.umber, lineHeight: 1.5,
          }}>{feedback.text}</div>
        )}

        <div style={{ display: 'flex', gap: 8 }}>
          <button onClick={reset} style={{
            appearance: 'none', cursor: 'pointer', padding: '7px 14px', borderRadius: 99,
            border: `0.6px solid ${C.umberHair}`, background: 'transparent',
            color: C.umberSoft, fontFamily: window.ATELIER_TYPE.ui,
            fontSize: 10, letterSpacing: 1.5, textTransform: 'uppercase',
          }}>{T.reset}</button>
        </div>

        <div style={{
          padding: '14px 16px',
          background: C.cream, borderRadius: 10,
          border: `0.6px dashed ${C.umberHair}`,
        }}>
          <div style={{
            fontFamily: window.ATELIER_TYPE.ui, fontSize: 9, letterSpacing: 3,
            textTransform: 'uppercase', color: C.umberFaint, marginBottom: 8,
          }}>{T.howToReadTitle}</div>
          <p style={{ margin: 0, fontFamily: window.ATELIER_TYPE.display, fontSize: 12, lineHeight: 1.5, color: C.umberSoft }}>
            {T.howToReadBody}
          </p>
        </div>
      </aside>

      <div style={{ display: 'flex', flexDirection: 'column' }}>
        <window.Topbar palette={C} kicker={T.topbarKicker} title={T.topbarTitle} rightSlot={null} />
        <div style={{
          flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center',
          padding: 24,
          background: `radial-gradient(120% 80% at 50% -10%, ${window.withAlpha(C.brassLight, 0.35)}, transparent 60%)`,
        }}>
          <div style={{
            background: C.boneDeep, padding: 14, borderRadius: 8,
            boxShadow: '0 30px 50px -28px rgba(42,34,27,0.45)',
          }}>
            <GhostRouteBoard
              palette={C}
              position={position}
              hero={hero}
              target={target}
              route={route}
              userPath={userPath}
              enemyAttacks={enemyAttacks}
              onSquareClick={handleSquareClick}
              size={520}
            />
          </div>
        </div>
      </div>

      <aside style={{
        padding: '24px 22px', borderLeft: `0.6px solid ${C.umberHair}`,
        background: C.cream, overflow: 'auto',
      }}>
        <window.SectionHeading palette={C} kicker={T.legendKicker} title={T.legendTitle} small />
        <ul style={{ margin: '12px 0 0', padding: 0, listStyle: 'none', display: 'flex', flexDirection: 'column', gap: 8 }}>
          <li style={{ fontFamily: window.ATELIER_TYPE.display, fontSize: 13, color: C.umber, display: 'flex', alignItems: 'center', gap: 10 }}>
            <span style={{ width: 12, height: 12, borderRadius: 99, background: C.celadon || '#9bbf9b' }} />{T.legendSafe}
          </li>
          <li style={{ fontFamily: window.ATELIER_TYPE.display, fontSize: 13, color: C.umber, display: 'flex', alignItems: 'center', gap: 10 }}>
            <span style={{ width: 12, height: 12, borderRadius: 99, background: C.terracotta || C.sienna }} />{T.legendUnsafe}
          </li>
          <li style={{ fontFamily: window.ATELIER_TYPE.display, fontSize: 13, color: C.umber, display: 'flex', alignItems: 'center', gap: 10 }}>
            <span style={{ width: 14, height: 14, border: `1.5px dashed ${C.brass || C.umber}`, borderRadius: 2 }} />{T.legendTarget}
          </li>
        </ul>
      </aside>
    </div>
  );
}

Object.assign(window, { GhostRoutesScreen });
