// Kanban board, cards, and the right-side detail panel

// ISO timestamp -> "just now" / "5m ago" / "3h ago" / "2d ago"
function relTime(iso) {
  if (!iso) return '';
  const t = new Date(iso).getTime();
  if (isNaN(t)) return iso;
  const s = Math.max(0, Math.floor((Date.now() - t) / 1000));
  if (s < 10) return 'just now';
  if (s < 60) return `${s}s ago`;
  const m = Math.floor(s / 60);
  if (m < 60) return `${m}m ago`;
  const h = Math.floor(m / 60);
  if (h < 24) return `${h}h ago`;
  return `${Math.floor(h / 24)}d ago`;
}

function TaskCard({ task, project, agent, selected, onClick, animState, actions }) {
  const showApprove = task.column === 'review';
  const showRollback = task.column === 'done';
  const showRetry = task.column === 'failed';
  const act = actions || {};
  project = project || { color: 'var(--c-text-3)', name: task.project };

  const typeLabel = {
    'module-install': 'Module Install',
    'update': 'Update',
    'agent-task': 'Agent Task',
    'system-task': 'System Task',
  }[task.type];

  return (
    <article
      className={`card status-${task.column} ${selected ? 'selected' : ''} ${animState || ''}`}
      onClick={onClick}
    >
      <div className="card-top">
        <span className="card-id">{task.id}</span>
        <span className={`card-type ${task.type}`}>{typeLabel}</span>
        <PriorityBadge priority={task.priority} />
      </div>

      <h4 className="card-title">{task.title}</h4>

      <div className="card-project">
        <Swatch color={project.color} size={8} />
        <span>{project.name}</span>
        <span style={{ color: 'var(--c-text-4)', marginLeft: 'auto', fontFamily: 'var(--font-mono)', fontSize: 10 }}>
          {relTime(task.updated)}
        </span>
      </div>

      <div className="card-foot">
        <span className="agent-tag">
          <span className="agent-dot" style={{
            background: task.running
              ? 'var(--c-status-running)'
              : task.column === 'failed' ? 'var(--c-status-failed)'
              : task.column === 'done' ? 'var(--c-status-done)'
              : task.column === 'review' ? 'var(--c-status-review)'
              : 'var(--c-text-3)'
          }} />
          {task.agent}
        </span>
        {task.running ? (
          <>
            <div className="card-progress"><span style={{ width: `${task.progress}%` }} /></div>
            <span className="card-time">{Math.round(task.progress)}%</span>
          </>
        ) : task.column === 'failed' ? (
          <span className="card-time" style={{ color: 'var(--c-status-failed)' }}>halted</span>
        ) : task.column === 'done' ? (
          <span className="card-time s-done"><Icon name="check" size={11} /></span>
        ) : null}
      </div>

      <div className="card-meta">
        <span className="meta-item"><Icon name="database" size={10} /><b>db:</b>
          <span className={task.affectsDb ? 'meta-yes' : 'meta-no'}>{task.affectsDb ? 'yes' : 'no'}</span>
        </span>
        <span className="meta-item"><Icon name="shield" size={10} /><b>approval:</b>
          <span className={task.requiresApproval ? 'meta-required' : 'meta-no'}>
            {task.requiresApproval ? 'required' : 'no'}
          </span>
        </span>
        <span className="meta-item"><Icon name="branch" size={10} /><b>{task.version}</b></span>
      </div>

      {task.column === 'failed' && task.error && (
        <div style={{
          fontFamily: 'var(--font-mono)', fontSize: 10.5,
          color: 'var(--c-status-failed)',
          background: 'var(--c-status-failed-bg)',
          border: '1px solid color-mix(in oklch, var(--c-status-failed) 25%, var(--c-line))',
          padding: '6px 8px', borderRadius: 6, lineHeight: 1.4
        }}>
          <Icon name="alert" size={10} /> {task.error}
        </div>
      )}

      <div className="card-actions" onClick={e => e.stopPropagation()}>
        {task.column === 'backlog' && act.transition && (
          <button className="card-action" type="button" onClick={() => act.transition(task.id, 'ready')}><Icon name="check" size={11} /> Ready</button>
        )}
        {task.column === 'ready' && act.transition && (
          <button className="card-action" type="button" onClick={() => act.transition(task.id, 'running')}><Icon name="play" size={11} /> Run</button>
        )}
        {task.column === 'running' && act.transition && (
          <button className="card-action" type="button" onClick={() => act.transition(task.id, 'review')}><Icon name="log" size={11} /> Review</button>
        )}
        {showRetry && act.transition && <button className="card-action retry" type="button" onClick={() => act.transition(task.id, 'ready')}><Icon name="rotate" size={11} /> Retry</button>}
        {showApprove && act.approve && <button className="card-action approve" type="button" onClick={() => act.approve(task.id)}><Icon name="check" size={11} /> Approve</button>}
        {showRollback && <button className="card-action rollback" type="button" disabled><Icon name="rotate" size={11} /> Rollback</button>}
        <button className="card-action" type="button" style={{ marginLeft: 'auto' }} onClick={onClick}>
          <Icon name="open" size={11} /> Details
        </button>
      </div>
    </article>
  );
}

