/* PM-198 Tool pages - one shared template at #/tools/<id>: title + plain
   description, parameter controls (only what the tool needs), Run, full-width
   result area, last-run provenance line. Saved queries + export run through
   /api/tools/query (server binds params); health-probe hits /api/platform-health
   ?fresh=1; reflash is the PM-199 placeholder; kiosk relaunches the wall display. */

const FRIENDLY_COL = { _time:'Time', _value:'Value', gateway_id:'Gateway', node:'Device', sensor_type:'Channel', site_id:'Site' };

function ToolParamControls({ def, params, setParams }){
  return <div style={{display:'flex',gap:10,flexWrap:'wrap',alignItems:'flex-end'}}>
    {def.params.map(p=>{
      const v=params[p.name]||'';
      const set=val=>setParams(Object.assign({},params,{[p.name]:val}));
      const lab=<div style={{fontFamily:O.mono,fontSize:9.5,fontWeight:700,textTransform:'uppercase',letterSpacing:'.05em',color:O.fg3,marginBottom:4}}>{p.label}{p.required?' *':''}</div>;
      const sel={padding:'8px 10px',borderRadius:9,border:`1px solid ${O.line}`,background:'#fff',fontFamily:O.sans,fontSize:12.5,color:O.fg1,outline:'none'};
      if(p.type==='device') return <div key={p.name}>{lab}<select value={v} onChange={e=>set(e.target.value)} style={sel}>
        <option value="">{p.required?'Select a device':'All devices'}</option>
        {DEVICES.map(d=><option key={d.id} value={d.node}>{d.name} ({d.node})</option>)}
      </select></div>;
      if(p.type==='range') return <div key={p.name}>{lab}<select value={v||p.default||'24h'} onChange={e=>set(e.target.value)} style={sel}>
        <option value="24h">Last 24h</option><option value="7d">Last 7d</option>
      </select></div>;
      return null;
    })}
  </div>;
}

function ToolResultTable({ result }){
  if(!result) return null;
  if(result.rowCount===0) return <div style={{fontFamily:O.sans,fontSize:12.5,color:O.fg3,padding:'14px 0'}}>No rows returned.</div>;
  return <div style={{overflowX:'auto',marginTop:12}}>
    <table style={{width:'100%',borderCollapse:'collapse'}}>
      <thead><tr style={{background:O.sunken}}>{result.columns.map(c=><th key={c} style={{padding:'8px 10px',fontFamily:O.mono,fontSize:10,fontWeight:700,textTransform:'uppercase',letterSpacing:'.05em',color:O.fg3,textAlign:'left'}}>{FRIENDLY_COL[c]||c}</th>)}</tr></thead>
      <tbody>{result.rows.map((r,i)=><tr key={i} style={{borderTop:`1px solid ${O.line}`}}>
        {result.columns.map(c=><td key={c} style={{padding:'7px 10px',fontFamily:O.mono,fontSize:11.5,color:O.fg1}}>{r[c]==null?'-':(typeof r[c]==='number'?(Math.round(r[c]*100)/100):String(r[c]))}</td>)}
      </tr>)}</tbody>
    </table>
  </div>;
}

