// Amber Esti — front-end SPA
const { useState, useEffect, useCallback, useRef } = React;

const api = {
  async req(method, url, data, isForm) {
    const opts = { method, headers: {} };
    if (isForm) opts.body = data;
    else if (data !== undefined) { opts.headers['Content-Type'] = 'application/json'; opts.body = JSON.stringify(data); }
    const r = await fetch(url, opts);
    if (r.status === 401) { location.href = '/login.html'; return null; }
    return r.json();
  },
  get: u => api.req('GET', u),
  post: (u, d) => api.req('POST', u, d),
  put: (u, d) => api.req('PUT', u, d),
  patch: (u, d) => api.req('PATCH', u, d),
  del: u => api.req('DELETE', u),
  upload: (u, files) => { const fd = new FormData(); [...files].forEach(f => fd.append('files', f)); return api.req('POST', u, fd, true); }
};
const eur = n => (n == null ? '—' : Number(n).toLocaleString('lv-LV', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' €');
const hrs = n => (n == null ? '' : Number(n).toLocaleString('lv-LV', { maximumFractionDigits: 2 }));

function Alert({ type, message, onClose }) {
  if (!message) return null;
  return (
    <div className={type === 'error' ? 'error-msg' : 'success-msg'}
      style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between' }}>
      <span>{message}</span>
      {onClose && <span style={{ cursor: 'pointer', marginLeft: 12 }} onClick={onClose}>✕</span>}
    </div>
  );
}

// ── Projektu saraksts ───────────────────────────────────────────────────────
function ProjectsList({ onOpen }) {
  const [projects, setProjects] = useState([]);
  const [show, setShow] = useState(false);
  const [form, setForm] = useState({ name: '', description: '' });
  const [status, setStatus] = useState(null);
  const [loading, setLoading] = useState(false);

  const load = useCallback(async () => setProjects(await api.get('/api/projects') || []), []);
  useEffect(() => { load(); }, [load]);

  const create = async () => {
    if (!form.name.trim()) return;
    setLoading(true);
    const r = await api.post('/api/projects', form);
    setLoading(false);
    if (r?.error) { setStatus({ type: 'error', msg: r.error }); return; }
    setForm({ name: '', description: '' }); setShow(false); load();
  };
  const remove = async (p) => {
    if (!confirm(`Dzēst projektu "${p.name}" un visus tā failus?`)) return;
    await api.del(`/api/projects/${p.slug}`); load();
  };

  return (
    <div>
      <div className="page-header"><h1>Projekti</h1><p>Tāmēšanas projektu saraksts</p></div>
      <Alert type={status?.type} message={status?.msg} onClose={() => setStatus(null)} />
      {show ? (
        <div className="card">
          <div className="card-title">Jauns projekts</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            <input placeholder="Nosaukums *" value={form.name} autoFocus
              onChange={e => setForm(f => ({ ...f, name: e.target.value }))} />
            <input placeholder="Apraksts (neobligāts)" value={form.description}
              onChange={e => setForm(f => ({ ...f, description: e.target.value }))} />
            <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
              <button className="btn btn-outline" onClick={() => setShow(false)}>Atcelt</button>
              <button className="btn btn-primary" onClick={create} disabled={loading || !form.name.trim()}>+ Pievienot</button>
            </div>
          </div>
        </div>
      ) : <button className="btn btn-primary" onClick={() => setShow(true)} style={{ marginBottom: 16 }}>+ Jauns projekts</button>}

      {projects.length === 0 ? (
        <div className="card" style={{ color: 'var(--color-muted)', textAlign: 'center', padding: 40 }}>Nav projektu.</div>
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {projects.map(p => (
            <div className="card" key={p.slug} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 0 }}>
              <div>
                <div style={{ fontWeight: 500 }}>{p.name}</div>
                {p.description && <div style={{ fontSize: 12, color: 'var(--color-muted)' }}>{p.description}</div>}
              </div>
              <div style={{ display: 'flex', gap: 6 }}>
                <button className="btn btn-outline btn-sm" onClick={() => onOpen(p.slug)}>Atvērt</button>
                <button className="btn btn-danger btn-sm" onClick={() => remove(p)}>Dzēst</button>
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ── Saistību (links) attēlošana ─────────────────────────────────────────────
const LINK_TYPE = {
  duplicate:    { label: 'dublikāts',      color: '#b91c1c', bg: '#fef2f2', border: '#fecaca' },
  partial:      { label: 'daļēji dublē',   color: '#b45309', bg: '#fffbeb', border: '#fde68a' },
  estimated_in: { label: 'novērtēta citā', color: '#6d28d9', bg: '#f5f3ff', border: '#ddd6fe' },
  related:      { label: 'saistīta',       color: '#1d4ed8', bg: '#eff6ff', border: '#bfdbfe' },
};
function linkMeta(t) { return LINK_TYPE[t] || { label: t, color: '#475569', bg: '#f1f5f9', border: '#e2e8f0' }; }

// Prasības efektīvie tegi = metadata.tags (masīvs) ∪ mantotais metadata.veids (viens tegs)
function effTags(it) {
  const md = it && it.metadata;
  const arr = (md && Array.isArray(md.tags)) ? md.tags.slice() : [];
  const v = md && md.veids;
  if (v && !arr.includes(v)) arr.push(v);
  return arr;
}

// Saraksta visu prasību saites → {outbound, inbound} pa id (apgrieztā sasaiste UI vajadzībām)
function buildLinkIndex(items) {
  const outbound = {}, inbound = {};
  for (const it of items) {
    for (const l of (it.links || [])) {
      (outbound[it.id] = outbound[it.id] || []).push(l);
      (inbound[l.targetId] = inbound[l.targetId] || []).push({ sourceId: it.id, type: l.type, note: l.note });
    }
  }
  return { outbound, inbound };
}

function LinkChip({ type, label, onClick, title }) {
  const m = linkMeta(type);
  return <span className="link-chip" title={title}
    style={{ background: m.bg, color: m.color, borderColor: m.border, cursor: onClick ? 'pointer' : 'default' }}
    onClick={onClick}>{label}</span>;
}

// Kompakts saišu attēlojums rindā (Pārskatam un pilnam režģim)
function LinksInline({ id, index, byId, onJump }) {
  const out = index.outbound[id] || [];
  const inb = index.inbound[id] || [];
  if (!out.length && !inb.length) return null;
  return (
    <div className="links-inline">
      {out.map((l, i) => { const t = byId[l.targetId]; const m = linkMeta(l.type);
        return <LinkChip key={'o' + i} type={l.type} label={'→ ' + m.label + ': ' + l.targetId}
          title={(t ? t.title + ' — ' : '') + (l.note || '')} onClick={onJump ? () => onJump(l.targetId) : null} />; })}
      {inb.map((l, i) => { const s = byId[l.sourceId]; const m = linkMeta(l.type);
        return <LinkChip key={'i' + i} type={l.type} label={'← ' + m.label + ': ' + l.sourceId}
          title={(s ? s.title + ' — ' : '') + (l.note || '')} onClick={onJump ? () => onJump(l.sourceId) : null} />; })}
    </div>
  );
}

// Bagātinātā teksta attēlojums: marķierus ⟦TABULA⟧ / ⟦ATTĒLS⟧ aizvieto ar izceltu paziņojumu
const CONTENT_NOTICE = {
  'TABULA': 'Šī prasība satur tabulu, kas nav pilnībā pārkopēta — skatiet pilno variantu oriģinālajā dokumentā.',
  'ATTĒLS': 'Šī prasība satur attēlu vai diagrammu, kas nav pārkopēta — skatiet oriģinālo dokumentu.',
  'SAREŽĢĪTS SATURS': 'Šī prasība satur saturu, kas nav pilnībā pārkopēts — skatiet oriģinālo dokumentu.',
};
function noticeFor(key) { return CONTENT_NOTICE[key] || CONTENT_NOTICE['SAREŽĢĪTS SATURS']; }
function hasComplexContent(text) { return /⟦[^⟧]+⟧/.test(text || ''); }
function renderRichText(text) {
  if (!text) return null;
  const parts = String(text).split(/(⟦[^⟧]+⟧)/g);
  return parts.map((p, i) => {
    const m = p.match(/^⟦([^⟧]+)⟧$/);
    if (m) return <div className="content-notice" key={i}><span className="content-notice-icon">⚠️</span><span>{noticeFor(m[1].trim().toUpperCase())}</span></div>;
    return p ? <span key={i}>{p}</span> : null;
  });
}

// Komentāra marķieru izcelšana: "Jautājums:" zilā, "Svarīgi!" sarkanā
function renderComment(text) {
  if (!text) return null;
  const parts = String(text).split(/(Jautājums:|Svarīgi!)/g);
  return parts.map((p, i) => {
    if (p === 'Jautājums:') return <span key={i} className="cmark-q">{p}</span>;
    if (p === 'Svarīgi!') return <span key={i} className="cmark-imp">{p}</span>;
    return p ? <span key={i}>{p}</span> : null;
  });
}

// Laika zīmoga formāts
function fmtTime(iso) {
  try { return new Date(iso).toLocaleString('lv-LV', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); }
  catch (e) { return iso || ''; }
}
// Izmaiņu ieraksta teksts (ieskaitot koeficienta atvasinātās lomas)
function changeText(e) {
  const parts = (e.changes || []).map(c => `${c.label}: ${hrs(c.from)}→${hrs(c.to)} h`);
  let s = 'Novērtējums mainīts';
  if (parts.length) s += ': ' + parts.join('; ');
  if (e.grandFrom != null && e.grandTo != null && e.grandFrom !== e.grandTo) s += ` · Kopā ${eur(e.grandFrom)} → ${eur(e.grandTo)}`;
  return s;
}
// Komentāru / izmaiņu žurnāls: komentārus var pievienot/dzēst; izmaiņas pierakstās automātiski
function CommentLog({ slug, it, reload, editable }) {
  const [text, setText] = useState('');
  const [busy, setBusy] = useState(false);
  const all = Array.isArray(it.commentLog) ? it.commentLog : [];
  const add = async () => {
    const t = text.trim(); if (!t || busy) return;
    setBusy(true);
    await api.post(`/api/projects/${slug}/requirements/${it.id}/comments`, { text: t });
    setText(''); setBusy(false); reload && reload();
  };
  const del = async (cid) => {
    if (!window.confirm('Dzēst šo komentāru?')) return;
    await api.del(`/api/projects/${slug}/requirements/${it.id}/comments/${cid}`); reload && reload();
  };
  const renderEntry = (e) => e.kind === 'change'
    ? <div key={e.id} className="clog-change"><span className="clog-time">{fmtTime(e.at)}</span> {changeText(e)}</div>
    : <div key={e.id} className="clog-comment">
        <div className="clog-meta"><span className="clog-time">{fmtTime(e.at)}</span>{e.author ? ' · ' + e.author : ''}
          {editable && <span className="clog-del" title="Dzēst komentāru" onClick={() => del(e.id)}>✕</span>}</div>
        <div className="clog-text">{renderComment(e.text)}</div>
      </div>;
  if (!editable) {
    if (!all.length) return <span className="clog-empty">—</span>;
    const recent = all.slice().reverse().slice(0, 3);
    return <div className="clog clog-compact">{recent.map(renderEntry)}{all.length > 3 && <div className="clog-more">+{all.length - 3} vēl…</div>}</div>;
  }
  return (
    <div className="clog">
      {all.length === 0 && <div className="clog-empty">Vēl nav komentāru vai izmaiņu.</div>}
      {all.map(renderEntry)}
      <div className="clog-add">
        <textarea rows={2} value={text} placeholder="Pievienot komentāru..." onChange={e => setText(e.target.value)} />
        <button className="btn btn-primary btn-sm" onClick={add} disabled={busy || !text.trim()}>Pievienot komentāru</button>
      </div>
    </div>
  );
}

// ── Prasību režģis ──────────────────────────────────────────────────────────
// Jaunas prasības forma (paplašinātā) — pievieno ierakstu tieši no saskarnes
function NewRequirementForm({ slug, items, allTags, onDone, onCancel }) {
  const [f, setF] = useState({
    id: '', type: 'requirement', title: '', description: '', section: '', priority: 'obligāta',
    tags: '', minimalaFunkcionalitate: '', originalText: '', location: '', place: 'end', insertAfter: ''
  });
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState(null);
  const set = (k, v) => setF(x => ({ ...x, [k]: v }));

  const sections = Array.from(new Set(items.map(i => i.section).filter(Boolean))).sort((a, b) => a.localeCompare(b, 'lv'));
  const priorities = Array.from(new Set(items.map(i => i.priority).filter(Boolean).concat(['obligāta', 'vēlama'])))
    .sort((a, b) => a.localeCompare(b, 'lv'));
  const idTaken = !!f.id.trim() && items.some(i => i.id === f.id.trim());

  const submit = async () => {
    setErr(null);
    if (!f.id.trim()) return setErr('ID ir obligāts');
    if (!f.title.trim()) return setErr('Nosaukums ir obligāts');
    if (idTaken) return setErr(`Prasība ar ID "${f.id.trim()}" jau pastāv`);
    setBusy(true);
    const body = {
      id: f.id.trim(), type: f.type, title: f.title.trim(), description: f.description.trim(),
      section: f.section.trim(), priority: f.priority.trim(),
      tags: f.tags.split(',').map(t => t.trim()).filter(Boolean),
      minimalaFunkcionalitate: f.minimalaFunkcionalitate.trim(),
      originalText: f.originalText.trim(), location: f.location.trim(),
      insertAtStart: f.place === 'start',
      insertAfter: f.place === 'after' ? f.insertAfter : ''
    };
    const r = await api.post(`/api/projects/${slug}/requirements`, body);
    setBusy(false);
    if (r && r.error) { setErr(r.error); return; }
    onDone();
  };

  const lbl = { fontSize: 12, color: 'var(--color-muted)', display: 'block', marginBottom: 3 };
  const row = { display: 'flex', gap: 10, flexWrap: 'wrap' };
  const col = (w) => ({ flex: w, minWidth: 160 });

  return (
    <div className="card" style={{ marginBottom: 12 }}>
      <div className="card-title">Jauna prasība</div>
      <Alert type="error" message={err} onClose={() => setErr(null)} />
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        <div style={row}>
          <div style={col(1)}>
            <label style={lbl}>ID *</label>
            <input value={f.id} autoFocus placeholder="piem. TS-2.2.8" onChange={e => set('id', e.target.value)}
              style={idTaken ? { borderColor: '#dc2626' } : undefined} />
            {idTaken && <div style={{ fontSize: 11, color: '#dc2626', marginTop: 2 }}>Šāds ID jau pastāv</div>}
          </div>
          <div style={col(1)}>
            <label style={lbl}>Tips</label>
            <select value={f.type} onChange={e => set('type', e.target.value)}>
              <option value="requirement">Prasība</option>
              <option value="heading">Virsraksts (sadaļa)</option>
              <option value="definition">Termins / definīcija</option>
            </select>
          </div>
          <div style={col(1)}>
            <label style={lbl}>Prioritāte</label>
            <input list="nr-priorities" value={f.priority} onChange={e => set('priority', e.target.value)} />
            <datalist id="nr-priorities">{priorities.map(p => <option key={p} value={p} />)}</datalist>
          </div>
        </div>

        <div>
          <label style={lbl}>Nosaukums *</label>
          <input value={f.title} placeholder="Īss prasības nosaukums" onChange={e => set('title', e.target.value)} />
        </div>

        <div>
          <label style={lbl}>Apraksts</label>
          <textarea rows={3} value={f.description} onChange={e => set('description', e.target.value)}
            style={{ width: '100%' }} placeholder="Prasības skaidrojums saviem vārdiem" />
        </div>

        <div style={row}>
          <div style={col(2)}>
            <label style={lbl}>Sadaļa</label>
            <input list="nr-sections" value={f.section} onChange={e => set('section', e.target.value)} />
            <datalist id="nr-sections">{sections.map(s => <option key={s} value={s} />)}</datalist>
          </div>
          <div style={col(2)}>
            <label style={lbl}>Tegi (atdala ar komatu)</label>
            <input list="nr-tags" value={f.tags} onChange={e => set('tags', e.target.value)} placeholder="piem. integrācija, migrācija" />
            <datalist id="nr-tags">{(allTags || []).map(t => <option key={t} value={t} />)}</datalist>
          </div>
          <div style={col(1)}>
            <label style={lbl}>Min. funkcionalitāte</label>
            <input value={f.minimalaFunkcionalitate} onChange={e => set('minimalaFunkcionalitate', e.target.value)} />
          </div>
        </div>

        <div>
          <label style={lbl}>Oriģinālais teksts (no dokumenta — izsekojamībai)</label>
          <textarea rows={4} value={f.originalText} onChange={e => set('originalText', e.target.value)}
            style={{ width: '100%' }} placeholder="Ja tukšs, tiks izmantots apraksts" />
        </div>

        <div style={row}>
          <div style={col(1)}>
            <label style={lbl}>Atrašanās vieta avotā</label>
            <input value={f.location} onChange={e => set('location', e.target.value)} placeholder="piem. [¶142] vai TS 2.2.7" />
          </div>
          <div style={col(1)}>
            <label style={lbl}>Ievietot</label>
            <select value={f.place} onChange={e => set('place', e.target.value)}>
              <option value="end">Saraksta beigās</option>
              <option value="start">Saraksta sākumā</option>
              <option value="after">Aiz izvēlētās prasības…</option>
            </select>
          </div>
          {f.place === 'after' && (
            <div style={col(2)}>
              <label style={lbl}>Aiz kuras</label>
              <select value={f.insertAfter} onChange={e => set('insertAfter', e.target.value)}>
                <option value="">— izvēlies —</option>
                {items.map((i, n) => <option key={i.id + '_' + n} value={i.id}>{i.id} · {(i.title || '').slice(0, 60)}</option>)}
              </select>
            </div>
          )}
        </div>

        <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
          <button className="btn btn-outline" onClick={onCancel} disabled={busy}>Atcelt</button>
          <button className="btn btn-primary" onClick={submit} disabled={busy || idTaken || !f.id.trim() || !f.title.trim()}>
            {busy ? 'Saglabā…' : '+ Pievienot prasību'}
          </button>
        </div>
      </div>
    </div>
  );
}

function RequirementsGrid({ slug, data, reload }) {
  const allRoles = (data.config.roles || []).filter(r => r.active !== false).sort((a, b) => (a.order || 0) - (b.order || 0));
  const roles = allRoles.filter(r => r.type !== 'coefficient');        // stundu pozīcijas (kolonnas)
  const coeffRoles = allRoles.filter(r => r.type === 'coefficient');   // koeficientu rindas (piem. Peļņa)
  const items = (data.requirements.items || []);
  // Termini netiek rādīti tabulā — tos rāda atsevišķs panelis (poga "Termini")
  const visibleItems = items.filter(it => it.type !== 'definition' && !(it.type === 'heading' && /^termini$/i.test(it.title || '')));
  const reqItems = visibleItems.filter(it => it.type === 'requirement');
  const [saving, setSaving] = useState(false);
  const [mode, setMode] = useState('overview');   // 'overview' | 'focus' | 'grid'
  const [focusIdx, setFocusIdx] = useState(0);
  const [showNew, setShowNew] = useState(false);
  const [analyzing, setAnalyzing] = useState(false);
  // Filtra atslēga ir per-projekts, lai izvēle nepārceļas starp projektiem
  const tagKey = 'ae_tag_filter_' + slug;
  const [tagFilter, setTagFilter] = useState(() => { try { return localStorage.getItem(tagKey) || 'all'; } catch(e) { return 'all'; } });
  const setTag = (v) => { setTagFilter(v); try { localStorage.setItem(tagKey, v); } catch(e) {} };
  const allTags = Array.from(new Set(reqItems.flatMap(effTags))).sort((a, b) => a.localeCompare(b, 'lv'));
  // Ja aktīvais tags nepastāv šajā projektā — automātiski resetē uz 'all'
  const activeTag = (tagFilter === 'all' || allTags.includes(tagFilter)) ? tagFilter : 'all';
  const filteredVisibleItems = activeTag === 'all' ? visibleItems
    : visibleItems.filter(it => it.type !== 'requirement' || effTags(it).includes(activeTag));
  const filteredReqItems = filteredVisibleItems.filter(it => it.type === 'requirement');
  const filteredTotals = activeTag === 'all' ? null : (() => {
    let hours = 0, eur2 = 0, risk = 0, grandTotal = 0;
    const coeffs = {};
    for (const it of filteredReqItems) {
      const c = it.computed || {};
      hours += c.totalHours || 0;
      eur2 += c.totalEUR || 0;
      risk += c.risk || 0;
      grandTotal += c.grandTotal || 0;
      if (c.coeffs) { for (const k in c.coeffs) coeffs[k] = (coeffs[k] || 0) + (c.coeffs[k] || 0); }
    }
    return { hours, eur: eur2, risk, grandTotal, coeffs };
  })();
  const linkIndex = buildLinkIndex(items);
  const byId = {}; items.forEach(i => byId[i.id] = i);
  const linksMeta = data.requirements.linksMeta;

  const patch = async (id, fields) => {
    setSaving(true);
    await api.patch(`/api/projects/${slug}/requirements/${id}`, fields);
    setSaving(false); reload();
  };
  const setEffort = (it, key, val) => {
    const effort = { ...(it.effort || {}) };
    if (val === '' || val == null) delete effort[key];           // tukšs → atvasināts
    else effort[key] = { hours: Number(val), mode: 'manual' };   // ievadīts → manuāls
    patch(it.id, { effort });
  };
  const toggleStatus = (it) => patch(it.id, { status: it.status === 'estimated' ? 'unestimated' : 'estimated' });
  // Dzēšana pēc pozīcijas sarakstā — droši arī tad, ja ir divi ieraksti ar vienu ID
  const removeItem = async (it) => {
    const idx = items.indexOf(it);
    const dupes = items.filter(x => x.id === it.id).length;
    const extra = dupes > 1 ? `\n\nUZMANĪBU: šim ID ir ${dupes} ieraksti — tiks dzēsts tieši šis (pozīcija ${idx + 1}).` : '';
    if (!confirm(`Dzēst "${it.id} · ${it.title}"?${extra}\n\nPirms dzēšanas tiek saglabāts momentuzņēmums.`)) return;
    setSaving(true);
    const r = await api.del(`/api/projects/${slug}/requirements/${encodeURIComponent(it.id)}?index=${idx}`);
    setSaving(false);
    if (r && r.error) alert('Neizdevās dzēst: ' + r.error);
    reload();
  };

  const estCount = reqItems.filter(r => r.status === 'estimated').length;
  const clampIdx = (i) => Math.max(0, Math.min(i, reqItems.length - 1));
  const goPrev = () => setFocusIdx(i => clampIdx(i - 1));
  const goNext = () => setFocusIdx(i => clampIdx(i + 1));
  const goNextUnestimated = () => {
    for (let k = 1; k <= reqItems.length; k++) {
      const j = (focusIdx + k) % reqItems.length;
      if (reqItems[j].status !== 'estimated') { setFocusIdx(j); return; }
    }
  };
  const estimateOne = (it) => { const j = reqItems.findIndex(r => r.id === it.id); if (j >= 0) { setFocusIdx(j); setMode('focus'); } };
  const jumpTo = (id) => { const j = reqItems.findIndex(r => r.id === id); if (j >= 0) { setFocusIdx(j); setMode('focus'); } };
  const analyze = async () => {
    setAnalyzing(true);
    const r = await api.post(`/api/projects/${slug}/links/analyze`);
    setAnalyzing(false);
    if (r && r.error) alert('Saistību analīze neizdevās: ' + r.error); else reload();
  };

  const modes = [['overview', 'Pārskats'], ['focus', 'Fokuss'], ['grid', 'Pilns režģis']];
  const cur = reqItems.length ? reqItems[clampIdx(focusIdx)] : null;

  return (
    <div>
      <div className="totals-bar">
        {filteredTotals ? (
          <>
            <span style={{ color: 'var(--color-accent)', fontWeight: 600, fontSize: 12 }}>Filtrs: {tagFilter}</span>
            <span>Kopā stundas: <b>{hrs(filteredTotals.hours)}</b></span>
            <span>EUR: <b>{eur(filteredTotals.eur)}</b></span>
            <span>Risks: <b>{eur(filteredTotals.risk)}</b></span>
            {coeffRoles.map(r => <span key={r.key}>{r.label}: <b>{eur((filteredTotals.coeffs && filteredTotals.coeffs[r.key]) || 0)}</b></span>)}
            <span>Pavisam kopā: <b>{eur(filteredTotals.grandTotal)}</b></span>
            <span style={{ marginLeft: 'auto' }}>Novērtēts: <b>{filteredReqItems.filter(r => r.status === 'estimated').length}/{filteredReqItems.length}</b></span>
          </>
        ) : (
          <>
            <span>Kopā stundas: <b>{hrs(data.summary.totals.hours)}</b></span>
            <span>EUR: <b>{eur(data.summary.totals.eur)}</b></span>
            <span>Risks: <b>{eur(data.summary.totals.risk)}</b></span>
            {coeffRoles.map(r => <span key={r.key}>{r.label}: <b>{eur((data.summary.totals.coeffs && data.summary.totals.coeffs[r.key]) || 0)}</b></span>)}
            <span>Pavisam kopā: <b>{eur(data.summary.totals.grandTotal)}</b></span>
            <span style={{ marginLeft: 'auto' }}>Novērtēts: <b>{estCount}/{reqItems.length}</b></span>
          </>
        )}
        {saving && <span style={{ color: 'var(--color-muted)' }}>saglabā...</span>}
      </div>

      <div className="req-modes">
        {modes.map(([k, label]) => (
          <button key={k} className={'btn btn-sm ' + (mode === k ? 'btn-primary' : 'btn-outline')} onClick={() => setMode(k)}>{label}</button>
        ))}
        <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 10 }}>
          {linksMeta && <span style={{ fontSize: 12, color: 'var(--color-muted)' }}>Saistības: {linksMeta.count}</span>}
          <button className={'btn btn-sm ' + (showNew ? 'btn-outline' : 'btn-primary')} onClick={() => setShowNew(v => !v)}
            title="Pievieno prasību manuāli, bez dokumenta apstrādes">
            {showNew ? 'Aizvērt formu' : '+ Jauna prasība'}
          </button>
          <button className="btn btn-outline btn-sm" onClick={analyze} disabled={analyzing}
            title="Analizē visas prasības un atrod dublikātus / savstarpējās saistības">
            {analyzing ? 'Analizē…' : '🔗 Atrast saistības/dublikātus'}
          </button>
        </div>
      </div>

      {showNew && <NewRequirementForm slug={slug} items={items} allTags={allTags}
        onCancel={() => setShowNew(false)}
        onDone={() => { setShowNew(false); reload(); }} />}

      {mode === 'overview' && <OverviewList items={filteredVisibleItems} toggleStatus={toggleStatus} onEstimate={estimateOne} slug={slug} reload={reload}
        linkIndex={linkIndex} byId={byId} onJump={jumpTo} tagFilter={activeTag} setTag={setTag} allTags={allTags} patch={patch} onDelete={removeItem} />}

      {mode === 'focus' && (!cur
        ? <div className="card">Nav prasību.</div>
        : <FocusCard key={cur.id} it={cur} idx={clampIdx(focusIdx)} total={reqItems.length} section={cur.section || ''}
            slug={slug} reload={reload} roles={roles} coeffRoles={coeffRoles} setEffort={setEffort} toggleStatus={toggleStatus} patch={patch}
            onPrev={goPrev} onNext={goNext} onNextUnestimated={goNextUnestimated}
            linkIndex={linkIndex} byId={byId} onJump={jumpTo} allTags={allTags} onDelete={removeItem} />)}

      {mode === 'grid' && <FullGrid items={filteredVisibleItems} roles={roles} setEffort={setEffort} toggleStatus={toggleStatus} slug={slug} reload={reload}
        linkIndex={linkIndex} byId={byId} onJump={jumpTo} tagFilter={activeTag} setTag={setTag} allTags={allTags} patch={patch} onDelete={removeItem} />}
    </div>
  );
}

// Lomas stundu šūna (lietota gan pilnā režģī, gan fokusa skatā)
function EffortCell({ it, role, setEffort }) {
  const c = it.computed || {};
  const manual = it.effort && it.effort[role.key] && it.effort[role.key].mode === 'manual';
  const cellVal = c.hoursByRole ? c.hoursByRole[role.key] : '';
  return (
    <td className="num">
      <input key={role.key + ':' + cellVal} className={'cell-input' + (manual ? ' manual' : '')} type="number" step="0.25"
        defaultValue={cellVal}
        onBlur={e => { const v = e.target.value; const curv = cellVal != null ? String(cellVal) : ''; if (v !== curv) setEffort(it, role.key, v); }} />
    </td>
  );
}

// Tegu redaktors — čipi ar noņemšanu + ievade ar datalist (raksti jaunu vai izvēlies esošu).
// Saglabā uz metadata.tags un pārceļ mantoto metadata.veids uz tags (viens avots).
function TagEditor({ it, allTags, patch, compact }) {
  const [adding, setAdding] = useState(false);
  const [val, setVal] = useState('');
  const tags = effTags(it);
  const dlId = 'tags-dl-' + it.id;
  const save = (next) => {
    const clean = Array.from(new Set(next.map(t => String(t).trim()).filter(Boolean)));
    const md = { ...(it.metadata || {}), tags: clean };
    delete md.veids;                      // mantoto veids ietveram tags masīvā
    patch(it.id, { metadata: md });
  };
  const add = () => {
    const t = val.trim();
    if (t && !tags.includes(t)) save([...tags, t]);
    setVal(''); setAdding(false);
  };
  const remove = (t) => save(tags.filter(x => x !== t));
  const suggestions = (allTags || []).filter(t => !tags.includes(t));
  return (
    <div className={'tag-editor' + (compact ? ' tag-editor-compact' : '')}>
      {tags.map(t => (
        <span className="tag tag-chip" key={t}>{t}
          <span className="tag-chip-x" title="Noņemt tegu" onClick={() => remove(t)}>×</span>
        </span>
      ))}
      {adding ? (
        <span className="tag-add">
          <input list={dlId} autoFocus value={val} placeholder="tegs…"
            onChange={e => setVal(e.target.value)}
            onKeyDown={e => {
              if (e.key === 'Enter') { e.preventDefault(); add(); }
              else if (e.key === 'Escape') { setVal(''); setAdding(false); }
            }}
            onBlur={add} />
          <datalist id={dlId}>{suggestions.map(t => <option key={t} value={t} />)}</datalist>
        </span>
      ) : (
        <span className="tag tag-add-btn" title="Pievienot tegu" onClick={() => setAdding(true)}>+ tegs</span>
      )}
    </div>
  );
}

// Tegu filtrs — atsevišķa, skaidri redzama josla (lietota Pārskatā un Pilnā režģī)
function TagFilterBar({ tagFilter, setTag, allTags }) {
  const has = allTags && allTags.length > 0;
  return (
    <div className="tag-filter-bar">
      <span className="tag-filter-label">Filtrēt pēc tega:</span>
      {!has
        ? <span className="tag-filter-empty">nav tegu — pievieno tos pie prasībām zemāk</span>
        : (<>
            <button className={'btn btn-sm ' + (tagFilter === 'all' ? 'btn-primary' : 'btn-outline')} onClick={() => setTag('all')}>Visi</button>
            {allTags.map(t => (
              <button key={t} className={'btn btn-sm ' + (tagFilter === t ? 'btn-primary' : 'btn-outline')} onClick={() => setTag(t)}>{t}</button>
            ))}
          </>)}
    </div>
  );
}

// Pārskats — kompakts, lasāms saraksts (bez lomu kolonnām)
function OverviewList({ items, toggleStatus, onEstimate, linkIndex, byId, onJump, slug, reload, tagFilter, setTag, allTags, patch, onDelete }) {
  const [showComments, setShowComments] = useState(() => { try { return localStorage.getItem('ae_overview_comments') === '1'; } catch (e) { return false; } });
  const toggleComments = () => setShowComments(v => { const n = !v; try { localStorage.setItem('ae_overview_comments', n ? '1' : '0'); } catch (e) {} return n; });
  return (
    <div style={{ overflowX: 'auto' }}>
      <div className="overview-toolbar">
        <button className={'btn btn-sm ' + (showComments ? 'btn-primary' : 'btn-outline')} onClick={toggleComments}>
          {showComments ? 'Slēpt komentārus' : 'Rādīt komentārus'}
        </button>
      </div>
      <TagFilterBar tagFilter={tagFilter} setTag={setTag} allTags={allTags} />
      <table className="req-table req-overview">
        <thead>
          <tr>
            <th style={{ width: 64 }}>ID</th><th>Prasība</th><th style={{ width: 112 }}>Statuss</th>
            <th className="num" style={{ width: 80 }}>Stundas</th><th className="num" style={{ width: 112 }}>Kopā</th><th style={{ width: 150 }}></th>
          </tr>
        </thead>
        <tbody>
          {items.map((it, n) => {
            if (it.type === 'heading') return (
              <tr className="req-row-heading" key={it.id + '_' + n}>
                <td colSpan={5}>{it.title}</td>
                <td style={{ textAlign: 'right' }}>
                  {onDelete && <button className="btn btn-danger btn-sm" title="Dzēst virsrakstu" onClick={() => onDelete(it)}>✕</button>}
                </td>
              </tr>);
            const c = it.computed || {};
            return (
              <tr key={it.id + '_' + n}>
                <td>{it.id}</td>
                <td>
                  <div style={{ fontWeight: 500 }}>{it.title}{hasComplexContent(it.source && it.source.originalText) && <span className="badge-warn" title="Satur tabulu, kas nav pilnībā pārkopēta">⚠ tabula</span>}</div>
                  {it.description && <div className="req-desc">{it.description}</div>}
                  {it.type === 'requirement' && <TagEditor it={it} allTags={allTags} patch={patch} />}
                  {showComments && <div className="req-comment"><CommentLog slug={slug} it={it} reload={reload} editable={false} /></div>}
                  <LinksInline id={it.id} index={linkIndex} byId={byId} onJump={onJump} />
                </td>
                <td><span className={'status-pill ' + (it.status === 'estimated' ? 'status-estimated' : 'status-unestimated')}
                  style={{ cursor: 'pointer' }} onClick={() => toggleStatus(it)}>{it.status === 'estimated' ? 'novērtēts' : 'nenovērtēts'}</span></td>
                <td className="num">{hrs(c.totalHours)}</td>
                <td className="num"><b>{eur(c.grandTotal)}</b></td>
                <td style={{ whiteSpace: 'nowrap' }}>
                  <button className="btn btn-outline btn-sm" onClick={() => onEstimate(it)}>Novērtēt →</button>
                  {onDelete && <button className="btn btn-danger btn-sm" style={{ marginLeft: 4 }}
                    title="Dzēst prasību" onClick={() => onDelete(it)}>✕</button>}
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

// Pilns režģis — visas lomu kolonnas vienlaikus (iepriekšējais skats)
function FullGrid({ items, roles, setEffort, toggleStatus, linkIndex, byId, onJump, slug, reload, tagFilter, setTag, allTags, patch, onDelete }) {
  const [showComments, setShowComments] = useState(() => { try { return localStorage.getItem('ae_grid_comments') === '1'; } catch (e) { return false; } });
  const toggleComments = () => setShowComments(v => { const n = !v; try { localStorage.setItem('ae_grid_comments', n ? '1' : '0'); } catch (e) {} return n; });
  // Kopsummas pa lomu kolonnām — stundas un budžets (stundas × likme)
  const colHours = {}; const colEUR = {};
  roles.forEach(r => { colHours[r.key] = 0; colEUR[r.key] = 0; });
  for (const it of items) {
    if (it.type !== 'requirement') continue;
    const c = it.computed || {};
    const hbr = c.hoursByRole || {};
    for (const r of roles) {
      const h = Number(hbr[r.key] || 0);
      const rate = (it.rateOverrides && it.rateOverrides[r.key] != null) ? it.rateOverrides[r.key] : r.rate;
      colHours[r.key] += h;
      colEUR[r.key] += h * Number(rate || 0);
    }
  }
  const totalHoursAll = roles.reduce((s, r) => s + colHours[r.key], 0);
  const totalEURAll = roles.reduce((s, r) => s + colEUR[r.key], 0);
  return (
    <div style={{ overflowX: 'auto' }}>
      <div className="overview-toolbar">
        <button className={'btn btn-sm ' + (showComments ? 'btn-primary' : 'btn-outline')} onClick={toggleComments}>
          {showComments ? 'Slēpt komentārus' : 'Rādīt komentārus'}
        </button>
      </div>
      <TagFilterBar tagFilter={tagFilter} setTag={setTag} allTags={allTags} />
      <table className="req-table">
        <thead>
          <tr>
            <th>ID</th><th>Prasība</th><th>Statuss</th>
            {roles.map(r => <th key={r.key} className="num" title={r.label}>{r.label}</th>)}
            <th className="num">Stundas</th><th className="num">EUR</th><th className="num">Kopā</th><th style={{ minWidth: 150 }}>Saites</th><th style={{ width: 44 }}></th>
          </tr>
          <tr className="grid-totals-row">
            <th colSpan={3} className="grid-totals-label">Kopā stundas</th>
            {roles.map(r => <th key={r.key} className="num">{hrs(colHours[r.key])}</th>)}
            <th className="num"><b>{hrs(totalHoursAll)}</b></th><th className="num"></th><th className="num"></th><th></th><th></th>
          </tr>
          <tr className="grid-totals-row">
            <th colSpan={3} className="grid-totals-label">Kopā budžets</th>
            {roles.map(r => <th key={r.key} className="num">{eur(colEUR[r.key])}</th>)}
            <th className="num"></th><th className="num"><b>{eur(totalEURAll)}</b></th><th className="num"></th><th></th><th></th>
          </tr>
        </thead>
        <tbody>
          {items.map((it, n) => {
            if (it.type === 'heading') return (
              <tr className="req-row-heading" key={it.id + '_' + n}>
                <td colSpan={roles.length + 7}>{it.title}</td>
                <td style={{ textAlign: 'right' }}>
                  {onDelete && <button className="btn btn-danger btn-sm" title="Dzēst virsrakstu" onClick={() => onDelete(it)}>✕</button>}
                </td>
              </tr>);
            const c = it.computed || {};
            return (
              <tr key={it.id + '_' + n}>
                <td>{it.id}</td>
                <td style={{ maxWidth: 320 }}>
                  <div style={{ fontWeight: 500 }}>{it.title}</div>
                  {it.type === 'requirement' && <TagEditor it={it} allTags={allTags} patch={patch} compact />}
                  {showComments && <div style={{ marginTop: 2 }}><CommentLog slug={slug} it={it} reload={reload} editable={false} /></div>}
                </td>
                <td><span className={'status-pill ' + (it.status === 'estimated' ? 'status-estimated' : 'status-unestimated')}
                  style={{ cursor: 'pointer' }} onClick={() => toggleStatus(it)}>{it.status === 'estimated' ? 'novērtēts' : 'nenovērtēts'}</span></td>
                {roles.map(r => <EffortCell key={r.key} it={it} role={r} setEffort={setEffort} />)}
                <td className="num">{hrs(c.totalHours)}</td>
                <td className="num">{eur(c.totalEUR)}</td>
                <td className="num"><b>{eur(c.grandTotal)}</b></td>
                <td><LinksInline id={it.id} index={linkIndex} byId={byId} onJump={onJump} /></td>
                <td style={{ textAlign: 'right' }}>
                  {onDelete && <button className="btn btn-danger btn-sm" title="Dzēst prasību" onClick={() => onDelete(it)}>✕</button>}
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
      <p style={{ fontSize: 12, color: 'var(--color-muted)', marginTop: 8 }}>
        Dzeltenā šūna = manuāli pārrakstīta. Iztukšo šūnu, lai atgrieztos pie aprēķinātās (koeficienta) vērtības.
      </p>
    </div>
  );
}

// Fokuss — viena prasība pēc otras ar pilnu tekstu un novērtējumu
function FocusCard({ it, idx, total, section, roles, coeffRoles, setEffort, toggleStatus, patch, onPrev, onNext, onNextUnestimated, linkIndex, byId, onJump, slug, reload, allTags, onDelete }) {
  const c = it.computed || {};
  const [comment, setComment] = useState(it.comments || '');
  const veids = it.metadata && it.metadata.veids;
  const minimal = it.metadata && it.metadata.minimalaFunkcionalitate;
  const orig = it.source && it.source.originalText;
  const loc = it.source && it.source.location;
  const outL = (linkIndex && linkIndex.outbound[it.id]) || [];
  const inbL = (linkIndex && linkIndex.inbound[it.id]) || [];
  return (
    <div className="focus-wrap">
      <div className="focus-nav">
        <button className="btn btn-outline btn-sm" onClick={onPrev} disabled={idx === 0}>← Iepriekšējā</button>
        <span className="focus-progress">{idx + 1} / {total}</span>
        <button className="btn btn-outline btn-sm" onClick={onNext} disabled={idx === total - 1}>Nākamā →</button>
        <button className="btn btn-outline btn-sm" onClick={onNextUnestimated} style={{ marginLeft: 'auto' }}>Nākamā nenovērtētā ↦</button>
        {onDelete && <button className="btn btn-danger btn-sm" title="Dzēst šo prasību" onClick={() => onDelete(it)}>✕ Dzēst</button>}
      </div>

      <div className="card focus-card">
        <div className="focus-head">
          <div>
            {section && <div className="focus-section">{section}</div>}
            <h2 className="focus-title"><span className="focus-id">{it.id}</span> {it.title}</h2>
          </div>
          <span className={'status-pill ' + (it.status === 'estimated' ? 'status-estimated' : 'status-unestimated')}
            style={{ cursor: 'pointer', flexShrink: 0 }} onClick={() => toggleStatus(it)}>{it.status === 'estimated' ? 'novērtēts' : 'nenovērtēts'}</span>
        </div>

        <div className="focus-meta">
          <div className="focus-tags">
            <span className="focus-meta-label">Tegi:</span>
            <TagEditor it={it} allTags={allTags} patch={patch} />
          </div>
          <div className="focus-meta-info">
            {minimal && <span className="tag">Min. funkc.: {minimal}</span>}
            {it.priority && <span className="tag">{it.priority}</span>}
            {loc && <span className="tag tag-muted">{loc}</span>}
            {hasComplexContent(orig) && <span className="tag tag-warn">satur tabulu</span>}
          </div>
        </div>

        <div className="focus-fulltext">{renderRichText(orig || it.description)}</div>

        {(outL.length > 0 || inbL.length > 0) && (
          <div className="focus-links">
            <div className="focus-roles-title">Saistītās prasības ({outL.length + inbL.length})</div>
            {outL.map((l, i) => { const t = byId[l.targetId]; const m = linkMeta(l.type); return (
              <div className="focus-link-row" key={'o' + i}>
                <LinkChip type={l.type} label={m.label} />
                <button className="link-jump" onClick={() => onJump(l.targetId)}>→ {l.targetId} · {t ? t.title : ''}</button>
                {l.note && <div className="focus-link-note">{l.note}</div>}
              </div> ); })}
            {inbL.map((l, i) => { const s = byId[l.sourceId]; const m = linkMeta(l.type); return (
              <div className="focus-link-row" key={'i' + i}>
                <LinkChip type={l.type} label={m.label} />
                <button className="link-jump" onClick={() => onJump(l.sourceId)}>← {l.sourceId} · {s ? s.title : ''}</button>
                {l.note && <div className="focus-link-note">{l.note}</div>}
              </div> ); })}
          </div>
        )}

        <div className="focus-roles">
          <div className="focus-roles-title">Novērtējums — stundas pa lomām</div>
          <table className="req-table focus-roles-table">
            <tbody>
              {roles.map(r => (
                <tr key={r.key}>
                  <td>{r.label}</td>
                  <EffortCell it={it} role={r} setEffort={setEffort} />
                </tr>
              ))}
              <tr className="focus-roles-total">
                <td><b>Kopā</b></td>
                <td className="num"><b>{hrs(c.totalHours)}</b> h · <b>{eur(c.grandTotal)}</b></td>
              </tr>
            </tbody>
          </table>
          <div className="focus-breakdown">
            Stundu izmaksas: <b>{eur(c.totalEUR)}</b> · Risks: <b>{eur(c.risk)}</b>
            {(coeffRoles || []).map(r => <span key={r.key}> · {r.label}: <b>{eur((c.coeffs && c.coeffs[r.key]) || 0)}</b></span>)}
            {' · '}Kopā: <b>{eur(c.grandTotal)}</b>
          </div>
          <p style={{ fontSize: 12, color: 'var(--color-muted)', marginTop: 6 }}>
            Dzeltenā šūna = manuāli pārrakstīta. Iztukšo, lai atgrieztos pie aprēķinātās vērtības.
          </p>
        </div>

        <div className="focus-comment">
          <label>Komentāri un izmaiņas</label>
          <CommentLog slug={slug} it={it} reload={reload} editable={true} />
        </div>
      </div>
    </div>
  );
}

// ── Avoti + apstrāde (asinhrona, ar progresu) ───────────────────────────────
const PROC = {
  pending:    { label: 'gaida',      color: '#64748b' },
  queued:     { label: 'rindā',      color: '#64748b' },
  processing: { label: 'apstrādā…',  color: '#2563eb' },
  done:       { label: 'apstrādāts', color: '#16a34a' },
  error:      { label: 'kļūda',      color: '#dc2626' },
  timeout:    { label: 'noildze',    color: '#f59e0b' },
};

function SourcesPanel({ slug, meta, reload }) {
  const [data, setData] = useState({ job: null, sources: [] });
  const [uploading, setUploading] = useState(false);
  const [alert, setAlert] = useState(null);
  const fileRef = useRef();
  const timer = useRef(null);

  const fetchStatus = useCallback(async () => {
    const d = await api.get(`/api/projects/${slug}/process/status`);
    if (d) setData(d);
    return d;
  }, [slug]);

  const stopPoll = () => { if (timer.current) { clearInterval(timer.current); timer.current = null; } };
  const startPoll = useCallback(() => {
    stopPoll();
    timer.current = setInterval(async () => {
      const d = await fetchStatus();
      if (!d || !d.job || d.job.status !== 'running') { stopPoll(); reload(); }
    }, 1500);
  }, [fetchStatus, reload]);

  useEffect(() => {
    fetchStatus().then(d => { if (d && d.job && d.job.status === 'running') startPoll(); });
    return stopPoll;
  }, [fetchStatus, startPoll]);

  const onUpload = async (e) => {
    if (!e.target.files.length) return;
    setUploading(true);
    await api.upload(`/api/projects/${slug}/sources`, e.target.files);
    setUploading(false); fileRef.current.value = '';
    reload(); fetchStatus();
  };
  const startJob = async (opts) => {
    setAlert(null);
    const r = await api.post(`/api/projects/${slug}/process`, opts);
    if (r?.error) { setAlert({ type: 'error', msg: r.error }); return; }
    await fetchStatus(); startPoll();
  };
  const removeSource = async (id) => { await api.del(`/api/projects/${slug}/sources/${id}`); reload(); fetchStatus(); };

  const job = data.job;
  const running = job && job.status === 'running';
  const sources = data.sources.length ? data.sources
    : (meta.sources || []).map(s => ({ id: s.id, name: s.originalName, status: s.processStatus || 'pending', itemsExtracted: s.itemsExtracted || 0, error: s.error }));
  const pendingCount = sources.filter(s => s.status !== 'done' && s.status !== 'processing').length;

  return (
    <div className="card">
      <div className="card-title">Avota dokumenti</div>
      <Alert type={alert?.type} message={alert?.msg} onClose={() => setAlert(null)} />
      <input ref={fileRef} type="file" multiple onChange={onUpload} disabled={uploading || running} style={{ marginBottom: 12 }} />

      {sources.length === 0 ? <p style={{ color: 'var(--color-muted)' }}>Nav augšupielādētu failu.</p> : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 6, marginBottom: 12 }}>
          {sources.map(s => {
            const p = PROC[s.status] || PROC.pending;
            return (
              <div key={s.id} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', fontSize: 13 }}>
                <span>{s.name}
                  <span style={{ color: p.color, marginLeft: 8 }}>● {p.label}</span>
                  {s.status === 'done' && <span style={{ color: 'var(--color-muted)', marginLeft: 6 }}>({s.itemsExtracted} prasības)</span>}
                  {s.error && <span style={{ color: 'var(--color-danger)', marginLeft: 6 }} title={s.error}>— {String(s.error).slice(0, 60)}</span>}
                </span>
                <span style={{ cursor: running ? 'default' : 'pointer', color: 'var(--color-danger)', opacity: running ? 0.4 : 1 }}
                  onClick={() => !running && removeSource(s.id)}>✕</span>
              </div>
            );
          })}
        </div>
      )}

      {running && (
        <div style={{ marginBottom: 12 }}>
          <div style={{ fontSize: 13, marginBottom: 4 }}>
            Apstrādā {job.done}/{job.total}{job.current ? ': ' + job.current.name : ''}
            {job.current && job.current.chunks > 1 ? ` (fragments ${job.current.chunk}/${job.current.chunks})` : ''} — kopā {job.itemsTotal} prasības
          </div>
          <div style={{ height: 8, background: 'var(--color-border)', borderRadius: 999, overflow: 'hidden' }}>
            <div style={{ height: '100%', width: (job.total ? Math.round(job.done / job.total * 100) : 0) + '%', background: 'var(--color-primary)', transition: 'width .3s' }} />
          </div>
        </div>
      )}
      {job && job.status !== 'running' && job.errors && job.errors.length > 0 && (
        <div className="error-msg" style={{ marginBottom: 12 }}>Apstrādē bija {job.errors.length} kļūda(s). Skat. statusu pie dokumentiem.</div>
      )}

      <div style={{ display: 'flex', gap: 8 }}>
        <button className="btn btn-primary" disabled={running || pendingCount === 0}
          onClick={() => startJob({})}>{running ? 'Apstrādā...' : `Apstrādāt jaunos (${pendingCount})`}</button>
        <button className="btn btn-outline" disabled={running || sources.length === 0}
          onClick={() => { if (confirm('Apstrādāt visus dokumentus no jauna un aizvietot esošās prasības?')) startJob({ all: true, mode: 'replace' }); }}>Apstrādāt visus no jauna</button>
      </div>
      <p style={{ fontSize: 12, color: 'var(--color-muted)', marginTop: 8 }}>
        Atbalstīts: .docx, .xlsx, .txt, .md, .csv. PDF tekstu pagaidām jāizgūst manuāli.
        Lieli dokumenti tiek sadalīti fragmentos un apstrādāti pa daļām (katrs ar 2 min limitu),
        tāpēc viena fragmenta vai dokumenta kļūme neaptur pārējos.
      </p>
    </div>
  );
}

// ── Aprēķinu konfigurācija ──────────────────────────────────────────────────
function ConfigEditor({ slug, config, reload }) {
  const [cfg, setCfg] = useState(config);
  const [status, setStatus] = useState(null);
  useEffect(() => setCfg(config), [config]);
  const setRole = (i, field, val) => { const roles = cfg.roles.map((r, j) => j === i ? { ...r, [field]: val } : r); setCfg({ ...cfg, roles }); };
  const addRole = (type) => {
    const base = { key: 'r' + Date.now().toString(36), active: true, order: (cfg.roles.length + 1) };
    const row = type === 'coefficient'
      ? { ...base, type: 'coefficient', label: 'Jauns koeficients', coefficient: 0.1 }
      : { ...base, label: 'Jauna loma', rate: 37, driver: false, coefficient: 0.1, base: 'coding' };
    setCfg({ ...cfg, roles: [...cfg.roles, row] });
  };
  const removeRole = (i) => { if (!window.confirm('Noņemt šo rindu no aprēķina?')) return; setCfg({ ...cfg, roles: cfg.roles.filter((_, j) => j !== i) }); };
  const save = async () => { const r = await api.put(`/api/projects/${slug}/config`, cfg); if (!r?.error) { setStatus({ type: 'success', msg: 'Saglabāts' }); reload(); } };

  return (
    <div className="card">
      <div className="card-title">Aprēķinu dzinējs — rindas un koeficienti</div>
      <Alert type={status?.type} message={status?.msg} onClose={() => setStatus(null)} />
      <table className="req-table" style={{ marginBottom: 12 }}>
        <thead><tr><th>Nosaukums</th><th>Tips</th><th className="num">Likme €/h</th><th>Dzinējs</th><th className="num">Koef./%</th><th>Bāze</th><th>Aktīva</th><th></th></tr></thead>
        <tbody>
          {cfg.roles.map((r, i) => {
            const isCoeff = r.type === 'coefficient';
            return (
            <tr key={r.key}>
              <td><input className="cell-input" style={{ width: 170, textAlign: 'left' }} value={r.label || ''} onChange={e => setRole(i, 'label', e.target.value)} /></td>
              <td style={{ fontSize: 12, color: 'var(--color-muted)' }}>{isCoeff ? 'koeficients' : 'stundas'}</td>
              <td className="num">{isCoeff ? '—' : <input className="cell-input" type="number" value={r.rate} onChange={e => setRole(i, 'rate', Number(e.target.value))} />}</td>
              <td style={{ textAlign: 'center' }}>{isCoeff ? '—' : <input type="checkbox" checked={!!r.driver} onChange={e => setRole(i, 'driver', e.target.checked)} />}</td>
              <td className="num">{(isCoeff || !r.driver) ? <input className="cell-input" type="number" step="0.01" value={r.coefficient || 0} onChange={e => setRole(i, 'coefficient', Number(e.target.value))} /> : '—'}</td>
              <td>{isCoeff ? <span style={{ fontSize: 12, color: 'var(--color-muted)' }}>kopsumma</span> : (r.driver ? '—' : <select value={r.base || 'devSum'} onChange={e => setRole(i, 'base', e.target.value)} style={{ width: 100, fontSize: 12 }}>
                <option value="devSum">devSum</option>{cfg.roles.filter(x => x.driver && x.type !== 'coefficient').map(x => <option key={x.key} value={x.key}>{x.key}</option>)}</select>)}</td>
              <td style={{ textAlign: 'center' }}><input type="checkbox" checked={r.active !== false} onChange={e => setRole(i, 'active', e.target.checked)} /></td>
              <td style={{ textAlign: 'center' }}><button className="btn btn-outline btn-sm" title="Noņemt rindu" onClick={() => removeRole(i)}>✕</button></td>
            </tr>
            );
          })}
        </tbody>
      </table>
      <div style={{ display: 'flex', gap: 8, marginBottom: 16 }}>
        <button className="btn btn-outline btn-sm" onClick={() => addRole('hours')}>+ Pievienot lomu (stundas)</button>
        <button className="btn btn-outline btn-sm" onClick={() => addRole('coefficient')}>+ Pievienot koeficientu</button>
      </div>
      <div className="form-group" style={{ maxWidth: 200, marginBottom: 12 }}>
        <label>Risku rezerve (piem. 0.12 = 12%)</label>
        <input type="number" step="0.01" value={cfg.riskPercent || 0} onChange={e => setCfg({ ...cfg, riskPercent: Number(e.target.value) })} />
      </div>
      <button className="btn btn-primary" onClick={save}>Saglabāt konfigurāciju</button>
      <p style={{ fontSize: 12, color: 'var(--color-muted)', marginTop: 10 }}>
        „Koeficients" tipa rindas (piem. <b>Peļņa</b>) tiek piemērotas uz visu pārējo pozīciju kopsummu
        (stundu izmaksas + papildu izmaksas + risks). Koef. vērtība: 0.10 = 10%. Katram projektam konfigurācija ir atsevišķa.
      </p>
    </div>
  );
}

// ── Claude čata panelis ─────────────────────────────────────────────────────
function ChatPanel({ slug, onClose, docked }) {
  const [log, setLog] = useState([]);
  const [input, setInput] = useState('');
  const [sessionId, setSessionId] = useState(null);
  const [busy, setBusy] = useState(false);
  const endRef = useRef();
  useEffect(() => { endRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [log, busy]);

  const send = async () => {
    if (!input.trim() || busy) return;
    const msg = input.trim(); setInput('');
    setLog(l => [...l, { role: 'user', text: msg }]); setBusy(true);
    const r = await api.post(`/api/projects/${slug}/chat`, { message: msg, sessionId });
    setBusy(false);
    if (r?.error) { setLog(l => [...l, { role: 'assistant', text: 'Kļūda: ' + r.error }]); return; }
    setSessionId(r.sessionId);
    setLog(l => [...l, { role: 'assistant', text: r.reply || '(bez teksta atbildes)' }]);
    window.dispatchEvent(new Event('ae:reload')); // prasības varēja mainīties
  };

  return (
    <div className={'card chat-panel' + (docked ? ' chat-panel-docked' : '')}>
      <div className="chat-head">
        <div className="card-title" style={{ marginBottom: 0 }}>Claude panelis</div>
        {onClose && <span className="chat-close" onClick={onClose} title="Aizvērt">✕</span>}
      </div>
      <div className="chat-log">
        {log.length === 0 && <p style={{ color: 'var(--color-muted)' }}>Piem.: "Novērtē prasību LPA001", "Atrodi dublikātus", "Sagrupē prasības pa sadaļām".</p>}
        {log.map((m, i) => <div key={i} className={'chat-msg ' + (m.role === 'user' ? 'chat-user' : 'chat-assistant')}>{m.text}</div>)}
        {busy && <div className="chat-msg chat-assistant">Domā...</div>}
        <div ref={endRef} />
      </div>
      <div className="chat-input-row">
        <input value={input} placeholder="Raksti Claude..." onChange={e => setInput(e.target.value)}
          onKeyDown={e => e.key === 'Enter' && send()} />
        <button className="btn btn-primary" onClick={send} disabled={busy}>Sūtīt</button>
      </div>
    </div>
  );
}

// ── Definīciju sānpanelis ───────────────────────────────────────────────────
function DefinitionsPanel({ items, onClose }) {
  const defs = items.filter(i => i.type === 'definition');
  const [q, setQ] = useState('');
  const norm = s => (s || '').toLowerCase();
  const ql = norm(q.trim());
  const match = d => !ql || norm(d.title).includes(ql) || norm(d.description).includes(ql);
  const shown = defs.filter(match);
  return (
    <div className="defs-panel">
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <h3 style={{ marginBottom: 0 }}>Termini ({ql ? shown.length + '/' + defs.length : defs.length})</h3>
        <span style={{ cursor: 'pointer' }} onClick={onClose} title="Aizvērt">✕</span>
      </div>
      <input type="text" placeholder="Meklēt terminu..." value={q}
        onChange={e => setQ(e.target.value)} style={{ width: '100%', margin: '12px 0' }} autoFocus />
      <div className="defs-list">
        {defs.length === 0 ? <p style={{ color: 'var(--color-muted)' }}>Nav definīciju.</p> :
          shown.length === 0 ? <p style={{ color: 'var(--color-muted)' }}>Nav atbilstību meklētajam tekstam.</p> :
          shown.map(d => <div className="def-item" key={d.id}><b>{d.title}</b><span style={{ fontSize: 13 }}>{d.description}</span></div>)}
      </div>
      <button className="btn btn-outline" onClick={onClose} style={{ width: '100%', marginTop: 16 }}>Aizvērt paneli</button>
    </div>
  );
}

// ── Projekta skats ──────────────────────────────────────────────────────────
function ProjectView({ slug, onBack, chatOpen, onToggleChat }) {
  const [data, setData] = useState(null);
  const [tab, setTab] = useState('reqs');
  const [showDefs, setShowDefs] = useState(false);

  const reload = useCallback(async () => {
    const d = await api.get(`/api/projects/${slug}`);
    setData(d);
  }, [slug]);
  useEffect(() => { reload(); }, [reload]);
  useEffect(() => {
    const h = () => reload();
    window.addEventListener('ae:reload', h);
    return () => window.removeEventListener('ae:reload', h);
  }, [reload]);

  if (!data) return <div className="loading">Ielādē...</div>;
  if (data.error) return <div className="card">{data.error}</div>;

  const tabs = [['reqs', 'Prasības'], ['sources', 'Avoti'], ['config', 'Konfigurācija'], ['coverage', 'Pārklājums'], ['methodology', 'Metodoloģija'], ['notes', 'Pieraksti']];

  return (
    <div>
      <div className="page-header">
        <button className="btn btn-outline btn-sm" onClick={onBack} style={{ marginBottom: 8 }}>← Projekti</button>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <h1>{data.meta.name}</h1>
          <div style={{ display: 'flex', gap: 8 }}>
            <button className="btn btn-outline btn-sm" onClick={() => setShowDefs(s => !s)}>Termini</button>
            <button className={'btn btn-sm ' + (chatOpen ? 'btn-primary' : 'btn-outline')} onClick={onToggleChat}>Claude panelis</button>
          </div>
        </div>
        {data.meta.description && <p>{data.meta.description}</p>}
      </div>

      <div className="tabs">
        {tabs.map(([k, label]) => (
          <button key={k} className={'btn btn-sm ' + (tab === k ? 'btn-primary' : 'btn-outline')} onClick={() => setTab(k)}>{label}</button>
        ))}
      </div>

      {tab === 'reqs' && <RequirementsGrid slug={slug} data={data} reload={reload} />}
      {tab === 'sources' && <SourcesPanel slug={slug} meta={data.meta} reload={reload} />}
      {tab === 'config' && <ConfigEditor slug={slug} config={data.config} reload={reload} />}
      {tab === 'coverage' && <CoveragePanel slug={slug} />}
      {tab === 'methodology' && <MethodologyPanel slug={slug} />}
      {tab === 'notes' && <NotesPanel slug={slug} />}

      {showDefs && <DefinitionsPanel items={data.requirements.items || []} onClose={() => setShowDefs(false)} />}
    </div>
  );
}

// ── Iepirkumi (data.gov.lv izsludinātie iepirkumi) ──────────────────────────
const KLAS_META = {
  'ir-it':           { label: 'IT iepirkums',  short: 'IT',  color: '#15803d', bg: '#f0fdf4', border: '#bbf7d0' },
  'nav-drosi':       { label: 'Nav drošs',     short: '?',   color: '#b45309', bg: '#fffbeb', border: '#fde68a' },
  'nav-it':          { label: 'Nav IT',        short: 'Nav', color: '#475569', bg: '#f1f5f9', border: '#e2e8f0' },
  'nav-klasificets': { label: 'Neklasificēts', short: '—',   color: '#94a3b8', bg: 'transparent', border: '#e2e8f0' }
};
function klasMeta(k) { return KLAS_META[k] || KLAS_META['nav-klasificets']; }

function ClassifyControl({ value, onSet }) {
  const opts = [['ir-it', 'IT'], ['nav-drosi', '?'], ['nav-it', 'Nav']];
  return (
    <div style={{ display: 'inline-flex', gap: 2 }}>
      {opts.map(([k, lbl]) => {
        const active = value === k;
        const m = klasMeta(k);
        return (
          <button key={k} type="button" title={m.label} onClick={() => onSet(k)}
            style={{ fontSize: 11, padding: '2px 7px', borderRadius: 4, cursor: 'pointer',
              border: '1px solid ' + (active ? m.color : '#e2e8f0'),
              background: active ? m.bg : '#fff', color: active ? m.color : '#94a3b8',
              fontWeight: active ? 600 : 400 }}>{lbl}</button>
        );
      })}
    </div>
  );
}

const INTERESE_META = {
  apstrade: { label: 'Apstrādē', color: '#2563eb', bg: '#eff6ff', border: '#bfdbfe' },
  interese: { label: 'Interese', color: '#15803d', bg: '#f0fdf4', border: '#bbf7d0' },
  gatavo_pieteikumu: { label: 'Gatavo pieteikumu', color: '#d97706', bg: '#fffbeb', border: '#fde68a' },
  saglabats: { label: 'Saglabāts', color: '#7c3aed', bg: '#f5f3ff', border: '#ddd6fe' },
  atmests:  { label: 'Atmests',  color: '#b91c1c', bg: '#fef2f2', border: '#fecaca' }
};
function InteresControl({ value, onSet }) {
  const v = value || '';
  const m = INTERESE_META[v];
  return (
    <select value={v} title="Mūsu interese" onChange={e => onSet(e.target.value)}
      style={{ fontSize: 11, padding: '2px 4px', borderRadius: 4, cursor: 'pointer',
        border: '1px solid ' + (m ? m.color : '#e2e8f0'),
        background: m ? m.bg : '#fff', color: m ? m.color : '#94a3b8',
        fontWeight: m ? 600 : 400 }}>
      <option value="">—</option>
      <option value="apstrade">Apstrādē</option>
      <option value="interese">Interese</option>
      <option value="gatavo_pieteikumu">Gatavo pieteikumu</option>
      <option value="saglabats">Saglabāts</option>
      <option value="atmests">Atmests</option>
    </select>
  );
}

function KomentarsCell({ value, onSave }) {
  const [v, setV] = useState(value || '');
  useEffect(() => { setV(value || ''); }, [value]);
  const commit = () => { const t = v.trim(); if (t !== (value || '')) onSave(t); };
  return (
    <input type="text" value={v} placeholder="—" title={v}
      onChange={e => setV(e.target.value)} onBlur={commit}
      onKeyDown={e => { if (e.key === 'Enter') e.target.blur(); }}
      style={{ fontSize: 11, padding: '2px 4px', width: 150, border: '1px solid #e2e8f0', borderRadius: 4 }} />
  );
}
function KomentarsBox({ value, onSave }) {
  const [v, setV] = useState(value || '');
  useEffect(() => { setV(value || ''); }, [value]);
  const commit = () => { const t = v.trim(); if (t !== (value || '')) onSave(t); };
  return (
    <textarea value={v} onChange={e => setV(e.target.value)} onBlur={commit}
      placeholder="Pievieno komentāru…" rows={3}
      style={{ width: '100%', boxSizing: 'border-box', fontSize: 13, padding: 8, border: '1px solid #e2e8f0', borderRadius: 6, resize: 'vertical', fontFamily: 'inherit' }} />
  );
}

// Lauku grupas detaļu skatam (iepirkuma līmenis = rindas[0])
const IEP_FIELD_GROUPS = [
  ['Pamatinformācija', [
    ['Iepirkuma_ID', 'Iepirkuma ID'], ['Iepirkuma_nosaukums', 'Nosaukums'],
    ['Iepirkuma_identifikacijas_numurs', 'Identifikācijas numurs'], ['Iepirkuma_statuss', 'Statuss'],
    ['Iepirkuma_prieksmeta_veids', 'Priekšmeta veids'], ['Proceduras_veids', 'Procedūras veids'],
    ['Regulejosais_tiesibu_akts', 'Regulējošais tiesību akts']
  ]],
  ['Pasūtītājs', [
    ['Pasutitaja_nosaukums', 'Nosaukums'], ['Pasutitaja_registracijas_numurs', 'Reģistrācijas numurs'],
    ['Pasutitaja_registracijas_numura_veids', 'Reģ. numura veids'], ['Pasutitaja_PVS_ID', 'PVS ID'],
    ['Augstak_stavosa_organizacija', 'Augstāk stāvošā organizācija'], ['Citu_pasutitaju_vajadzibam', 'Citu pasūtītāju vajadzībām'],
    ['Faktiskais_sanemejs', 'Faktiskais saņēmējs'], ['Pasutitaja_kontaktpersona', 'Kontaktpersona']
  ]],
  ['CPV un priekšmets', [
    ['CPV_kods_galvenais_prieksmets', 'CPV galvenais'], ['CPV_kodi_papildus_prieksmeti', 'CPV papildus'],
    ['Precu_vai_pakalpojumu_sniegsanas_vieta', 'Sniegšanas vieta']
  ]],
  ['Termiņi un iesniegšana', [
    ['Iepirkuma_izsludinasanas_datums', 'Izsludināts'], ['Piedavajumu_iesniegsanas_datums', 'Piedāvājumu iesniegšana'],
    ['Piedavajumu_iesniegsanas_laiks', 'Iesniegšanas laiks'], ['Iesniegsanas_vieta', 'Iesniegšanas vieta'],
    ['Piedavajuma_iesniegsanas_valoda', 'Valoda'], ['Ieintereseto_personu_sanaksmes', 'Ieinteresēto personu sanāksmes']
  ]],
  ['Līgums', [
    ['Planotais_liguma_darbibas_termina_termina_veids', 'Termiņa veids'], ['Planotais_liguma_darbibas_termins', 'Termiņš'],
    ['Planota_liguma_darbibas_termina_mervieniba', 'Termiņa mērvienība'], ['Planota_liguma_izpilde_no', 'Izpilde no'],
    ['Planota_liguma_izpilde_lidz', 'Izpilde līdz'], ['Ligumcenas_veids', 'Līgumcenas veids'],
    ['Planota_ligumcena', 'Plānotā līgumcena'], ['Planota_ligumcena_no', 'Līgumcena no'],
    ['Planota_ligumcena_lidz', 'Līgumcena līdz'], ['Ligumcenas_valuta', 'Valūta']
  ]],
  ['Cits', [
    ['Atsauce_uz_ES_projektiem_un_programmam', 'ES projekti/programmas'], ['Vai_pielaujami_piedavajuma_varianti', 'Pieļaujami varianti'],
    ['Uzvaretaja_izveles_metode', 'Uzvarētāja izvēles metode'], ['Ir_dalijums_dalas', 'Dalījums daļās'],
    ['Dalu_iesniegsanas_nosacijumi', 'Daļu iesniegšanas nosacījumi']
  ]]
];
const IEP_LINK_FIELDS = [
  ['Hipersaite_EIS_kura_pieejams_zinojums', 'EIS publikācija'],
  ['Hipersaite_uz_IUB_publikaciju', 'IUB publikācija']
];
const IEP_PART_FIELDS = [
  ['Iepirkuma_dalas_nr', 'Nr.'], ['Iepirkuma_dalas_nosaukums', 'Nosaukums'], ['Iepirkuma_dalas_statuss', 'Statuss'],
  ['Dalas_planota_ligumcena', 'Līgumcena'], ['Dalas_planota_ligumcena_no', 'Cena no'], ['Dalas_planota_ligumcena_lidz', 'Cena līdz'],
  ['Dalas_ligumcenas_valuta', 'Val.'], ['Dalas_planota_liguma_izpilde_no', 'Izpilde no'], ['Dalas_planota_liguma_izpilde_lidz', 'Izpilde līdz']
];
function iepFmt(v) {
  if (v == null || v === '') return null;
  if (typeof v === 'string' && /^\d{4}-\d{2}-\d{2}T/.test(v)) { const d = new Date(v); if (!isNaN(d)) return d.toLocaleDateString('lv-LV'); }
  return String(v);
}

function IepirkumiDetail({ id, year, onClose, onClassify, onInterese, onKomentars }) {
  const [rec, setRec] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let alive = true;
    setLoading(true);
    api.get('/api/iepirkumi/' + id + (year ? '?year=' + year : '')).then(r => {
      if (!alive) return;
      setRec(r && r.records && r.records[0] ? r.records[0] : null);
      setLoading(false);
    });
    return () => { alive = false; };
  }, [id, year]);

  const head = rec && rec.rindas && rec.rindas[0];
  const klas = rec && rec.meta && rec.meta.itKlasifikacija ? rec.meta.itKlasifikacija : 'nav-klasificets';
  const interese = rec && rec.meta && rec.meta.interese ? rec.meta.interese : '';
  const komentars = rec && rec.meta && rec.meta.komentars ? rec.meta.komentars : '';
  const am = rec ? klasMeta(rec.auto) : null;
  const isParts = head && head.Ir_dalijums_dalas === 'Jā' && rec.rindas.length > 0;

  const doClassify = k => {
    setRec(r => r ? { ...r, meta: { ...(r.meta || {}), itKlasifikacija: k, klasificejis: 'user', atjauninats: new Date().toISOString() } } : r);
    onClassify(id, k);
  };
  const doInterese = val => {
    setRec(r => r ? { ...r, meta: { ...(r.meta || {}), interese: val || undefined } } : r);
    onInterese(id, val);
  };
  const doKomentars = text => {
    setRec(r => r ? { ...r, meta: { ...(r.meta || {}), komentars: text || undefined } } : r);
    onKomentars(id, text);
  };

  const row = (label, val) => {
    const f = iepFmt(val);
    if (f == null) return null;
    return (
      <div key={label} style={{ display: 'flex', gap: 10, padding: '4px 0', borderBottom: '1px solid #f1f5f9' }}>
        <div style={{ flex: '0 0 210px', color: 'var(--color-muted)', fontSize: 12 }}>{label}</div>
        <div style={{ flex: 1, fontSize: 13, whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}>{f}</div>
      </div>
    );
  };

  return (
    <div className="iep-modal-overlay" onClick={onClose}>
      <div className="iep-modal" onClick={e => e.stopPropagation()}>
        <div className="iep-modal-head">
          <div style={{ minWidth: 0 }}>
            <div style={{ fontSize: 12, color: 'var(--color-muted)' }}>Iepirkuma ID {id}</div>
            <h2 style={{ margin: '2px 0 0', fontSize: 17 }}>{head ? head.Iepirkuma_nosaukums : 'Ielādē…'}</h2>
          </div>
          <button className="btn btn-outline btn-sm" onClick={onClose}>✕</button>
        </div>

        {loading ? <div className="loading" style={{ padding: 24 }}>Ielādē…</div> : !rec ? <div style={{ padding: 24 }}>Nav atrasts.</div> : (
          <div className="iep-modal-body">
            <div className="card" style={{ display: 'flex', alignItems: 'center', gap: 16, flexWrap: 'wrap' }}>
              <div><span style={{ fontSize: 12, color: 'var(--color-muted)', marginRight: 6 }}>Klasifikācija:</span>
                <ClassifyControl value={klas} onSet={doClassify} /></div>
              <div><span style={{ fontSize: 12, color: 'var(--color-muted)', marginRight: 6 }}>Interese:</span>
                <InteresControl value={interese} onSet={doInterese} /></div>
              <div style={{ fontSize: 12, color: 'var(--color-muted)' }}>CPV ieteic: <span style={{ color: am.color, fontWeight: 600 }}>{am.label}</span></div>
              {rec.meta && rec.meta.klasificejis ? <div style={{ fontSize: 12, color: 'var(--color-muted)' }}>
                Klasificēja: {rec.meta.klasificejis}{rec.meta.atjauninats ? ' · ' + new Date(rec.meta.atjauninats).toLocaleDateString('lv-LV') : ''}</div> : null}
            </div>

            <div className="card">
              <div className="card-title">Komentārs</div>
              <KomentarsBox value={komentars} onSave={doKomentars} />
            </div>

            {IEP_FIELD_GROUPS.map(g => {
              const rows = g[1].map(f => row(f[1], head[f[0]])).filter(Boolean);
              if (!rows.length) return null;
              return <div className="card" key={g[0]}><div className="card-title">{g[0]}</div>{rows}</div>;
            })}

            {(head.Hipersaite_EIS_kura_pieejams_zinojums || head.Hipersaite_uz_IUB_publikaciju) ? (
              <div className="card"><div className="card-title">Saites</div>
                {IEP_LINK_FIELDS.map(f => head[f[0]] ? (
                  <div key={f[0]} style={{ padding: '4px 0' }}><a href={head[f[0]]} target="_blank" rel="noopener noreferrer">{f[1]} ↗</a></div>
                ) : null)}
              </div>
            ) : null}

            {isParts ? (
              <div className="card"><div className="card-title">Daļas ({rec.rindas.length})</div>
                <div style={{ overflowX: 'auto' }}>
                  <table className="iep-table">
                    <thead><tr>{IEP_PART_FIELDS.map(f => <th key={f[0]}>{f[1]}</th>)}</tr></thead>
                    <tbody>{rec.rindas.map((p, i) => (
                      <tr key={i}>{IEP_PART_FIELDS.map(f => <td key={f[0]} style={{ fontSize: 12 }}>{iepFmt(p[f[0]]) || '—'}</td>)}</tr>
                    ))}</tbody>
                  </table>
                </div>
              </div>
            ) : null}
          </div>
        )}
      </div>
    </div>
  );
}

const DEFAULT_IEP_FILTERS = { klasifikacija: '', auto: '', search: '', cpvPrefix: '', statuss: '', iesniegsanaNo: '', iesniegsanaLidz: '', interese: '' };
const IEP_FILTERS_KEY = 'ae_iep_filters';
function loadIepFilters() {
  try {
    const raw = localStorage.getItem(IEP_FILTERS_KEY);
    if (raw) return Object.assign({}, DEFAULT_IEP_FILTERS, JSON.parse(raw));
  } catch {}
  return Object.assign({}, DEFAULT_IEP_FILTERS);
}

function IepirkumiView() {
  const [summary, setSummary] = useState(null);
  const [data, setData] = useState({ records: [], matched: 0, total: 0 });
  const [filters, setFilters] = useState(loadIepFilters);
  const [searchInput, setSearchInput] = useState(() => loadIepFilters().search);
  const [offset, setOffset] = useState(0);
  const [loading, setLoading] = useState(false);
  const [syncing, setSyncing] = useState(false);
  const [alert, setAlert] = useState(null);
  const [detailId, setDetailId] = useState(null);
  const limit = 50;

  const loadSummary = useCallback(async () => {
    const s = await api.get('/api/iepirkumi/summary');
    if (s && !s.error) setSummary(s);
  }, []);
  const loadList = useCallback(async (off, f) => {
    setLoading(true);
    const qs = new URLSearchParams();
    qs.set('limit', limit); qs.set('offset', off);
    ['klasifikacija', 'auto', 'search', 'cpvPrefix', 'statuss', 'iesniegsanaNo', 'iesniegsanaLidz', 'interese'].forEach(k => { if (f[k]) qs.set(k, f[k]); });
    const r = await api.get('/api/iepirkumi?' + qs.toString());
    setLoading(false);
    if (r && !r.error) setData(r);
    else setAlert({ type: 'error', message: (r && r.error) || 'Kļūda ielādējot' });
  }, []);

  useEffect(() => { loadSummary(); }, [loadSummary]);
  useEffect(() => { loadList(offset, filters); }, [offset, filters, loadList]);
  useEffect(() => { try { localStorage.setItem(IEP_FILTERS_KEY, JSON.stringify(filters)); } catch {} }, [filters]);

  const setFilter = patch => { setOffset(0); setFilters(f => ({ ...f, ...patch })); };
  const doSearch = () => setFilter({ search: searchInput.trim() });
  const clearFilters = () => { setSearchInput(''); setOffset(0); setFilters(Object.assign({}, DEFAULT_IEP_FILTERS)); };

  const sync = async () => {
    setSyncing(true); setAlert(null);
    const r = await api.post('/api/iepirkumi/sync', {});
    setSyncing(false);
    if (r && r.error) { setAlert({ type: 'error', message: 'Sinhronizācija neizdevās: ' + r.error }); return; }
    setAlert({ type: 'success', message: 'Sinhronizēts: ' + r.fetched + ' ieraksti (' + Math.round((r.durationMs || 0) / 1000) + ' s)' });
    loadSummary(); loadList(offset, filters);
  };

  const classify = async (rec, klas) => {
    setData(d => ({ ...d, records: d.records.map(x => x.id === rec.id ? { ...x, klasifikacija: klas } : x) }));
    const r = await api.post('/api/iepirkumi/classify', { items: [{ iepirkumaId: rec.id, klasifikacija: klas }], actor: 'user' });
    if (r && r.error) { setAlert({ type: 'error', message: r.error }); loadList(offset, filters); return; }
    loadSummary();
  };
  const setInterese = async (rec, val) => {
    setData(d => ({ ...d, records: d.records.map(x => x.id === rec.id ? { ...x, meta: Object.assign({}, x.meta || {}, { interese: val || undefined }) } : x) }));
    const r = await api.post('/api/iepirkumi/interese', { items: [{ iepirkumaId: rec.id, interese: val }], actor: 'user' });
    if (r && r.error) { setAlert({ type: 'error', message: r.error }); loadList(offset, filters); return; }
    loadSummary();
  };
  const setKomentars = async (rec, text) => {
    setData(d => ({ ...d, records: d.records.map(x => x.id === rec.id ? { ...x, meta: Object.assign({}, x.meta || {}, { komentars: text || undefined }) } : x) }));
    const r = await api.post('/api/iepirkumi/komentars', { items: [{ iepirkumaId: rec.id, komentars: text }], actor: 'user' });
    if (r && r.error) { setAlert({ type: 'error', message: r.error }); loadList(offset, filters); return; }
  };

  const c = summary && summary.counts;
  const ac = summary && summary.autoCounts;
  const filtered = filters.search || filters.cpvPrefix || filters.klasifikacija || filters.auto || filters.statuss || filters.iesniegsanaNo || filters.iesniegsanaLidz || filters.interese;

  return (
    <div>
      <div className="page-header">
        <h1>Iepirkumi</h1>
        <p>data.gov.lv izsludinātie iepirkumi{summary ? ' · ' + summary.year + '. gads' : ''}</p>
      </div>

      <Alert type={alert ? alert.type : ''} message={alert ? alert.message : ''} onClose={() => setAlert(null)} />

      <div className="card" style={{ display: 'flex', flexWrap: 'wrap', gap: 16, alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 16, fontSize: 13 }}>
          <span><b>{c ? c.total : '…'}</b> iepirkumi</span>
          <span style={{ color: '#15803d' }}>IT: <b>{c ? c['ir-it'] : '…'}</b></span>
          <span style={{ color: '#b45309' }}>Nav drošs: <b>{c ? c['nav-drosi'] : '…'}</b></span>
          <span style={{ color: '#475569' }}>Nav IT: <b>{c ? c['nav-it'] : '…'}</b></span>
          <span style={{ color: '#94a3b8' }}>Neklasificēti: <b>{c ? c['nav-klasificets'] : '…'}</b></span>
          {ac ? <span style={{ color: '#94a3b8' }}>· CPV ieteic IT: {ac['ir-it']}, ?: {ac['nav-drosi']}</span> : null}
          {summary && summary.interesCounts ? <span style={{ color: '#2563eb' }}>· Apstrādē: {summary.interesCounts.apstrade} · Interese: {summary.interesCounts.interese} · Gatavo pieteikumu: {summary.interesCounts.gatavo_pieteikumu} · Saglabāts: {summary.interesCounts.saglabats} · Atmests: {summary.interesCounts.atmests}</span> : null}
        </div>
        <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
          <span style={{ fontSize: 12, color: 'var(--color-muted)' }}>
            {summary && summary.lastSync ? 'Sinhr.: ' + new Date(summary.lastSync).toLocaleString('lv-LV') : 'Vēl nav sinhronizēts'}
          </span>
          <button className="btn btn-primary btn-sm" onClick={sync} disabled={syncing}>{syncing ? 'Sinhronizē…' : '↻ Atjaunot datus'}</button>
        </div>
      </div>

      <div className="card" style={{ display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center' }}>
        <select value={filters.klasifikacija} onChange={e => setFilter({ klasifikacija: e.target.value })}>
          <option value="">Klasifikācija: visi</option>
          <option value="nav-klasificets">Neklasificēti</option>
          <option value="ir-it">IT</option>
          <option value="nav-drosi">Nav drošs</option>
          <option value="nav-it">Nav IT</option>
        </select>
        <select value={filters.auto} onChange={e => setFilter({ auto: e.target.value })}>
          <option value="">CPV ieteikums: visi</option>
          <option value="ir-it">Ieteic IT</option>
          <option value="nav-drosi">Ieteic ?</option>
          <option value="nav-it">Ieteic nav IT</option>
        </select>
        <select value={filters.statuss} onChange={e => setFilter({ statuss: e.target.value })}>
          <option value="">Statuss: visi</option>
          {(summary && summary.statuses ? summary.statuses : []).map(s => <option key={s} value={s}>{s}</option>)}
        </select>
        <select value={filters.interese} onChange={e => setFilter({ interese: e.target.value })}>
          <option value="">Interese: visi</option>
          <option value="none">Nav atzīmēts</option>
          <option value="apstrade">Apstrādē</option>
          <option value="interese">Interese</option>
          <option value="gatavo_pieteikumu">Gatavo pieteikumu</option>
          <option value="saglabats">Saglabāts</option>
          <option value="atmests">Atmests</option>
        </select>
        <label style={{ display: 'flex', alignItems: 'center', gap: 4, fontSize: 12, color: 'var(--color-muted)' }}>
          Iesniegts no
          <input type="date" value={filters.iesniegsanaNo} onChange={e => setFilter({ iesniegsanaNo: e.target.value })} />
        </label>
        <label style={{ display: 'flex', alignItems: 'center', gap: 4, fontSize: 12, color: 'var(--color-muted)' }}>
          līdz
          <input type="date" value={filters.iesniegsanaLidz} onChange={e => setFilter({ iesniegsanaLidz: e.target.value })} />
        </label>
        <input placeholder="CPV (piem. 72)" value={filters.cpvPrefix} style={{ width: 110 }}
          onChange={e => setFilter({ cpvPrefix: e.target.value })} />
        <input placeholder="Meklēt nosaukumā / pasūtītājā…" value={searchInput} style={{ flex: 1, minWidth: 180 }}
          onChange={e => setSearchInput(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') doSearch(); }} />
        <button className="btn btn-outline btn-sm" onClick={doSearch}>Meklēt</button>
        {filtered ? <button className="btn btn-outline btn-sm" onClick={clearFilters}>Notīrīt</button> : null}
      </div>

      <div className="card" style={{ padding: 0, overflowX: 'auto' }}>
        <table className="iep-table">
          <thead>
            <tr>
              <th>ID</th><th>Nosaukums</th><th>Pasūtītājs</th><th>CPV</th>
              <th>Statuss</th><th>Izsludināts</th><th>Iesniegšana</th><th>CPV iet.</th><th>Klasifikācija</th><th>Interese</th><th>Komentārs</th>
            </tr>
          </thead>
          <tbody>
            {loading ? (
              <tr><td colSpan={11} style={{ textAlign: 'center', padding: 24, color: 'var(--color-muted)' }}>Ielādē…</td></tr>
            ) : data.records.length === 0 ? (
              <tr><td colSpan={11} style={{ textAlign: 'center', padding: 24, color: 'var(--color-muted)' }}>Nav ierakstu. Ja vēl nav sinhronizēts, spied “Atjaunot datus”.</td></tr>
            ) : data.records.map(r => {
              const am = klasMeta(r.auto);
              return (
                <tr key={r.id}>
                  <td style={{ whiteSpace: 'nowrap' }}>
                    <a onClick={() => setDetailId(r.id)} style={{ cursor: 'pointer', color: 'var(--color-primary, #2563eb)' }} title="Skatīt detaļas">{r.id}</a>
                  </td>
                  <td style={{ maxWidth: 340 }}>
                    {r.hipersaiteEis ? <a href={r.hipersaiteEis} target="_blank" rel="noopener noreferrer">{r.nosaukums}</a> : r.nosaukums}
                    {r.idNr ? <div style={{ fontSize: 11, color: 'var(--color-muted)' }}>{r.idNr}{r.dalas > 0 ? ' · ' + r.dalas + ' daļas' : ''}</div> : null}
                  </td>
                  <td style={{ maxWidth: 170, fontSize: 12 }}>{r.pasutitajs}</td>
                  <td style={{ fontSize: 11, maxWidth: 150 }} title={r.cpvGalvenais}>{(r.cpvGalvenais || '').slice(0, 28)}</td>
                  <td style={{ fontSize: 12, whiteSpace: 'nowrap' }}>{r.statuss}</td>
                  <td style={{ fontSize: 12, whiteSpace: 'nowrap' }}>{r.izsludinats}</td>
                  <td style={{ fontSize: 12, whiteSpace: 'nowrap' }}>{r.iesniegsana}</td>
                  <td><span style={{ fontSize: 10, padding: '1px 5px', borderRadius: 3, color: am.color, background: am.bg, border: '1px solid ' + am.border }}>{am.short}</span></td>
                  <td><ClassifyControl value={r.klasifikacija} onSet={k => classify(r, k)} /></td>
                  <td><InteresControl value={r.meta && r.meta.interese} onSet={val => setInterese(r, val)} /></td>
                  <td><KomentarsCell value={r.meta && r.meta.komentars} onSave={t => setKomentars(r, t)} /></td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 12, fontSize: 13 }}>
        <span style={{ color: 'var(--color-muted)' }}>
          {data.matched > 0 ? (offset + 1) + '–' + Math.min(offset + limit, data.matched) + ' no ' + data.matched : '0'}
          {data.matched !== data.total ? ' (filtrēti no ' + data.total + ')' : ''}
        </span>
        <div style={{ display: 'flex', gap: 8 }}>
          <button className="btn btn-outline btn-sm" disabled={offset === 0} onClick={() => setOffset(Math.max(0, offset - limit))}>‹ Iepriekšējie</button>
          <button className="btn btn-outline btn-sm" disabled={offset + limit >= data.matched} onClick={() => setOffset(offset + limit)}>Nākamie ›</button>
        </div>
      </div>

      {detailId ? <IepirkumiDetail id={detailId} year={summary ? summary.year : null}
        onClose={() => setDetailId(null)} onClassify={(id, k) => classify({ id }, k)} onInterese={(id, val) => setInterese({ id }, val)} onKomentars={(id, text) => setKomentars({ id }, text)} /> : null}
    </div>
  );
}

// ── App ─────────────────────────────────────────────────────────────────────
function parseHash() {
  const m = location.hash.match(/^#project\/(.+)$/);
  if (m) return { view: 'project', slug: m[1] };
  if (location.hash === '#iepirkumi') return { view: 'iepirkumi' };
  return { view: 'list' };
}

function App() {
  const [route, setRoute] = useState(parseHash);
  const [authed, setAuthed] = useState(null);
  const [collapsed, setCollapsed] = useState(() => { try { return localStorage.getItem('ae_sidebar') === '1'; } catch { return false; } });
  const [chatOpen, setChatOpen] = useState(false);

  useEffect(() => {
    fetch('/api/auth-check').then(r => r.json()).then(d => {
      if (!d.authenticated) location.href = '/login.html'; else setAuthed(true);
    }).catch(() => location.href = '/login.html');
  }, []);
  useEffect(() => {
    const h = () => setRoute(parseHash());
    addEventListener('hashchange', h); return () => removeEventListener('hashchange', h);
  }, []);
  useEffect(() => { if (route.view !== 'project') setChatOpen(false); }, [route.view]);

  const open = slug => { location.hash = 'project/' + slug; };
  const back = () => { location.hash = ''; };
  const goIepirkumi = () => { location.hash = 'iepirkumi'; };
  const logout = async () => { await fetch('/api/logout', { method: 'POST' }); location.href = '/login.html'; };
  const toggleSidebar = () => setCollapsed(c => { const n = !c; try { localStorage.setItem('ae_sidebar', n ? '1' : '0'); } catch {} return n; });

  if (!authed) return <div className="loading">Ielādē...</div>;

  return (
    <div className={'app-layout' + (collapsed ? ' sidebar-collapsed' : '') + (chatOpen ? ' chat-open' : '')}>
      <aside className="sidebar">
        <div className="sidebar-header">
          <div className="sidebar-brand"><h2>Amber Esti</h2><p>Tāmēšanas sistēma</p></div>
          <button className="sidebar-toggle" onClick={toggleSidebar} title={collapsed ? 'Izvērst izvēlni' : 'Sakļaut izvēlni'}>{collapsed ? '»' : '«'}</button>
        </div>
        <nav className="sidebar-nav">
          <div className={'nav-item' + (route.view === 'list' ? ' active' : '')} onClick={back} title="Projekti">
            <span className="nav-icon">◈</span><span className="nav-label">Projekti</span>
          </div>
          <div className={'nav-item' + (route.view === 'iepirkumi' ? ' active' : '')} onClick={goIepirkumi} title="Iepirkumi">
            <span className="nav-icon">▤</span><span className="nav-label">Iepirkumi</span>
          </div>
        </nav>
        <div className="sidebar-footer">
          <button className="btn btn-outline btn-full" onClick={logout} title="Iziet">
            <span className="nav-icon">⎋</span><span className="nav-label">Iziet</span>
          </button>
        </div>
      </aside>
      <main className="main-content">
        {route.view === 'project'
          ? <ProjectView slug={route.slug} onBack={back} chatOpen={chatOpen} onToggleChat={() => setChatOpen(o => !o)} />
          : route.view === 'iepirkumi'
            ? <IepirkumiView />
            : <ProjectsList onOpen={open} />}
      </main>
      {chatOpen && route.view === 'project' && <ChatPanel slug={route.slug} onClose={() => setChatOpen(false)} docked />}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);

// ── Pārklājuma panelis (izsekojamība) ───────────────────────────────────────
function CoveragePanel({ slug }) {
  const [cov, setCov] = useState(null);
  useEffect(() => { api.get(`/api/projects/${slug}/coverage`).then(setCov); }, [slug]);
  if (!cov) return <div className="loading">Ielādē...</div>;
  if (cov.error) return <div className="card">{cov.error}</div>;

  return (
    <div>
      <div className="totals-bar">
        <span>Prasības: <b>{cov.summary.requirements}</b></span>
        <span>Novērtētas: <b>{cov.summary.estimated}</b></span>
        <span>Ar izsekojamību: <b>{cov.summary.withProvenance}/{cov.summary.requirements}</b></span>
      </div>
      {cov.groups.filter(g => g.total > 0).map(g => (
        <div className="card" key={g.source.id}>
          <div className="card-title">{g.source.name} — {g.total} prasības ({g.estimated} novērtētas
            {g.missingProvenance > 0 && <span style={{ color: 'var(--color-warn)' }}>, {g.missingProvenance} bez atsauces</span>})</div>
          <table className="req-table">
            <thead><tr><th>ID</th><th>Prasība</th><th>Vieta dok.</th><th>Statuss</th></tr></thead>
            <tbody>
              {g.items.map(it => (
                <tr key={it.id}>
                  <td>{it.id}</td>
                  <td style={{ maxWidth: 360 }}>
                    <div style={{ fontWeight: 500 }}>{it.title}</div>
                    {it.originalText && <div style={{ fontSize: 11, color: 'var(--color-muted)', marginTop: 2 }}>„{it.originalText.slice(0, 200)}{it.originalText.length > 200 ? '…' : ''}”</div>}
                  </td>
                  <td>{it.location || <span style={{ color: 'var(--color-warn)' }}>—</span>}</td>
                  <td><span className={'status-pill ' + (it.status === 'estimated' ? 'status-estimated' : 'status-unestimated')}>{it.status === 'estimated' ? 'nov.' : 'nenov.'}</span></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      ))}
      {cov.noSource.length > 0 && (
        <div className="card">
          <div className="card-title" style={{ color: 'var(--color-warn)' }}>Bez avota atsauces ({cov.noSource.length})</div>
          <p style={{ fontSize: 13, color: 'var(--color-muted)' }}>Šīs prasības nav piesaistītas dokumentam (manuāli pievienotas vai bez izsekojamības): {cov.noSource.map(i => i.id).join(', ')}</p>
        </div>
      )}
    </div>
  );
}

// ── Novērtēšanas metodoloģija ────────────────────────────────────────────────
function MethodologyPanel({ slug }) {
  const edRef = useRef(null);
  const [initialHtml, setInitialHtml] = useState(null);
  const [updatedAt, setUpdatedAt] = useState(null);
  const [dirty, setDirty] = useState(false);
  const [saving, setSaving] = useState(false);
  const [status, setStatus] = useState(null);

  useEffect(() => {
    let alive = true;
    setInitialHtml(null);
    api.get(`/api/projects/${slug}/methodology`).then(n => {
      if (!alive) return;
      setInitialHtml((n && n.content) || '');
      setUpdatedAt((n && n.updatedAt) || null);
      setDirty(false);
    });
    return () => { alive = false; };
  }, [slug]);

  const exec = (cmd, val) => {
    document.execCommand(cmd, false, val || null);
    if (edRef.current) edRef.current.focus();
    if (!dirty) setDirty(true);
  };

  const save = async () => {
    if (!edRef.current) return;
    setSaving(true); setStatus(null);
    const content = edRef.current.innerHTML;
    const res = await api.put(`/api/projects/${slug}/methodology`, { content });
    setSaving(false);
    if (res && res.error) { setStatus({ type: 'error', message: res.error }); return; }
    setUpdatedAt((res && res.updatedAt) || new Date().toISOString());
    setDirty(false);
    setStatus({ type: 'success', message: 'Metodoloģija saglabāta' });
  };

  if (initialHtml === null) return <div className="loading">Ielādē...</div>;

  const tbtn = (label, title, handler, st) => (
    <button type="button" className="btn btn-sm btn-outline" title={title} style={st}
      onMouseDown={e => { e.preventDefault(); handler(); }}>{label}</button>
  );

  return (
    <div className="card">
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12, flexWrap: 'wrap', gap: 8 }}>
        <div className="card-title" style={{ marginBottom: 0 }}>Novērtēšanas metodoloģija</div>
        <span style={{ fontSize: 12, color: dirty ? 'var(--color-warn)' : 'var(--color-muted)' }}>
          {dirty ? '● Nesaglabātas izmaiņas' : (updatedAt ? 'Saglabāts: ' + new Date(updatedAt).toLocaleString('lv-LV') : 'Vēl nav saglabāts')}
        </span>
      </div>
      <p style={{ fontSize: 13, color: 'var(--color-muted)', marginBottom: 12 }}>
        Apraksti projekta novērtēšanas pieeju — tehnoloģiju, arhitektoniskos apsvērumus, pieņēmumus un citus faktorus, kas ietekmē novērtējumu.
      </p>

      <Alert type={status ? status.type : ''} message={status ? status.message : ''} onClose={() => setStatus(null)} />

      <div className="notes-toolbar">
        {tbtn('B', 'Treknraksts', () => exec('bold'), { fontWeight: 700 })}
        {tbtn('I', 'Slīpraksts', () => exec('italic'), { fontStyle: 'italic' })}
        {tbtn('U', 'Pasvītrots', () => exec('underline'), { textDecoration: 'underline' })}
        {tbtn('H', 'Virsraksts', () => exec('formatBlock', 'H3'))}
        {tbtn('¶', 'Parastais teksts', () => exec('formatBlock', 'P'))}
        {tbtn('• Saraksts', 'Aizzīmju saraksts', () => exec('insertUnorderedList'))}
        {tbtn('1. Saraksts', 'Numurēts saraksts', () => exec('insertOrderedList'))}
        {tbtn('Notīrīt formātu', 'Noņemt formatējumu', () => exec('removeFormat'))}
      </div>
      <div ref={edRef} className="notes-editor" contentEditable suppressContentEditableWarning
        onInput={() => { if (!dirty) setDirty(true); }}
        dangerouslySetInnerHTML={{ __html: initialHtml }} />
      <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>
        <button className="btn btn-primary btn-sm" onClick={save} disabled={saving || !dirty}>
          {saving ? 'Saglabā...' : 'Saglabāt'}
        </button>
      </div>
    </div>
  );
}

// ── Novērtējuma pieraksti (neatkarīgs rich-text bloks) ──────────────────────
function NotesPanel({ slug }) {
  const edRef = useRef(null);
  const [initialHtml, setInitialHtml] = useState(null); // null = vēl ielādējas
  const [updatedAt, setUpdatedAt] = useState(null);
  const [dirty, setDirty] = useState(false);
  const [saving, setSaving] = useState(false);
  const [status, setStatus] = useState(null);

  useEffect(() => {
    let alive = true;
    setInitialHtml(null);
    api.get(`/api/projects/${slug}/notes`).then(n => {
      if (!alive) return;
      setInitialHtml((n && n.content) || '');
      setUpdatedAt((n && n.updatedAt) || null);
      setDirty(false);
    });
    return () => { alive = false; };
  }, [slug]);

  const exec = (cmd, val) => {
    document.execCommand(cmd, false, val || null);
    if (edRef.current) edRef.current.focus();
    if (!dirty) setDirty(true);
  };

  const save = async () => {
    if (!edRef.current) return;
    setSaving(true); setStatus(null);
    const content = edRef.current.innerHTML;
    const res = await api.put(`/api/projects/${slug}/notes`, { content });
    setSaving(false);
    if (res && res.error) { setStatus({ type: 'error', message: res.error }); return; }
    setUpdatedAt((res && res.updatedAt) || new Date().toISOString());
    setDirty(false);
    setStatus({ type: 'success', message: 'Pieraksti saglabāti' });
  };

  if (initialHtml === null) return <div className="loading">Ielādē...</div>;

  const tbtn = (label, title, handler, st) => (
    <button type="button" className="btn btn-sm btn-outline" title={title} style={st}
      onMouseDown={e => { e.preventDefault(); handler(); }}>{label}</button>
  );

  return (
    <div className="card">
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12, flexWrap: 'wrap', gap: 8 }}>
        <div className="card-title" style={{ marginBottom: 0 }}>Novērtējuma pieraksti</div>
        <span style={{ fontSize: 12, color: dirty ? 'var(--color-warn)' : 'var(--color-muted)' }}>
          {dirty ? '● Nesaglabātas izmaiņas' : (updatedAt ? 'Saglabāts: ' + new Date(updatedAt).toLocaleString('lv-LV') : 'Vēl nav saglabāts')}
        </span>
      </div>

      <Alert type={status ? status.type : ''} message={status ? status.message : ''} onClose={() => setStatus(null)} />

      <div className="notes-toolbar">
        {tbtn('B', 'Treknraksts', () => exec('bold'), { fontWeight: 700 })}
        {tbtn('I', 'Slīpraksts', () => exec('italic'), { fontStyle: 'italic' })}
        {tbtn('U', 'Pasvītrots', () => exec('underline'), { textDecoration: 'underline' })}
        {tbtn('H', 'Virsraksts', () => exec('formatBlock', 'H3'))}
        {tbtn('¶', 'Parastais teksts', () => exec('formatBlock', 'P'))}
        {tbtn('• Saraksts', 'Aizzīmju saraksts', () => exec('insertUnorderedList'))}
        {tbtn('1. Saraksts', 'Numurēts saraksts', () => exec('insertOrderedList'))}
        {tbtn('Notīrīt formātu', 'Noņemt formatējumu', () => exec('removeFormat'))}
      </div>

      <div ref={edRef} className="notes-editor" contentEditable={true}
        data-placeholder="Raksti šeit piezīmes par novērtējumu…"
        onInput={() => { if (!dirty) setDirty(true); }}
        suppressContentEditableWarning={true}
        dangerouslySetInnerHTML={{ __html: initialHtml }} />

      <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 12 }}>
        <button className="btn btn-primary" onClick={save} disabled={saving}>
          {saving ? 'Saglabā…' : 'Saglabāt'}
        </button>
      </div>
    </div>
  );
}
