import React          from "https://esm.sh/react@19/";
import { createRoot } from "https://esm.sh/react-dom@19/client/";
import { pipeline }   from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers';

import {initState,reducer} from './reducer.js';
import BusySignal from './busy.js';


function App () {
  const [state, dispatch] = React.useReducer(reducer, initState());
  const setData = (key,data) => dispatch({type:'setData', key:key, data:data});

  async function goOn() {
    if (state.prompt.length<1) {
      setData('error', 'Please enter a prompt.');
      setData('output', '');
      return;
    }
    dispatch({type:'goOn'});

    let textGen=null;

    let t0 = performance.now();
    try {
      textGen = await pipeline('text-generation', state.model, {device:'webgpu'});
    } catch(err) {
      dispatch({type:'done', error:err.toString()});
    }
    
    if (typeof textGen === 'function') {
      textGen(state.prompt, {
	max_new_tokens: state.tokens,
	temperature: state.temp,
	do_sample: state.do_sample,
      })
	.then(output=>{
	  let t1 = performance.now();
	  dispatch({type:'done', output:output[0].generated_text, time:(t1-t0)});
	})
	.catch(err=>dispatch({type:'done', error:err.toString()}))
    } else {
      dispatch({type:'done', error:"Couldn't get a text-generation function."});
    }
  } // goOn

  return (
    <>
      {state.error && <h3 className='error'>{state.error}</h3>}

      <p className='input flexRow'>

	<label>Model: 
	  <select onChange={e=>setData('model',e.target.value)}>
	    {state.models.map(x=>
	      <option key={x} value={x}>{x}</option>
	    )}
	  </select>
	</label>

	<label>Model: 
	  <input style={{width:'20em'}} value={state.model} onChange={e=>setData('model',e.target.value)} />
	</label>

	<label className='checkbox flexInput'>
          Sample:<input type="checkbox" defaultChecked={state.do_sample}
			onChange={e=>setData('do_sample', e.target.checked)} />
	</label>
	
      </p>
      
      <div id="sliders" className='flexRow'>
	<div>
	  <label>Max tokens:
	    <input type="range" value={state.tokens} min="1" max="200"
		   onChange={e=>setData('tokens', e.target.value)} />
	  </label>
	  {state.tokens}
	</div>

	<div className=''>
	  <label>Temperature:
	    <input type="range" value={state.temp} min="0" max="2" step=".1"
		   onChange={e=>setData('temp', e.target.value)} />
	  </label>
	  {state.temp}
	</div>
      </div>

      <p>
	<label>Prompt:<br />
	  <textarea value={state.prompt} style={{width:'30em', height:'10em'}}
		    onChange={e=>setData('prompt', e.target.value)} />
	</label>
      </p>
      
      {!state.busy && <button onClick={goOn}>Go on...</button>}

      {state.busy && <p className='busyDIV'>Working... <BusySignal  /></p>}

    <div id='outputs'>
      {state.outputs.map(x=>
	<table>
	  <tbody>
	    <tr><th>Model</th><td>{x.model}</td></tr>
	    <tr><th>Tokens</th><td>{x.tokens}</td></tr>
	    <tr><th>Temp</th><td>{x.temp}</td></tr>
	    <tr><th>Sample</th><td>{x.do_sample}</td></tr>
	    <tr><th>Prompt</th><td>{x.prompt}</td></tr>
	    <tr><th>Output</th><td>{x.output}</td></tr>
	    <tr><th>Time</th><td>{(x.time/1000).toFixed(2)} seconds</td></tr>
	  </tbody>
	</table>
      )}
    </div>
       
    </>
  )
}

createRoot(document.getElementById('root')).render( <React.StrictMode> <App/> </React.StrictMode> );
