/* Model Training screen — globale gap-analyse voor het contour fine-tune model.
   Spiegelt tools/export_training.py --stats (endpoint GET /api/training/stats). */

const VLAG_KLEUR = {
  ok:     'var(--color-success)',
  krap:   'var(--color-warning)',
  tekort: 'var(--color-error)',
};
const VLAG_KIND = { ok: 'success', krap: 'warning', tekort: 'danger' };
const VLAG_LABEL = { ok: 'Op orde', krap: 'Krap', tekort: 'Tekort' };

const STATUS_LABEL = {
  ok:                  'Bruikbaar (compleet gereviewd)',
  incompleet_gereviewd:'Nog te reviewen',
  geen_componenten:    'Geen genummerde componenten',
  label_onbepaald:     'Label onbepaald',
  ongeldig_beeldpad:   'Ongeldig beeldpad',
  beeld_ontbreekt:     'Beeld ontbreekt',
};

function TStatCard({ label, value, hint, icon, kind = 'neutral' }) {
  return (
    <div className="bd-stat-card">
      <div className={'bd-stat-icon bd-stat-icon--' + kind}><Icon name={icon} size={18} /></div>
      <div>
        <div className="bd-stat-label">{label}</div>
        <div className="bd-stat-value">{value}</div>
        {hint && <div className="bd-stat-hint">{hint}</div>}
      </div>
    </div>
  );
}

function SubtypeBar({ subtype, n, vlag, signaal, fatsoenlijk, schaalMax }) {
  const kleur = VLAG_KLEUR[vlag] || 'var(--color-border)';
  // Gedeelde schaal: staaflengte = werkelijk aantal t.o.v. de grootste klasse/streefwaarde,
  // zodat de staven onderling vergelijkbaar zijn (echte staafdiagram). Twee referentielijnen
  // tonen signaal- en streefwaarde.
  const pct = Math.round(100 * n / schaalMax);
  const signaalPct = Math.round(100 * signaal / schaalMax);
  const doelPct = Math.round(100 * fatsoenlijk / schaalMax);
  return (
    <div style={{display:'grid', gridTemplateColumns:'140px 1fr 44px', alignItems:'center', gap:'var(--space-3)', padding:'5px 0'}}>
      <span style={{fontSize:'var(--font-size-sm)'}}>{CONTOUR_SUBTYPE_LABEL[subtype] || subtype}</span>
      <div style={{position:'relative', height:16, background:'var(--color-primary-light)', borderRadius:8, overflow:'hidden'}}>
        <div style={{position:'absolute', top:0, bottom:0, left:0, width:pct+'%', background:kleur, borderRadius:8, transition:'width .3s'}} />
        {/* signaal-referentielijn */}
        <div title={`Signaal ${signaal}`} style={{position:'absolute', top:0, bottom:0, left:signaalPct+'%', width:2, background:'var(--text-muted)', opacity:0.4}} />
        {/* streef-referentielijn */}
        <div title={`Streefwaarde ${fatsoenlijk}`} style={{position:'absolute', top:0, bottom:0, left:doelPct+'%', width:2, background:'var(--text-muted)', opacity:0.7}} />
      </div>
      <span className="bd-mono" style={{fontSize:'var(--font-size-sm)', textAlign:'right'}}>
        <strong>{n}</strong>
      </span>
    </div>
  );
}