function Column({ column, tasks, projectsById, agentsById, selectedId, onSelect, animMap, actions }) {
  return (
    <section className="column">
      <header className="column-header">
        <span className={`col-status-bar s-${column.status}`} />
        <span className="column-name">{column.name}</span>
        <span className="column-count">{tasks.length}</span>
        <div className="column-actions">
          <button className="icon-btn" style={{ width: 22, height: 22 }} type="button" title="Filter">
            <Icon name="filter" size={12} />
          </button>
          <button className="icon-btn" style={{ width: 22, height: 22 }} type="button" title="Add">
            <Icon name="plus" size={12} />
          </button>
        </div>
      </header>
      <div className="col-list">
        {tasks.length === 0 ? (
          <div className="empty">no tasks</div>
        ) : tasks.map(t => (
          <TaskCard
            key={t.id}
            task={t}
            project={projectsById[t.project]}
            agent={agentsById[t.agent]}
            selected={selectedId === t.id}
            animState={animMap[t.id]}
            onClick={() => onSelect(t.id)}
            actions={actions}
          />
        ))}
      </div>
    </section>
  );
}

function Board({ tasks, onSelect, selectedId, animMap, actions }) {
  const { COLUMNS, PROJECTS, AGENTS } = window.ORC_DATA;
  const projectsById = Object.fromEntries((PROJECTS || []).map(p => [p.id, p]));
  const agentsById = Object.fromEntries((AGENTS || []).map(a => [a.id, a]));

  return (
    <div className="board">
      {(COLUMNS || []).map(col => (
        <Column
          key={col.id}
          column={col}
          tasks={tasks.filter(t => t.column === col.id)}
          projectsById={projectsById}
          agentsById={agentsById}
          selectedId={selectedId}
          onSelect={onSelect}
          animMap={animMap}
          actions={actions}
        />
      ))}
    </div>
  );
}

/* ---------------- Detail panel ---------------- */

