// @ts-nocheck
/**
 * 2026-11-10: runs INSIDE Chromium (page.evaluate) on a filled job form and returns Word-friendly HTML:
 * every element's computed look (borders, shading, bold, sizes, alignment) is written inline, table
 * column grids are rebuilt from the rendered page, flex rows become tables and framed boxes become
 * one-cell tables — so LibreOffice's Word export looks like the PDF.
 */
export function wordify(): string {
  const pageW = window.innerWidth;
  const contentW = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth);
  const fit = contentW > pageW + 2 ? pageW / contentW : 1;
  const px2pt = (v) => Math.round(parseFloat(v) * 0.75 * fit * 10) / 10;
  const isTransparent = (c) => !c || c === 'transparent' || /rgba\([^)]*,\s*0\)$/.test(c);
  const hex = (c) => { const m = c.match(/\d+(\.\d+)?/g); if (!m) return c; return '#' + m.slice(0, 3).map((x) => (+x).toString(16).padStart(2, '0')).join(''); };
  const all = Array.from(document.body.querySelectorAll('*'));
  const snap = new Map();
  for (const el of all) {
    const cs = getComputedStyle(el);
    if (cs.display === 'none' || cs.visibility === 'hidden') { snap.set(el, null); continue; }
    const r = el.getBoundingClientRect();
    const st = [];
    const box = [];
    const tag = el.tagName;
    const cell = tag === 'TD' || tag === 'TH';
    st.push(`font-size:${px2pt(cs.fontSize)}pt`);
    if (parseInt(cs.fontWeight, 10) >= 600) st.push('font-weight:bold'); else st.push('font-weight:normal');
    if (cs.fontStyle === 'italic') st.push('font-style:italic');
    if (cs.textDecorationLine && cs.textDecorationLine !== 'none') st.push(`text-decoration:${cs.textDecorationLine}`);
    st.push(`color:${hex(cs.color)}`);
    st.push(`font-family:${cs.fontFamily}`);
    st.push(`text-transform:${cs.textTransform || 'none'}`);
    if (!/^(SPAN|B|STRONG|I|EM|SUP|SUB|A|BR|IMG|INPUT|LABEL|U|SMALL)$/.test(tag)) st.push(`text-align:${cs.textAlign === 'start' ? 'left' : cs.textAlign}`);
    let bg = null;
    if (!isTransparent(cs.backgroundColor)) { bg = hex(cs.backgroundColor); box.push(`background-color:${bg}`); }
    let anyBorder = false;
    for (const side of ['top', 'right', 'bottom', 'left']) {
      const w = parseFloat(cs[`border-${side}-width`] || cs.getPropertyValue(`border-${side}-width`));
      const s = cs.getPropertyValue(`border-${side}-style`);
      if (w > 0 && s !== 'none' && s !== 'hidden') { anyBorder = true; box.push(`border-${side}:${Math.max(0.5, px2pt(w))}pt ${s} ${hex(cs.getPropertyValue(`border-${side}-color`))}`); }
      else if (cell) box.push(`border-${side}:none`);
    }
    if (cell || tag === 'DIV' || tag === 'P') {
      for (const side of ['top', 'right', 'bottom', 'left']) { const p = parseFloat(cs.getPropertyValue(`padding-${side}`)); if (p > 0) box.push(`padding-${side}:${px2pt(p)}pt`); }
    }
    if (cell) st.push(`vertical-align:${['top', 'middle', 'bottom'].includes(cs.verticalAlign) ? cs.verticalAlign : 'top'}`);
    snap.set(el, { rect: { l: r.left, t: r.top, r: r.right, b: r.bottom, w: r.width, h: r.height }, st: st.concat(box).join(';'), text: st.join(';'), box: box.join(';'), bg, w: r.width, h: r.height, anyBorder, cs: { display: cs.display, lh: cs.lineHeight } });
  }
  // real column grid of every table, measured from the rendered page (drops phantom colspan columns)
  const grids = [];
  for (const table of Array.from(document.querySelectorAll('table'))) {
    if (!snap.get(table)) continue;
    const cells = [];
    for (const row of Array.from(table.rows)) for (const c of Array.from(row.cells)) { if (!snap.get(c)) continue; const r = c.getBoundingClientRect(); cells.push({ c, l: Math.round(r.left), r: Math.round(r.right) }); }
    if (!cells.length) continue;
    const edges = [...new Set(cells.flatMap((x) => [x.l, x.r]))].sort((a, b) => a - b);
    const merged = []; for (const e of edges) if (!merged.length || e - merged[merged.length - 1] > 3) merged.push(e);
    const idx = (v) => merged.reduce((bi, e, i) => (Math.abs(e - v) < Math.abs(merged[bi] - v) ? i : bi), 0);
    grids.push({ table, cells: cells.map((x) => ({ c: x.c, span: Math.max(1, idx(x.r) - idx(x.l)) })), widths: merged.slice(1).map((e, i) => e - merged[i]), total: merged[merged.length - 1] - merged[0] });
  }
  // inputs → text
  for (const inp of Array.from(document.querySelectorAll('input'))) {
    const t = inp.type === 'checkbox' || inp.type === 'radio' ? (inp.checked ? '☑ ' : '☐ ') : (inp.value || '');
    const si = snap.get(inp);
    if (inp.type === 'checkbox' || inp.type === 'radio' || !si) { inp.replaceWith(document.createTextNode(t)); continue; }
    // text field: same font, underline kept; pad short values so the line still shows
    const span = document.createElement('span');
    const minChars = Math.max(0, Math.round(si.w / 7) - t.length);
    span.textContent = t + '\u00a0'.repeat(Math.min(minChars, 120));
    const underline = /border-bottom:[^;]*solid/.test(si.box);
    span.setAttribute('style', si.text + (underline ? ';text-decoration:underline' : ''));
    snap.delete(inp);
    inp.replaceWith(span);
  }
  // flex / grid rows → one-row tables (Writer cannot lay out flexbox)
  for (const el of all.slice().reverse()) {
    const s = snap.get(el);
    if (!s || !el.isConnected) continue;
    if (!/flex|grid/.test(s.cs.display)) continue;
    const kids = Array.from(el.children).filter((k) => snap.get(k));
    if (kids.length < 2) continue;
    const box0 = s.rect;
    const total = box0.w || 1;
    const R = (k) => snap.get(k).rect;
    const vertical = kids.every((k, i) => i === 0 || R(kids[i - 1]).b <= R(k).t + 2);
    if (vertical) continue;
    const t = document.createElement('table'); t.setAttribute('width', '100%'); t.setAttribute('cellspacing', '0'); t.setAttribute('cellpadding', '0'); t.setAttribute('border', '0');
    t.setAttribute('style', 'border:none;border-collapse:collapse');
    // group items into visual rows (a 2-column grid of 6 boxes = 3 rows)
    const rows = [];
    for (const k of kids.slice().sort((a, b) => R(a).t - R(b).t || R(a).l - R(b).l)) {
      const row = rows.find((rw) => Math.abs(R(rw[0]).t - R(k).t) < Math.max(4, R(rw[0]).h / 2));
      if (row) row.push(k); else rows.push([k]);
    }
    for (const rw of rows) {
      rw.sort((a, b) => R(a).l - R(b).l);
      const tr = document.createElement('tr'); t.appendChild(tr);
      let prevRight = box0.l;
      const spacer = (w) => { const sp = document.createElement('td'); sp.setAttribute('width', Math.max(1, Math.round((w / total) * 100)) + '%'); sp.setAttribute('style', 'border:none;padding:0'); tr.appendChild(sp); };
      for (const k of rw) {
        const kr = R(k); const ks = snap.get(k);
        if (kr.l - prevRight > 8) spacer(kr.l - prevRight);
        prevRight = kr.r;
        const td = document.createElement('td'); td.setAttribute('width', Math.max(1, Math.round((kr.w / total) * 100)) + '%'); td.setAttribute('valign', 'middle');
        if (ks.box && /border|background/.test(ks.box) && !k.querySelector('table')) {
          // a bordered/shaded item in a row becomes the bordered cell itself
          td.setAttribute('style', ks.box + ';vertical-align:middle'); if (ks.bg) td.setAttribute('bgcolor', ks.bg);
          ks.st = ks.text; ks.boxed = true;
        } else td.setAttribute('style', 'border:none;vertical-align:middle;padding:0');
        td.appendChild(k); tr.appendChild(td);
      }
      if (box0.r - prevRight > 8) spacer(box0.r - prevRight);
    }
    el.appendChild(t);
  }
  // bordered/shaded boxes that hold tables or blocks → one-cell table (Writer cannot frame a block of tables)
  for (const el of all) {
    const s = snap.get(el);
    if (!s || !el.isConnected || el.tagName !== 'DIV' || !s.box || s.boxed) continue;
    if (!/border|background/.test(s.box)) continue;
    // a frame around more than one page of content cannot be a table cell (it would not break across
    // pages cleanly) — let that content flow and drop only the frame line
    {
      let bottom = 0; const top = el.getBoundingClientRect().top;
      for (const k of Array.from(el.querySelectorAll('*'))) { const r = k.getBoundingClientRect(); if (r.height && r.bottom - top > bottom) bottom = r.bottom - top; }
      if (bottom * 0.75 * fit > 780) { s.st = s.text; continue; }
    }
    const parentW = el.parentElement ? el.parentElement.getBoundingClientRect().width : s.w;
    const pct = parentW ? Math.min(100, Math.round((s.w / parentW) * 100)) : 100;
    const t = document.createElement('table'); t.setAttribute('width', pct + '%');
    const cs2 = getComputedStyle(el);
    const centred = cs2.marginLeft === cs2.marginRight && parseFloat(cs2.marginLeft) > 0;
    const rightAligned = parseFloat(cs2.marginLeft) > 20 && !centred || (el.parentElement && getComputedStyle(el.parentElement).textAlign === 'right');
    if (pct < 100) t.setAttribute('align', centred ? 'center' : rightAligned ? 'right' : 'left'); t.setAttribute('cellspacing', '0'); t.setAttribute('cellpadding', '0');
    t.setAttribute('style', 'border-collapse:collapse;border:none');
    const tr = document.createElement('tr'); const td = document.createElement('td'); td.setAttribute('valign', 'top');
    td.setAttribute('style', s.box + ';vertical-align:top'); if (s.bg) td.setAttribute('bgcolor', s.bg);
    // keep the box's height (empty Remarks boxes, full-page frames), capped to one page
    const fullPt = Math.round(s.h * 0.75 * fit);
    let contentBottom = 0; const top0 = el.getBoundingClientRect().top;
    for (const k of Array.from(el.querySelectorAll('*'))) { const r = k.getBoundingClientRect(); if (r.height && r.bottom - top0 > contentBottom) contentBottom = r.bottom - top0; }
    const contentPt = Math.round(contentBottom * 0.75 * fit);
    const hpt = contentPt > 780 ? 0 : Math.min(fullPt, 800);
    const tallAncestor = hpt > 400 && all.some((a) => a !== el && a.contains(el) && snap.get(a) && snap.get(a).tall);
    // fixed height only for a full-page frame (starts at the top) or a mostly empty box (e.g. Remarks)
    const pageFrame = s.rect.t < 60;
    const emptyBox = contentPt < fullPt * 0.6 && fullPt < 300;
    if (hpt > 24 && !tallAncestor && (pageFrame || emptyBox)) td.setAttribute('height', String(Math.round(hpt / 0.75)));
    if (hpt > 400) s.tall = true;
    tr.appendChild(td); t.appendChild(tr);
    el.parentNode.insertBefore(t, el); td.appendChild(el);
    s.st = s.text;
  }
  for (const li of Array.from(document.querySelectorAll('li'))) {
    if (getComputedStyle(li).listStyleType !== 'none') continue;
    const d = document.createElement('div'); while (li.firstChild) d.appendChild(li.firstChild); snap.set(d, snap.get(li)); li.replaceWith(d);
  }
  // apply
  for (const el of all) {
    const s = snap.get(el);
    if (s === null) { el.remove(); continue; }
    if (!s || !el.isConnected) continue;
    el.setAttribute('style', s.st);
    el.removeAttribute('class');
    const tag = el.tagName;
    if (tag === 'TABLE') { el.setAttribute('cellspacing', '0'); el.setAttribute('cellpadding', '3'); if (!el.getAttribute('width')) el.setAttribute('width', '100%'); el.setAttribute('style', s.st + ';border-collapse:collapse'); }
    if ((tag === 'TD' || tag === 'TH')) {
      if (s.bg) el.setAttribute('bgcolor', s.bg);
      const table = el.closest('table'); const tw = table && snap.get(table) ? snap.get(table).w : 0;
      if (tw) el.setAttribute('width', Math.max(1, Math.round((s.w / tw) * 100)) + '%');
      el.setAttribute('valign', /vertical-align:(middle|bottom)/.exec(s.st)?.[1] || 'top');
    }
    if (tag === 'IMG') { el.setAttribute('width', String(Math.round(s.w))); el.setAttribute('height', String(Math.round(s.h))); }
  }
  for (const g of grids) {
    if (!g.table.isConnected) continue;
    for (const x of g.cells) { if (x.span > 1) x.c.setAttribute('colspan', String(x.span)); else x.c.removeAttribute('colspan'); x.c.removeAttribute('width'); }
    const cg = document.createElement('colgroup');
    for (const w of g.widths) { const col = document.createElement('col'); col.setAttribute('width', Math.max(1, Math.round((w / g.total) * 1000) / 10) + '%'); cg.appendChild(col); }
    g.table.insertBefore(cg, g.table.firstChild);
    // first-row-style widths on each cell too (Writer reads cell widths more reliably than <col>)
    for (const row of Array.from(g.table.rows)) { let k = 0; for (const c of Array.from(row.cells)) { const span = +(c.getAttribute('colspan') || 1); const w = g.widths.slice(k, k + span).reduce((a, b) => a + b, 0); c.setAttribute('width', Math.max(1, Math.round((w / g.total) * 1000) / 10) + '%'); k += span; } }
  }
  for (const n of Array.from(document.querySelectorAll('style,link,script'))) n.remove();
  document.body.setAttribute('style', 'margin:0;padding:0;font-family:Source Sans Pro, Arial, sans-serif');
  return '<!DOCTYPE html>' + document.documentElement.outerHTML;
};