function ToolPage({ id }){
  const [params,setParams]=React.useState({});
  const [running,setRunning]=React.useState(false);
  const [result,setResult]=React.useState(null);
  const [err,setErr]=React.useState(null);
  const [ranAt,setRanAt]=React.useState(null);
  const [cat,setCat]=React.useState(window.TOOL_CATALOG);
  React.useEffect(()=>{ if(!cat) window.loadToolCatalog().then(setCat).catch(e=>setErr(String(e.message||e))); },[]);
  const def=(cat||[]).find(t=>t.id===id);
  if(!cat&&!err) return <div style={{fontFamily:O.mono,fontSize:12,color:O.fg3}}>Loading tool catalog...</div>;
  if(!def) return <div><PageTitle title="Unknown tool"/><div style={{fontFamily:O.sans,fontSize:13,color:O.fg2}}>No tool with id <span style={{fontFamily:O.mono}}>{String(id)}</span> in the catalog.{err?' ('+err+')':''}</div></div>;

  // Effective params: defaults fill anything unset.
  const eff={}; def.params.forEach(p=>{ const v=params[p.name]||p.default||''; if(v) eff[p.name]=v; });
  const missing=def.params.some(p=>p.required&&!eff[p.name]);

  const run=()=>{
    setRunning(true); setErr(null); setRanAt(null); // stale provenance never outlives a failed run
    const go = id==='health-probe' ? window.loadPlatformHealth(true).then(p=>({ probe:p })) : window.runTool(id, eff);
    go.then(r=>{ setResult(r); setRanAt(new Date()); })
      .catch(e=>{ setResult(null); setErr(String(e.message||e)); })
      .finally(()=>setRunning(false));
  };

  return <div>
    <PageTitle title={def.title} sub={def.description}/>
    {def.kind==='placeholder'
      ? <Card><div style={{display:'flex',alignItems:'center',gap:12,padding:'18px 6px'}}><OIcon name="zap" size={26} color={O.faint}/><div><div style={{fontFamily:O.sans,fontWeight:700,fontSize:14.5,color:O.fg1}}>Coming soon</div><div style={{fontFamily:O.sans,fontSize:12.5,color:O.fg3,marginTop:3}}>Web-triggered bench reflash arrives with the bench agent (PM-199). This page will carry every step, status, and completion message for the job.</div></div></div></Card>
      : def.kind==='launcher'
      ? <Card><button onClick={()=>window.open(location.pathname+location.search+'#/kiosk','_blank')} className="clk" style={{display:'inline-flex',alignItems:'center',gap:8,background:O.azure,border:'none',borderRadius:9,padding:'10px 22px',cursor:'pointer',fontFamily:O.sans,fontWeight:700,fontSize:13,color:'#fff'}}><OIcon name="monitor" size={16}/>Open kiosk display</button></Card>
      : <Card>
        <div style={{display:'flex',gap:12,flexWrap:'wrap',alignItems:'flex-end',justifyContent:'space-between'}}>
          <ToolParamControls def={def} params={params} setParams={setParams}/>
          <div style={{display:'flex',gap:8}}>
            {def.csv&&<a href={missing?undefined:window.toolCsvUrl(id, eff)} download className="clk" style={{display:'inline-flex',alignItems:'center',gap:7,border:`1px solid ${O.lineS}`,background:'#fff',borderRadius:9,padding:'9px 16px',cursor:missing?'not-allowed':'pointer',fontFamily:O.sans,fontWeight:700,fontSize:12.5,color:missing?O.faint:O.fg1,textDecoration:'none',opacity:missing?0.5:1}} onClick={e=>{ if(missing) e.preventDefault(); }}><OIcon name="download" size={14}/>Export</a>}
            <button onClick={run} disabled={running||missing} className="clk" style={{display:'inline-flex',alignItems:'center',gap:7,background:missing?O.faint:O.azure,border:'none',borderRadius:9,padding:'9px 20px',cursor:missing?'not-allowed':'pointer',fontFamily:O.sans,fontWeight:700,fontSize:12.5,color:'#fff'}}><OIcon name="play" size={14}/>{running?'Running...':'Run'}</button>
          </div>
        </div>
        {err&&<div style={{marginTop:12,padding:'10px 12px',border:`1px solid ${O.crit}`,borderRadius:9,fontFamily:O.sans,fontSize:12.5,color:O.crit}}>Run failed: {err}</div>}
        {result&&result.probe&&<div style={{marginTop:12}}>{result.probe.services.map(s=>
          <div key={s.id} style={{display:'flex',alignItems:'center',gap:10,padding:'9px 11px',border:`1px solid ${O.line}`,borderRadius:9,marginBottom:7}}>
            <span style={{width:9,height:9,borderRadius:'50%',background:s.ok?O.leaf:O.crit}}/>
            <div style={{flex:1,fontFamily:O.sans,fontWeight:700,fontSize:12.5,color:O.fg1}}>{s.label}</div>
            <span style={{fontFamily:O.mono,fontSize:11,color:s.ok?O.fg2:O.crit}}>{s.ok?'UP':'DOWN'} · {s.latencyMs!=null?s.latencyMs+' ms':'-'} · {s.detail}</span>
          </div>)}</div>}
        {result&&!result.probe&&<ToolResultTable result={result}/>}
        {ranAt&&<div style={{fontFamily:O.mono,fontSize:10.5,color:O.fg3,marginTop:12}}>Last run {ranAt.toLocaleTimeString()}{result&&result.rowCount!=null?` · ${result.rowCount} rows`:''} · params {JSON.stringify(eff)}</div>}
      </Card>}
  </div>;
}