const SAMPLE_LOGS = [
  { time: '00:14:01.221', level: 'info', msg: 'Acquired lock on tenant=helio.prod' },
  { time: '00:14:01.498', level: 'info', msg: 'Resolved migration plan: 3 ops, ~14m est.' },
  { time: '00:14:02.012', level: 'info', msg: 'Snapshotted users (12,438,221 rows) → s3://hl-bk/2026-05-04T00-14' },
  { time: '00:14:02.880', level: 'ok',   msg: 'Snapshot integrity verified (sha256 matches manifest)' },
  { time: '00:14:08.402', level: 'info', msg: 'CREATE TABLE users_new PARTITION BY HASH (org_id) PARTITIONS 12' },
  { time: '00:14:09.140', level: 'info', msg: 'Backfill batch 1/12 → 1,036,518 rows in 642ms' },
  { time: '00:14:09.802', level: 'warn', msg: 'Slow rebuild on idx_users_email (est. 4m, ~3x baseline)' },
  { time: '00:14:14.011', level: 'info', msg: 'Backfill batch 4/12 → 1,041,002 rows in 681ms' },
  { time: '00:14:18.553', level: 'info', msg: 'Switching read traffic to users_new in shadow mode' },
  { time: '00:14:18.640', level: 'ok',   msg: 'Shadow read parity: 100.000% across 50k probe queries' },
];

const SAMPLE_DIFF = [
  { kind: 'hunk', n: '', mark: '', text: '@@ migrations/2026_04_28_partition_users.sql' },
  { kind: 'ctx',  n: '12', mark: ' ', text: '-- Phase 2: cutover to partitioned schema' },
  { kind: 'del',  n: '13', mark: '-', text: 'CREATE TABLE users (' },
  { kind: 'del',  n: '14', mark: '-', text: '  id UUID PRIMARY KEY,' },
  { kind: 'del',  n: '15', mark: '-', text: '  org_id UUID NOT NULL,' },
  { kind: 'add',  n: '13', mark: '+', text: 'CREATE TABLE users (' },
  { kind: 'add',  n: '14', mark: '+', text: '  id UUID NOT NULL,' },
  { kind: 'add',  n: '15', mark: '+', text: '  org_id UUID NOT NULL,' },
  { kind: 'add',  n: '16', mark: '+', text: '  PRIMARY KEY (org_id, id)' },
  { kind: 'add',  n: '17', mark: '+', text: ') PARTITION BY HASH (org_id) PARTITIONS 12;' },
  { kind: 'ctx',  n: '18', mark: ' ', text: '' },
  { kind: 'ctx',  n: '19', mark: ' ', text: 'CREATE INDEX idx_users_email ON users (email);' },
  { kind: 'del',  n: '20', mark: '-', text: 'CREATE INDEX idx_users_org ON users (org_id);' },
  { kind: 'add',  n: '20', mark: '+', text: '-- idx_users_org redundant after partition key' },
];

const SAMPLE_STEPS = [
  { state: 'done',    title: 'Plan validated',           meta: ['planner-agent', '0.4s'] },
  { state: 'done',    title: 'Snapshot created',         meta: ['migrator-agent', '0.9s', '1.2 GB'] },
  { state: 'done',    title: 'Schema applied (shadow)',  meta: ['migrator-agent', '5.3s'] },
  { state: 'running', title: 'Backfilling 12 partitions', meta: ['migrator-agent', '7/12 shards · 4m 12s'] },
  { state: 'pending', title: 'Cutover read traffic',     meta: ['sentinel-agent', 'queued'] },
  { state: 'pending', title: 'Cutover write traffic',    meta: ['sentinel-agent', 'queued'] },
  { state: 'pending', title: 'Drop legacy table',        meta: ['migrator-agent', 'awaits approval'] },
];

function Logs() {
  return (
    <div className="logs">
      {SAMPLE_LOGS.map((l, i) => (
        <div className="log-line" key={i}>
          <span className="log-time">{l.time}</span>
          <span className={`log-level ${l.level}`}>{l.level}</span>
          <span className="log-msg">{l.msg}</span>
        </div>
      ))}
    </div>
  );
}