function SchermTraining() {
  const [stats, setStats] = useState(null);
  const [laden, setLaden] = useState(true);
  const [fout, setFout] = useState(false);
  const [dsStatus, setDsStatus] = useState(null);
  const [dsBezig, setDsBezig] = useState(false);

  async function laad() {
    setLaden(true); setFout(false);
    try {
      const r = await fetch(`${API}/training/stats`);
      if (!r.ok) throw new Error('status ' + r.status);
      setStats(await r.json());
    } catch (e) {
      setFout(true);
    }
    setLaden(false);
  }
  useEffect(() => { laad(); }, []);

  // Crop-dataset bouwen + voortgang pollen.
  function pollDataset() {
    fetch(`${API}/training/dataset/status`)
      .then(r => r.json())
      .then(s => {
        setDsStatus(s);
        if (s.status === 'bezig') { setDsBezig(true); setTimeout(pollDataset, 2000); }
        else setDsBezig(false);
      })
      .catch(() => setDsBezig(false));
  }
  useEffect(() => { pollDataset(); }, []);

  async function bouwDataset() {
    setDsBezig(true);
    try { await fetch(`${API}/training/dataset/bouw`, { method: 'POST' }); } catch (e) {}
    pollDataset();
  }

  return (
    <div className="bd-page">
      <div className="bd-page-head">
        <div>
          <h1>Model Training</h1>
          <p>Hoever staat de contour-trainingsdata? Gebaseerd op mens-gereviewde clusters, over alle gemeenten.</p>
        </div>
        <div className="bd-page-head-actions">
          <Btn kind="primary" icon="database" onClick={bouwDataset} disabled={dsBezig}>
            {dsBezig
              ? `Klaarzetten… ${dsStatus ? dsStatus.verwerkt : 0}/${dsStatus ? dsStatus.totaal : 0}`
              : 'Trainingsset klaarzetten'}
          </Btn>
          <Btn kind="ghost" icon="refresh-cw" onClick={laad}>Verversen</Btn>
        </div>
      </div>

      {laden ? (
        <Empty icon="loader" title="Laden…" />
      ) : fout ? (
        <Empty icon="alert-triangle" title="Kon training-statistiek niet laden" hint="Controleer of de server draait." />
      ) : !stats ? null : (
        <>
          <div className="bd-stats-grid">
            <TStatCard label="Bruikbare voorbeelden" value={fmtNum(stats.bruikbaar)} hint="compleet gereviewd" icon="check-circle-2" kind="success" />
            <TStatCard label="Contour-resultaten totaal" value={fmtNum(stats.contour_totaal)} icon="layers" />
            <TStatCard label="Nog te reviewen" value={fmtNum(stats.nog_te_reviewen)} hint="resultaten met open componenten" icon="list-checks" kind={stats.nog_te_reviewen > 0 ? 'warning' : 'neutral'} />
            <TStatCard label="Kleinste balans-klasse" value={fmtNum(stats.balans.kleinste_klasse)} hint={VLAG_LABEL[stats.balans.oordeel]} icon="scale" kind={VLAG_KIND[stats.balans.oordeel]} />
          </div>

          {dsStatus && dsStatus.status !== 'leeg' && (() => {
            const drem = stats ? stats.drempels : { signaal: 50, fatsoenlijk: 150 };
            const entries = Object.entries(dsStatus.per_klasse || {});
            const maxN = Math.max(0, ...entries.map(([, n]) => n));
            const schaalMax = Math.max(drem.fatsoenlijk, maxN);
            const vlagVan = n => n >= drem.fatsoenlijk ? 'ok' : n >= drem.signaal ? 'krap' : 'tekort';
            const over = dsStatus.overgeslagen || {};
            const overTotaal = Object.values(over).reduce((a, b) => a + b, 0);
            return (
              <div className="bd-card">
                <div style={{display:'flex', justifyContent:'space-between', alignItems:'baseline', marginBottom:'var(--space-4)'}}>
                  <h2 style={{margin:0, fontSize:'var(--font-size-md)', fontWeight:600}}>Crop-trainingsset</h2>
                  <span style={{fontSize:'var(--font-size-xs)', color:'var(--text-muted)'}}>
                    {dsStatus.status === 'klaar'
                      ? `${dsStatus.verwerkt} crops · ${dsStatus.klaar_op}`
                      : dsStatus.status === 'fout' ? 'Fout' : `Bezig… ${dsStatus.verwerkt}/${dsStatus.totaal}`}
                  </span>
                </div>
                {dsStatus.status === 'fout' && (
                  <div style={{color:'var(--color-error)', marginBottom:'var(--space-3)'}}>Fout: {dsStatus.fout}</div>
                )}
                {[...entries].sort((a, b) => b[1] - a[1]).map(([k, n]) => (
                  <SubtypeBar key={k} subtype={k} n={n} vlag={vlagVan(n)}
                    signaal={drem.signaal} fatsoenlijk={drem.fatsoenlijk} schaalMax={schaalMax} />
                ))}
                {dsStatus.status === 'klaar' && (
                  <div style={{display:'flex', gap:'var(--space-4)', marginTop:'var(--space-4)', fontSize:'var(--font-size-xs)', color:'var(--text-muted)'}}>
                    <span>Map: <span className="bd-mono">{dsStatus.out_dir}</span></span>
                    {overTotaal > 0 && <span>Overgeslagen: {overTotaal}</span>}
                  </div>
                )}
              </div>
            );
          })()}

          <div className="bd-card">
            <div style={{display:'flex', justifyContent:'space-between', alignItems:'baseline', marginBottom:'var(--space-4)'}}>
              <h2 style={{margin:0, fontSize:'var(--font-size-md)', fontWeight:600}}>Gereviewde voorbeelden per subtype</h2>
              <span style={{fontSize:'var(--font-size-xs)', color:'var(--text-muted)'}}>
                streefwaarde {stats.drempels.fatsoenlijk} · signaal {stats.drempels.signaal}
              </span>
            </div>
            {(() => {
              const maxN = Math.max(0, ...stats.per_subtype.map(s => s.n));
              const schaalMax = Math.max(stats.drempels.fatsoenlijk, maxN);
              return [...stats.per_subtype].sort((a, b) => b.n - a.n).map(s => (
                <SubtypeBar key={s.subtype} subtype={s.subtype} n={s.n} vlag={s.vlag}
                  signaal={stats.drempels.signaal} fatsoenlijk={stats.drempels.fatsoenlijk} schaalMax={schaalMax} />
              ));
            })()}
            <div style={{display:'flex', gap:'var(--space-4)', marginTop:'var(--space-4)', fontSize:'var(--font-size-xs)', color:'var(--text-muted)'}}>
              <span><span style={{display:'inline-block',width:10,height:10,borderRadius:3,background:'var(--color-success)',marginRight:5}} />Op orde (≥{stats.drempels.fatsoenlijk})</span>
              <span><span style={{display:'inline-block',width:10,height:10,borderRadius:3,background:'var(--color-warning)',marginRight:5}} />Krap (≥{stats.drempels.signaal})</span>
              <span><span style={{display:'inline-block',width:10,height:10,borderRadius:3,background:'var(--color-error)',marginRight:5}} />Tekort</span>
              <span><span style={{display:'inline-block',width:2,height:11,background:'var(--text-muted)',marginRight:5,verticalAlign:'middle'}} />Lijnen = signaal ({stats.drempels.signaal}) &amp; streef ({stats.drempels.fatsoenlijk})</span>
            </div>
          </div>

          <div className="bd-grid-2">
            <div className="bd-card">
              <h2 style={{margin:'0 0 var(--space-4)', fontSize:'var(--font-size-md)', fontWeight:600}}>Detectie-balans</h2>
              <p style={{margin:'0 0 var(--space-4)', fontSize:'var(--font-size-xs)', color:'var(--text-muted)'}}>
                Binair doel: échte contourafwijking (bouwwerk) vs. geen afwijking. Gebalanceerd (~50/50) is ideaal.
              </p>
              {(() => {
                const a = stats.balans.afwijking, g = stats.balans.geen, tot = a + g || 1;
                return (
                  <>
                    <div style={{display:'flex', height:20, borderRadius:6, overflow:'hidden', border:'1px solid var(--color-border)'}}>
                      <div style={{width:(100*a/tot)+'%', background:'var(--color-primary)'}} title={`Afwijking ${a}`} />
                      <div style={{width:(100*g/tot)+'%', background:'var(--color-border)'}} title={`Geen ${g}`} />
                    </div>
                    <div style={{display:'flex', justifyContent:'space-between', marginTop:'var(--space-3)', fontSize:'var(--font-size-sm)'}}>
                      <span><Badge kind="info">Afwijking</Badge> {fmtNum(a)}</span>
                      <span>{fmtNum(g)} <Badge kind="neutral">Geen</Badge></span>
                    </div>
                  </>
                );
              })()}
            </div>

            <div className="bd-card">
              <h2 style={{margin:'0 0 var(--space-4)', fontSize:'var(--font-size-md)', fontWeight:600}}>Status-verdeling</h2>
              <table className="bd-table">
                <tbody>
                  {Object.entries(stats.status_verdeling)
                    .sort((a, b) => b[1] - a[1])
                    .map(([status, n]) => (
                      <tr key={status}>
                        <td>{STATUS_LABEL[status] || status}</td>
                        <td className="bd-mono" style={{textAlign:'right', fontWeight:600}}>{fmtNum(n)}</td>
                      </tr>
                    ))}
                </tbody>
              </table>
            </div>
          </div>

          <p style={{fontSize:'var(--font-size-xs)', color:'var(--text-muted)', marginTop:'var(--space-2)'}}>
            Exporteren naar een fine-tune dataset: <span className="bd-mono">python tools/export_training.py --out bag_contour.jsonl</span>
          </p>
        </>
      )}
    </div>
  );
}

window.SchermTraining = SchermTraining;