/* PM-198 Overview teaser: full-width quadrant-preview card, bottom of Overview.
   THREE static mini-tiles showing data Overview does NOT already display
   (PLATFORM service dots / DATA QUALITY 24h continuity / READY TO ACT).
   The whole card is ONE click target into Mission Control; owner exception:
   the Ready-to-Act buttons are live links to their Tool pages. */
function MissionTeaser({ onMission, onTool }){
  const [,setTick]=React.useState(0);
  React.useEffect(()=>{ let on=true;
    const load=()=>{ Promise.all([window.loadPlatformHealth().catch(()=>{}),window.loadToolCatalog().catch(()=>{})]).then(()=>{ if(on) setTick(t=>t+1); }); };
    load(); const id=setInterval(load,60000);
    return ()=>{ on=false; clearInterval(id); };
  },[]);
  const plat=window.PLATFORM_HEALTH, q=window.QUALITY24H;
  const acts=(window.TOOL_CATALOG||[]).filter(t=>t.kind==='saved-query'||t.kind==='utility').slice(0,4);
  const tile={border:`1px solid ${O.line}`,borderRadius:10,padding:'8px 12px',flex:1,minWidth:0};
  const tl=l=><div style={{fontFamily:O.mono,fontSize:11.5,fontWeight:700,letterSpacing:'.06em',textTransform:'uppercase',color:O.fg3,marginBottom:7}}>{l}</div>;
  return <div role="button" tabIndex={0} onClick={onMission} onKeyDown={e=>{ if(e.key==='Enter'||e.key===' '){ e.preventDefault(); onMission(); } }} title="Open Mission Control" style={{marginTop:10,cursor:'pointer'}}>
    <Card className="clk">
    <div style={{display:'flex',gap:12,flexWrap:'wrap'}}>
      <div style={tile}>{tl('Data quality')}
        <div style={{fontFamily:O.disp,fontWeight:800,fontSize:32,color:q?(q.gapBuckets===0?O.leaf:O.warn):O.faint,lineHeight:1}}>{q?q.availabilityPct+'%':'-'}</div>
        <div style={{fontFamily:O.mono,fontSize:12.5,color:O.fg3,marginTop:6}}>24h availability</div>
        <div style={{fontFamily:O.mono,fontSize:12.5,color:q&&q.gapBuckets>0?O.warn:O.fg3,marginTop:3}}>{q?q.gapBuckets+' gap bucket'+(q.gapBuckets===1?'':'s'):'-'}</div>
      </div>
      <div style={tile}>{tl('Platform')}
        <div style={{display:'flex',flexDirection:'column',gap:5}}>
          {(plat?plat.services:[{id:'influxdb',label:'InfluxDB'},{id:'grafana',label:'Grafana'},{id:'soracom',label:'Soracom'}]).map(s=>
            <span key={s.id} style={{display:'inline-flex',alignItems:'center',gap:7,fontFamily:O.mono,fontSize:12.5,color:O.fg2}}>
              <span style={{width:7,height:7,borderRadius:'50%',background:plat?(s.ok?O.leaf:O.crit):O.faint}}/>{s.label}{plat&&s.latencyMs!=null?<span style={{color:O.faint}}> {s.latencyMs}ms</span>:null}
            </span>)}
        </div>
      </div>
      <div style={tile}>{tl('Ready to act')}
        <div style={{display:'flex',flexDirection:'column',gap:5}}>
          {acts.length?acts.map(t=>
            <button key={t.id} onClick={e=>{e.stopPropagation();onTool(t.id);}} className="clk" style={{display:'inline-flex',alignItems:'center',gap:6,background:'none',border:'none',cursor:'pointer',padding:0,fontFamily:O.sans,fontWeight:700,fontSize:13.5,color:O.azure,textAlign:'left'}}>
              <OIcon name="play" size={13}/>{t.title}
            </button>):<span style={{fontFamily:O.mono,fontSize:12.5,color:O.faint}}>-</span>}
        </div>
      </div>
    </div>
    </Card>
  </div>;
}