function Diff() {
  return (
    <div className="diff">
      <div className="diff-head">
        <Icon name="diff" size={12} />
        <span>migrations/2026_04_28_partition_users.sql</span>
        <span style={{ marginLeft: 'auto', display: 'flex', gap: 8 }}>
          <span style={{ color: 'var(--c-status-done)' }}>+6</span>
          <span style={{ color: 'var(--c-status-failed)' }}>−4</span>
        </span>
      </div>
      {SAMPLE_DIFF.map((line, i) => (
        <div key={i} className={`diff-line ${line.kind === 'add' ? 'add' : line.kind === 'del' ? 'del' : line.kind === 'hunk' ? 'hunk' : ''}`}>
          {line.kind === 'hunk' ? (
            <div className="diff-content" style={{ gridColumn: '1 / -1', padding: '4px 10px' }}>{line.text}</div>
          ) : (
            <>
              <div className="diff-num">{line.n}</div>
              <div className="diff-mark">{line.mark}</div>
              <div className="diff-content">{line.text}</div>
            </>
          )}
        </div>
      ))}
    </div>
  );
}

function Steps() {
  return (
    <div className="steps">
      {SAMPLE_STEPS.map((step, i) => (
        <div key={i} className={`step ${step.state}`}>
          <div className="step-mark">
            {step.state === 'done' ? <Icon name="check" size={11} /> :
             step.state === 'failed' ? <Icon name="x" size={11} /> :
             step.state === 'running' ? <span className="dot" /> :
             i + 1}
          </div>
          <div className="step-body">
            <div className="step-title">{step.title}</div>
            <div className="step-meta">
              {step.meta.map((m, j) => <span key={j}>{m}</span>)}
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

// audit entries -> log lines
function AuditLog({ audit }) {
  if (!audit || audit.length === 0) return <div className="empty">no audit entries yet</div>;
  const levelOf = (a) => a.action === 'reject' || a.to_status === 'failed' ? 'err'
    : a.action === 'approve' || a.to_status === 'done' ? 'ok'
    : a.to_status === 'review' ? 'warn' : 'info';
  return (
    <div className="logs">
      {audit.map(a => (
        <div className="log-line" key={a.id}>
          <span className="log-time">{new Date(a.created_at).toLocaleTimeString()}</span>
          <span className={`log-level ${levelOf(a)}`}>{a.action}</span>
          <span className="log-msg">
            {a.actor}
            {a.from_status || a.to_status ? ` · ${a.from_status || '∅'} → ${a.to_status || '∅'}` : ''}
          </span>
        </div>
      ))}
    </div>
  );
}

function ResultDiff({ result }) {
  const diff = result?.diff;
  if (!diff) return <div className="empty">no diff — agent has not produced a change yet</div>;
  if (typeof diff === 'string') {
    return <div className="diff"><pre style={{ margin: 0, padding: '8px 10px', fontFamily: 'var(--font-mono)', fontSize: 11, whiteSpace: 'pre-wrap' }}>{diff}</pre></div>;
  }
  return <div className="diff"><pre style={{ margin: 0, padding: '8px 10px', fontFamily: 'var(--font-mono)', fontSize: 11, whiteSpace: 'pre-wrap' }}>{JSON.stringify(diff, null, 2)}</pre></div>;
}

function LiveLogs({ logs }) {
  const endRef = React.useRef(null);
  React.useEffect(() => { endRef.current?.scrollIntoView({ block: 'end' }); }, [logs]);
  if (!logs || logs.length === 0) return <div className="empty">no log output yet</div>;
  return (
    <div className="logs">
      {logs.map(l => (
        <div className="log-line" key={l.id}>
          <span className="log-time">{new Date(l.created_at).toLocaleTimeString()}</span>
          <span className={`log-level ${l.level}`}>{l.level}</span>
          <span className="log-msg">{l.msg}</span>
        </div>
      ))}
      <div ref={endRef} />
    </div>
  );
}

function DetailPanel({ task, onClose, actions, logs }) {
  const [tab, setTab] = React.useState('live');
  const [detail, setDetail] = React.useState(null);
  const open = !!task;
  const act = actions || {};

  // fetch real detail (audit + allowedNext) when task changes
  React.useEffect(() => {
    if (!task) { setDetail(null); return; }
    let live = true;
    window.ORC_API.getTask(task.id).then(d => { if (live) setDetail(d); }).catch(() => {});
    return () => { live = false; };
  }, [task && task.id, task && task.column]);

  if (!task) {
    return <aside className="detail-panel" />;
  }

  const { PROJECTS } = window.ORC_DATA;
  const project = (PROJECTS || []).find(p => p.id === task.project) || { color: 'var(--c-text-3)', name: task.project };
  const typeLabel = {
    'module-install': 'Module Install',
    'update': 'Update',
    'agent-task': 'Agent Task',
    'system-task': 'System Task',
  }[task.type] || task.type;

  const audit = detail?.audit || [];
  const allowedNext = detail?.allowedNext || [];
  const result = detail?.task?.result;

  return (
    <aside className={`detail-panel ${open ? 'open' : ''}`}>
      <div className="detail-head">
        <div className="detail-head-row">
          <span className="detail-id">{task.id}</span>
          <span className={`badge ${task.column === 'failed' ? 'failed' : task.column === 'done' ? 'live' : task.column === 'review' ? 'review' : 'idle'}`}>
            {task.column}
          </span>
          <button className="icon-btn detail-close" type="button" onClick={onClose}>
            <Icon name="close" size={14} />
          </button>
        </div>
        <h2 className="detail-title">{task.title}</h2>
        <div className="detail-meta-row">
          <span className="chip chip-mono"><Swatch color={project.color} size={8} />{project.name}</span>
          <span className="chip chip-mono">{typeLabel}</span>
          <span className="chip chip-mono"><Icon name="cpu" size={11} />{task.agent}</span>
          {task.version && <span className="chip chip-mono"><Icon name="branch" size={11} />{task.version}</span>}
          <span className="chip chip-mono"><Icon name="flag" size={11} />{task.priority}</span>
        </div>
        <div style={{ display: 'flex', gap: 6, marginTop: 12, flexWrap: 'wrap' }}>
          {task.column === 'review' && act.approve && (
            <button className="btn primary" type="button" onClick={() => act.approve(task.id)}><Icon name="check" size={12} />Approve → Done</button>
          )}
          {task.column === 'review' && act.reject && (
            <button className="btn danger" type="button" onClick={() => act.reject(task.id)}><Icon name="x" size={12} />Reject</button>
          )}
          {/* generic transitions (drives loop manually until worker exists) */}
          {allowedNext.filter(s => !(task.column === 'review' && (s === 'done' || s === 'failed'))).map(s => (
            <button key={s} className="btn ghost" type="button" onClick={() => act.transition && act.transition(task.id, s)}>
              <Icon name="play" size={12} />→ {s}
            </button>
          ))}
        </div>
      </div>

      <div className="detail-tabs">
        {[
          { id: 'live', label: 'Logs', icon: 'log' },
          { id: 'logs', label: 'Audit', icon: 'steps' },
          { id: 'diff', label: 'Result', icon: 'diff' },
        ].map(t => (
          <button
            key={t.id}
            className={`detail-tab ${tab === t.id ? 'active' : ''}`}
            onClick={() => setTab(t.id)}
            type="button"
          >
            <Icon name={t.icon} size={11} style={{ marginRight: 4, verticalAlign: -1 }} />
            {t.label}
          </button>
        ))}
      </div>

      <div className="detail-body">
        {tab === 'live' && <>
          <h5 className="section-title">Live tail · stdout</h5>
          <LiveLogs logs={logs} />
        </>}
        {tab === 'logs' && <>
          <h5 className="section-title">Audit trail · {audit.length} entries</h5>
          <AuditLog audit={audit} />
        </>}
        {tab === 'diff' && <>
          <h5 className="section-title">Agent result</h5>
          <ResultDiff result={result} />
        </>}
      </div>
    </aside>
  );
}

window.Board = Board;
window.DetailPanel = DetailPanel;
