// Formaterad text i offertens avsnitt — rubriker, punktlistor och fet stil.
//
// Textrutan är en vanlig textruta. Formateringen skrivs som enkla tecken:
//
//   ## Rubrik
//   ### Underrubrik
//   - punkt i en lista
//   **fet text**
//
// Klistrar man in från Word (eller Outlook, eller en webbsida) läses den
// formaterade versionen ur urklipp och görs om till de tecknen. Typsnitt,
// storlekar, färger och indrag från Word kastas — i offerten ritas allt med
// ULAB:s grafiska profil (OfferPreview.jsx).
//
// OBS: alla .jsx laddas som vanliga skript i samma globala scope, så
// toppnivånamn i den här filen har ki-prefix.

// ---------- Tolka texten (används av OfferPreview) ----------
// Ger en lista av block: { typ: 'rubrik'|'underrubrik'|'stycke'|'lista', text | punkter }
const kiPunktRe = /^\s*[-•*·▪◦–]\s+/;
function kiTolka(body) {
  const ut = [];
  let stycke = null, lista = null;
  const avsluta = () => {
    if (stycke) { ut.push({ typ: 'stycke', text: stycke.join('\n') }); stycke = null; }
    if (lista) { ut.push({ typ: 'lista', punkter: lista }); lista = null; }
  };
  for (const rad of String(body || '').split('\n')) {
    const r = rad.replace(/\s+$/, '');
    if (!r.trim()) { avsluta(); continue; }
    let m;
    if ((m = r.match(/^\s*###\s+(.*)$/))) { avsluta(); ut.push({ typ: 'underrubrik', text: m[1] }); continue; }
    if ((m = r.match(/^\s*##?\s+(.*)$/))) { avsluta(); ut.push({ typ: 'rubrik', text: m[1] }); continue; }
    if (kiPunktRe.test(r)) {
      if (stycke) { ut.push({ typ: 'stycke', text: stycke.join('\n') }); stycke = null; }
      (lista ||= []).push(r.replace(kiPunktRe, ''));
      continue;
    }
    if (lista) { ut.push({ typ: 'lista', punkter: lista }); lista = null; }
    (stycke ||= []).push(r);
  }
  avsluta();
  return ut;
}

// **fet** → <strong>. Används för stycken, punkter och rubriker i dokumentet.
function KiText({ text }) {
  const delar = String(text || '').split(/\*\*(.+?)\*\*/g);
  return delar.map((d, i) => (i % 2 ? <strong key={i} style={{ fontWeight: 600 }}>{d}</strong> : <React.Fragment key={i}>{d}</React.Fragment>));
}

// ---------- Inklistring från Word ----------
const kiBlockTaggar = 'p,div,h1,h2,h3,h4,h5,h6,ul,ol,li,table,tr,blockquote,section,article';

function kiArFet(el) {
  const stil = (el.getAttribute && el.getAttribute('style')) || '';
  const vikt = (stil.match(/font-weight\s*:\s*([a-z0-9]+)/i) || [])[1];
  if (vikt) return /bold|[6-9]00/i.test(vikt);
  // Google Docs lindar in allt i <b style="font-weight:normal"> — fångas ovan.
  return el.tagName === 'B' || el.tagName === 'STRONG';
}

// Löptext i ett block, med **fet**. Radbrytningar i källkoden (Word har många)
// blir mellanslag; bara <br> blir en riktig radbrytning.
function kiLoptext(nod) {
  const BR = '\u0001';
  const gå = (n) => {
    if (n.nodeType === 3) return n.nodeValue;
    if (n.nodeType !== 1) return '';
    if (n.tagName === 'BR') return BR;
    if (/^(UL|OL)$/.test(n.tagName)) return ''; // nästlade listor tas för sig
    const inne = [...n.childNodes].map(gå).join('');
    if (kiArFet(n) && inne.trim()) {
      const fore = inne.match(/^\s*/)[0], efter = inne.match(/\s*$/)[0];
      return fore + '**' + inne.trim() + '**' + efter;
    }
    return inne;
  };
  return gå(nod)
    .replace(/ /g, ' ')
    .replace(/[ \t\r\n]+/g, ' ')
    .replace(/\*\*\*\*/g, '')          // två feta bitar i rad blir en
    .replace(/\*\*\s*\*\*/g, ' ')
    .split(BR).map(s => s.trim()).join('\n')
    .trim();
}

function kiHtmlTillText(html) {
  const doc = new DOMParser().parseFromString(html, 'text/html');
  doc.querySelectorAll('style,script,meta,link,title,head').forEach(e => e.remove());
  // Words egna listtecken ("·" i Symbol-typsnitt + mellanslag) ligger i spans
  // märkta mso-list:Ignore. De är inte text — punkten sätts av oss.
  doc.querySelectorAll('span').forEach(s => { if (/mso-list\s*:\s*ignore/i.test(s.getAttribute('style') || '')) s.remove(); });

  const ut = []; // { typ, text }
  const block = (el) => {
    const tagg = el.tagName;
    const klass = el.getAttribute('class') || '';
    const stil = el.getAttribute('style') || '';
    if (/^H1$/.test(tagg) || /MsoTitle|Heading1|Rubrik1/i.test(klass)) return ut.push({ typ: 'rubrik', text: kiLoptext(el) });
    if (/^H[2-6]$/.test(tagg) || /Heading[2-6]|Rubrik[2-6]/i.test(klass)) return ut.push({ typ: 'underrubrik', text: kiLoptext(el) });
    if (tagg === 'LI' || /MsoListParagraph/i.test(klass) || /mso-list\s*:\s*l\d/i.test(stil)) {
      ut.push({ typ: 'punkt', text: kiLoptext(el) });
      el.querySelectorAll(':scope > ul, :scope > ol').forEach(gå);
      return;
    }
    ut.push({ typ: 'stycke', text: kiLoptext(el) });
  };
  const gå = (el) => {
    for (const n of [...el.childNodes]) {
      if (n.nodeType === 3) { if (n.nodeValue.trim()) ut.push({ typ: 'stycke', text: kiLoptext(n) }); continue; }
      if (n.nodeType !== 1) continue;
      const harBlock = n.matches(kiBlockTaggar) ? null : n.querySelector(kiBlockTaggar);
      if (/^(UL|OL|TABLE|TBODY|TR|BLOCKQUOTE|SECTION|ARTICLE)$/.test(n.tagName)) gå(n);
      else if (n.tagName === 'DIV' && n.querySelector(kiBlockTaggar)) gå(n);
      else if (harBlock) gå(n);                      // t.ex. Google Docs <b>-omslag
      else if (n.matches(kiBlockTaggar)) block(n);
      else { const t = kiLoptext(n); if (t) ut.push({ typ: 'stycke', text: t }); }
    }
  };
  gå(doc.body);

  // En hel rad i fetstil, kort och utan punkt i slutet, är en rubrik som
  // skrivits som fet text i stället för med Words rubrikformat.
  const rader = ut.filter(b => b.text && b.text.replace(/\*\*/g, '').trim()).map(b => {
    const ren = b.text.replace(/\*\*/g, '').trim();
    if (b.typ === 'stycke' && /^\*\*[^*]+\*\*$/.test(b.text.trim()) && ren.length <= 70 && !/[.:;,]$/.test(ren)) {
      return { typ: 'underrubrik', text: ren };
    }
    if (b.typ === 'rubrik' || b.typ === 'underrubrik') return { typ: b.typ, text: ren };
    return b;
  });

  // Ihop: punkter i följd på var sin rad, allt annat med en tom rad emellan.
  let s = '';
  rader.forEach((b, i) => {
    const rad = b.typ === 'rubrik' ? '## ' + b.text
      : b.typ === 'underrubrik' ? '### ' + b.text
      : b.typ === 'punkt' ? '- ' + b.text
      : b.text;
    if (i > 0) s += (b.typ === 'punkt' && rader[i - 1].typ === 'punkt') ? '\n' : '\n\n';
    s += rad;
  });
  return s;
}

// Ren text (t.ex. från Anteckningar, eller när urklipp saknar HTML): gör
// Words tecken för punktlistor till "- ".
function kiRenText(text) {
  return String(text || '').replace(/\r\n?/g, '\n')
    .split('\n').map(r => r.replace(/^\s*[•·▪◦o§–-]\t+/, '- ').replace(/^\s*[•·▪◦]\s+/, '- ')).join('\n');
}

// ---------- Ändra texten i rutan ----------
// execCommand('insertText') behåller webbläsarens egen ångra (Ctrl+Z). Finns
// den inte sätts värdet direkt och React får veta det via ett input-event.
function kiErsatt(el, fran, till, text, markeraFran, markeraTill) {
  el.focus();
  el.setSelectionRange(fran, till);
  let ok = false;
  try { ok = text ? document.execCommand('insertText', false, text) : document.execCommand('delete'); } catch (e) { ok = false; }
  if (!ok) {
    const nytt = el.value.slice(0, fran) + text + el.value.slice(till);
    Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value').set.call(el, nytt);
    el.dispatchEvent(new Event('input', { bubbles: true }));
  }
  const a = markeraFran != null ? markeraFran : fran + text.length;
  const b = markeraTill != null ? markeraTill : a;
  requestAnimationFrame(() => { try { el.setSelectionRange(a, b); } catch (e) {} });
}

// Rubrik/underrubrik/punkt på de markerade raderna. Har alla raderna redan
// det formatet tas det bort (knappen fungerar som av/på).
function kiRadFormat(el, prefix) {
  const v = el.value;
  const start = v.lastIndexOf('\n', el.selectionStart - 1) + 1;
  let slut = v.indexOf('\n', el.selectionEnd);
  if (slut < 0) slut = v.length;
  const rader = v.slice(start, slut).split('\n');
  const utanFormat = (r) => r.replace(/^\s*(###|##|#)\s+/, '').replace(kiPunktRe, '');
  const harRedan = rader.filter(r => r.trim()).every(r => r.startsWith(prefix) && !(prefix === '## ' && r.startsWith('### ')));
  const nya = rader.map(r => (!r.trim() ? r : harRedan ? utanFormat(r) : prefix + utanFormat(r))).join('\n');
  kiErsatt(el, start, slut, nya, start, start + nya.length);
}

function kiFet(el) {
  const v = el.value;
  let a = el.selectionStart, b = el.selectionEnd;
  const valt = v.slice(a, b);
  if (a === b) { kiErsatt(el, a, b, '****', a + 2, a + 2); return; }
  // Redan fet? Ta bort.
  if (valt.startsWith('**') && valt.endsWith('**') && valt.length >= 4) {
    const inne = valt.slice(2, -2);
    kiErsatt(el, a, b, inne, a, a + inne.length); return;
  }
  if (v.slice(a - 2, a) === '**' && v.slice(b, b + 2) === '**') {
    kiErsatt(el, a - 2, b + 2, valt, a - 2, a - 2 + valt.length); return;
  }
  // Mellanslag i kanten av markeringen hamnar utanför stjärnorna.
  const fore = valt.match(/^\s*/)[0], efter = valt.match(/\s*$/)[0];
  const ny = fore + '**' + valt.trim() + '**' + efter;
  kiErsatt(el, a, b, ny, a + fore.length + 2, a + fore.length + 2 + valt.trim().length);
}

// ---------- Textrutan ----------
function FormatTextarea({ value, onChange, placeholder, rows, style }) {
  const [v, setV] = React.useState(value || '');
  const senast = React.useRef(value);
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (value !== senast.current) { setV(value || ''); senast.current = value; }
  }, [value]);

  const klistra = (e) => {
    const cd = e.clipboardData;
    if (!cd) return;
    const html = cd.getData('text/html');
    const ren = cd.getData('text/plain');
    let text = '';
    if (html) { try { text = kiHtmlTillText(html); } catch (err) { text = ''; } }
    if (!text) text = kiRenText(ren);
    if (!text) return;
    e.preventDefault();
    const el = ref.current;
    kiErsatt(el, el.selectionStart, el.selectionEnd, text);
  };

  const knapp = (etikett, titel, gor) => (
    <button type="button" title={titel} onMouseDown={e => e.preventDefault()}
      onClick={() => { if (ref.current) gor(ref.current); }} style={kiKnapp}>{etikett}</button>
  );

  return (
    <div>
      <div style={kiVerktyg} role="toolbar" aria-label="Formatering">
        {knapp('Rubrik', 'Gör raden till rubrik (##)', el => kiRadFormat(el, '## '))}
        {knapp('Underrubrik', 'Gör raden till underrubrik (###)', el => kiRadFormat(el, '### '))}
        {knapp('• Punktlista', 'Gör raderna till punktlista (-)', el => kiRadFormat(el, '- '))}
        {knapp(<b>Fet</b>, 'Fet stil på markerad text (**)', kiFet)}
      </div>
      <textarea ref={ref} value={v} rows={rows} placeholder={placeholder} onPaste={klistra}
        onChange={e => { const nv = e.target.value; setV(nv); senast.current = nv; onChange(nv); }}
        style={{ ...style, borderTopLeftRadius: 0, borderTopRightRadius: 0 }}/>
      <div style={kiHjalp}>
        <code style={kiKod}>## Rubrik</code> <code style={kiKod}>### Underrubrik</code> <code style={kiKod}>- punkt</code> <code style={kiKod}>**fet**</code>
        <span style={{ marginLeft: 6 }}>— klistrar du in från Word görs det åt dig.</span>
      </div>
    </div>
  );
}

const kiVerktyg = {
  display: 'flex', gap: 4, padding: '5px 6px', background: 'var(--ulab-cool-grey)',
  border: '1px solid var(--border-strong)', borderBottom: 'none', borderRadius: '4px 4px 0 0',
};
const kiKnapp = {
  fontFamily: 'var(--font-sans)', fontSize: 11.5, fontWeight: 600, color: 'var(--ulab-navy)',
  background: '#fff', border: '1px solid var(--border)', borderRadius: 3, padding: '3px 9px', cursor: 'pointer',
};
const kiHjalp = { fontSize: 11, color: 'var(--fg-subtle)', marginTop: 5, lineHeight: 1.6 };
const kiKod = { fontFamily: 'ui-monospace, Menlo, Consolas, monospace', fontSize: 10.5, background: 'var(--ulab-cool-grey)', borderRadius: 3, padding: '0 4px', color: 'var(--fg-muted)' };

window.kiTolka = kiTolka;
window.KiText = KiText;
window.kiHtmlTillText = kiHtmlTillText;
window.FormatTextarea = FormatTextarea;
