/* panels/enginepanel.js — one engine's analysis output.
   Header: engine picker, MultiPV, start/stop. Body: PV rows (clickable),
   stats line (depth/nodes/nps/time). Bound to an Analyser instance. */
'use strict';

import { h, clear, fmtInt } from '../ui/dom.js';
import { icon } from '../ui/icons.js';
import { makePanel, showMenu } from '../ui/widgets.js';
import { engines, Analyser, whiteScore, fmtEval, evalClass } from '../svc/engines.js';
import { settings } from '../svc/settings.js';
import { Chess } from '../core/rules.js';
import { figurine } from '../core/doc.js';

export function createEnginePanel({ id = 'engine', title = 'Engine', engine = 'stockfish', instance = 'a', getTarget, onPlayLine, onBestMove }) {
  const analyser = new Analyser({ engine, instance, multipv: settings.get('analysis.multipv') });
  let lastInfo = null;
  let locked = false;      // line locking: keep displaying pinned info
  let lockedInfo = null;

  const linesEl = h('div.ep-lines');
  const statsEl = h('div.ep-stats');
  const toggleBtn = h('button.icon-btn', {
    html: icon('play'), title: 'Start analysis (Ctrl+E)', 'aria-label': 'Start/stop analysis',
    onclick: () => analyser.toggle(),
  });
  const engineBtn = h('button.btn.btn-ghost.btn-sm', {
    onclick: e => {
      e.stopPropagation();
      const avail = engines.available();
      showMenu(avail.map(a => ({
        label: a.name, checked: analyser.engine === a.key,
        action: () => { analyser.setEngine(a.key); engineBtn.textContent = engines.nameOf(a.key); },
      })), e.clientX, e.clientY);
    },
  }, engines.nameOf(engine));
  const pvBtn = h('button.btn.btn-ghost.btn-sm', {
    title: 'Number of lines (MultiPV)',
    onclick: e => {
      e.stopPropagation();
      showMenu([1, 2, 3, 4, 5].map(n => ({
        label: `${n} line${n > 1 ? 's' : ''}`, checked: analyser.multipv === n,
        action: () => { analyser.setMultiPv(n); pvBtn.textContent = n + 'PV'; },
      })), e.clientX, e.clientY);
    },
  }, analyser.multipv + 'PV');
  const lockBtn = h('button.icon-btn', {
    html: icon('pin'), title: 'Lock displayed lines',
    onclick: () => {
      locked = !locked;
      lockedInfo = locked ? lastInfo : null;
      lockBtn.classList.toggle('active', locked);
      render();
    },
  });

  const body = h('div.ep-body', {}, linesEl, statsEl);
  const panel = makePanel({ id, title, icon: 'cpu', body });
  const header = panel.el.querySelector('.panel-actions');
  header.prepend(engineBtn, pvBtn, lockBtn, toggleBtn);

  function render() {
    const info = locked && lockedInfo ? lockedInfo : lastInfo;
    clear(linesEl);
    if (!engines.has(analyser.engine)) {
      linesEl.append(h('div.ep-offline', {}, 'Engine unavailable — start server.py'));
      statsEl.textContent = '';
      return;
    }
    if (!info) {
      linesEl.append(h('div.ep-offline', {}, analyser.running ? 'Searching…' : 'Analysis stopped'));
      statsEl.textContent = '';
      return;
    }
    const { res, target } = info;
    const stm = target.stm;
    const fig = settings.get('ui.figurine');
    const lines = res.lines && res.lines.length ? res.lines : (res.pv ? [res] : []);
    for (const line of lines) {
      const score = whiteScore(line, stm);
      const sanLine = pvToSan(line.pv || [], target.fenNow, fig);
      const row = h('div.ep-line', {
        title: 'Click: play first move · Right-click: insert line as variation',
        onclick: () => onPlayLine && line.pv?.length && onPlayLine(line.pv, 1),
        oncontextmenu: e => {
          e.preventDefault();
          showMenu([
            { label: 'Play first move', icon: 'play', action: () => onPlayLine && onPlayLine(line.pv, 1) },
            { label: 'Insert full line as variation', icon: 'tree', action: () => onPlayLine && onPlayLine(line.pv, line.pv.length) },
            { label: 'Copy line', icon: 'copy', action: () => navigator.clipboard.writeText(sanLine).catch(() => {}) },
          ], e.clientX, e.clientY);
        },
      },
        h('span.ep-eval', { class: evalClass(score) }, fmtEval(score)),
        h('span.ep-depth', {}, 'd' + (line.depth ?? res.depth ?? '·')),
        h('span.ep-pv', {}, sanLine),
      );
      linesEl.append(row);
    }
    statsEl.textContent = `depth ${res.depth ?? '—'} · ${fmtInt(res.nodes)} nodes · ${fmtInt(res.nps)} n/s · ${res.time != null ? (res.time / 1000).toFixed(1) + 's' : '—'}`;
    if (locked) statsEl.textContent += '  (locked)';
  }

  analyser.on('info', (res, target) => {
    lastInfo = { res, target };
    if (onBestMove && res.lines?.[0]?.pv?.length) onBestMove(res.lines[0].pv[0], whiteScore(res.lines[0], target.stm), res);
    if (!locked) render();
  });
  analyser.on('reset', () => { lastInfo = null; if (!locked) render(); });
  analyser.on('state', running => {
    toggleBtn.innerHTML = icon(running ? 'pause' : 'play');
    toggleBtn.title = running ? 'Stop analysis' : 'Start analysis';
    render();
  });

  function retarget() {
    if (!getTarget) return;
    const t = getTarget();
    analyser.setTarget(t);
  }

  render();
  return { panel, analyser, retarget, render, get engineKey() { return analyser.engine; } };
}

export function pvToSan(pv, fen, fig) {
  try {
    const pos = new Chess(fen);
    const out = [];
    let first = true;
    for (const u of pv.slice(0, 12)) {
      const m = pos.findUci(u);
      if (!m) break;
      const no = pos.turn === 1 ? pos.fullmove + '. ' : (first ? pos.fullmove + '… ' : '');
      out.push(no + figurine(pos.san(m), fig));
      pos.makeMove(m);
      first = false;
    }
    return out.join(' ');
  } catch { return (pv || []).join(' '); }
}
