// pipeline-board.jsx — Kanban view of the pipeline. Shares PStore with the grid,
// so dragging a card to a new column is the same edit as changing the Stage cell.
// Exposes window.PipelineBoard. Three layouts: comfortable · compact · swimlanes.
const { useState, useRef } = React;
const BS = window.RaiseShell;
const BStore = window.RaisePipe.store;
const RB = window.RAISE;

// commitment probability per stage → feeds the weighted pipeline (the hero number)
const STAGE_PROB = { identified:0.03, outreach:0.10, meeting:0.20, dataroom:0.35, terms:0.60, verbal:0.80, wired:1.0, passed:0 };
// the event that justifies a forward move into a stage (quick-confirm copy)
const STAGE_ENTRY = {
  outreach:'first touch made', meeting:'a meeting held', dataroom:'data-room access granted',
  terms:'a terms conversation', verbal:'a verbal commit with a $ figure', wired:'funds received',
};
const STAGE_BY_LABEL = {}; RB.STAGES.forEach((s,i) => STAGE_BY_LABEL[s.label] = { ...s, idx:i });
const WARMTH_C = { Hot:'#c4504f', Warm:'#c96442', Cool:'#4a78c8', Cold:'#9b9285' };
const lastTouchOf = (id) => (RB.contactById(id) || {}).lastTouch || null;

function weightedOf(rows){
  return rows.reduce((s,r) => {
    const st = STAGE_BY_LABEL[r.stage]; const p = st ? (STAGE_PROB[st.id] ?? 0) : 0;
    return s + (typeof r.check==='number' ? r.check : 0) * p;
  }, 0);
}

// ── minimal LP card ────────────────────────────────────────────────
function BoardCard({ row, compact, onOpen, onDragStart, onDragEnd, dragging }){
  const wc = WARMTH_C[row.warmth] || '#9b9285';
  const lt = lastTouchOf(row.id);
  return (
    <div className={'bcard'+(compact?' compact':'')+(dragging?' dragging':'')+(row.anchor?' anchor':'')}
      draggable onDragStart={e => onDragStart(e, row.id)} onDragEnd={onDragEnd}
      onClick={() => row.isContact && onOpen(row)}>
      <div className="bcard-top">
        <span className={'bava mono'+(row.anchor?' anchor':'')}>{BS.initials(row.name)}{row.anchor && <i className="bstar">★</i>}</span>
        <div className="bcard-id">
          <div className="bnm">{row.name}</div>
          {!compact && <div className="bfirm">{row.firm || '—'}</div>}
        </div>
        <span className="bwarm" style={{ background:wc }} title={row.warmth} />
      </div>
      <div className="bcard-meta">
        <span className="bchk mono">{row.check!=null ? BS.money(row.check) : '—'}</span>
        <span className="btier">{row.tier}</span>
        {lt && <span className="bdays mono" title="Last touch">{lt}</span>}
      </div>
    </div>
  );
}

// ── one stage column ───────────────────────────────────────────────
function BoardColumn({ stage, rows, compact, dragId, dragOver, handlers, onOpen }){
  const sum = rows.reduce((s,r) => s + (typeof r.check==='number'?r.check:0), 0);
  const wsum = weightedOf(rows);
  return (
    <div className={'bcol'+(dragOver?' over':'')}
      onDragOver={e => handlers.onDragOver(e, stage)}
      onDragLeave={handlers.onDragLeave}
      onDrop={e => handlers.onDrop(e, stage)}>
      <div className="bcol-hd">
        <span className="bcol-dot" style={{ background:stage.color }} />
        <span className="bcol-nm">{stage.label}</span>
        <span className="bcol-ct mono">{rows.length}</span>
      </div>
      <div className="bcol-sub mono">{BS.money(sum)}{wsum>0 && <span className="bcol-w"> · {BS.money(Math.round(wsum))} wtd</span>}</div>
      <div className="bcol-body">
        {rows.length===0
          ? <div className={'bempty'+(dragOver?' active':'')}>{dragOver ? 'Drop here' : 'Empty'}</div>
          : rows.map(r => (
              <BoardCard key={r.id} row={r} compact={compact} onOpen={onOpen}
                dragging={dragId===r.id}
                onDragStart={handlers.onDragStart} onDragEnd={handlers.onDragEnd} />
            ))}
      </div>
    </div>
  );
}

// ── advance confirmation popover ───────────────────────────────────
function AdvanceConfirm({ pending, onConfirm, onCancel }){
  const [note, setNote] = useState('');
  const stage = pending.stage;
  const entry = STAGE_ENTRY[stage.id];
  return (
    <div className="bconfirm-back" onClick={onCancel}>
      <div className="bconfirm" onClick={e => e.stopPropagation()}>
        <div className="bconfirm-hd">
          <span className="bcol-dot" style={{ background:stage.color }} />
          Move <b>{pending.name}</b> to <b>{stage.label}</b>
        </div>
        <p className="bconfirm-sub">Log {entry ? <>the event — <b>{entry}</b></> : 'this move'} so the timeline stays honest.</p>
        <input className="bconfirm-in" autoFocus placeholder={entry ? 'e.g. '+entry+'…' : 'Optional note…'}
          value={note} onChange={e => setNote(e.target.value)}
          onKeyDown={e => { if(e.key==='Enter') onConfirm(note); if(e.key==='Escape') onCancel(); }} />
        <div className="bconfirm-row">
          <button className="btn sm" onClick={onCancel}>Cancel</button>
          <button className="btn primary sm" onClick={() => onConfirm(note)}>Log &amp; move</button>
        </div>
      </div>
    </div>
  );
}

function PipelineBoard({ rows, layout, onOpen }){
  const [dragId, setDragId] = useState(null);
  const [overKey, setOverKey] = useState(null);
  const [pending, setPending] = useState(null);   // {rowId, name, stage}
  const dragRef = useRef(null);

  const target = RB.capital.target;
  const weighted = weightedOf(rows);
  const activeLPs = rows.filter(r => r.stage!=='Identified' && r.stage!=='Passed').length;
  const wired = rows.filter(r => r.stage==='Wired').reduce((s,r)=> s+(r.check||0), 0);
  const pct = Math.min(100, Math.round((weighted/target)*100));

  const move = (rowId, label, note) => {
    BStore.patchCell(rowId, 'stage', label);
    const r = rows.find(x => x.id===rowId);
    BS.toast(`${r ? r.name : 'LP'} → ${label}${note ? ' · logged' : ''}`);
  };

  const handlers = {
    onDragStart: (e, rowId) => { setDragId(rowId); dragRef.current = rowId; e.dataTransfer.effectAllowed='move'; try{ e.dataTransfer.setData('text/plain', rowId); }catch(x){} },
    onDragEnd: () => { setDragId(null); setOverKey(null); dragRef.current = null; },
    onDragOver: (e, stage) => { e.preventDefault(); e.dataTransfer.dropEffect='move'; if(overKey!==stage.id) setOverKey(stage.id); },
    onDragLeave: () => {},
    onDrop: (e, stage) => {
      e.preventDefault();
      const rowId = dragRef.current || (e.dataTransfer && e.dataTransfer.getData('text/plain'));
      setOverKey(null); setDragId(null);
      if(!rowId) return;
      const row = rows.find(r => r.id===rowId); if(!row) return;
      const from = STAGE_BY_LABEL[row.stage]; const to = stage;
      if(!from || from.idx===to.idx) return;
      const forward = to.idx > from.idx;
      if(forward && STAGE_ENTRY[to.id]){ setPending({ rowId, name:row.name, stage:to }); }
      else { move(rowId, to.label); }   // regress, or move into Identified/Passed — no prompt
    },
  };

  const compact = layout==='compact';
  const lanes = layout==='swimlanes'
    ? RB.STAGES.length && [...new Set(rows.map(r => r.icp))].filter(Boolean).sort()
    : null;

  const colsFor = (laneRows) => RB.STAGES.map(s => (
    <BoardColumn key={s.id} stage={STAGE_BY_LABEL[s.label]}
      rows={laneRows.filter(r => r.stage===s.label)}
      compact={compact} dragId={dragId} dragOver={overKey===s.id && !lanes}
      handlers={handlers} onOpen={onOpen} />
  ));

  return (
    <div className="boardview">
      {/* persistent hero header — weighted pipeline vs target */}
      <div className="bhdr">
        <div className="bhdr-main">
          <div className="bhdr-num"><b>{BS.money(Math.round(weighted))}</b><span className="bhdr-of">weighted · of {BS.money(target)} target</span></div>
          <div className="bhdr-bar"><span style={{ width: pct+'%' }} /></div>
        </div>
        <div className="bhdr-stats">
          <div className="bstat"><b>{pct}%</b><span>to target</span></div>
          <div className="bstat"><b>{activeLPs}</b><span>active LPs</span></div>
          <div className="bstat"><b>{BS.money(wired)}</b><span>wired</span></div>
        </div>
      </div>

      {lanes
        ? (
          <div className="blanes">
            {lanes.map(seg => {
              const laneRows = rows.filter(r => r.icp===seg);
              return (
                <div className="blane" key={seg}>
                  <div className="blane-hd"><span className="blane-nm">{seg}</span><span className="blane-ct mono">{laneRows.length}</span><span className="blane-w mono">{BS.money(Math.round(weightedOf(laneRows)))} wtd</span></div>
                  <div className="bcols">{colsFor(laneRows)}</div>
                </div>
              );
            })}
          </div>
        )
        : <div className="bcols">{colsFor(rows)}</div>}

      {pending && (
        <AdvanceConfirm pending={pending}
          onConfirm={(note) => { move(pending.rowId, pending.stage.label, note); setPending(null); }}
          onCancel={() => setPending(null)} />
      )}
    </div>
  );
}
window.PipelineBoard = PipelineBoard;
window.RaiseBoard = { weightedOf, STAGE_PROB };
