from pathlib import Path
import re, subprocess, shutil
from docx import Document
from docx.shared import Cm, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_CELL_VERTICAL_ALIGNMENT
from docx.oxml import OxmlElement
from docx.oxml.ns import qn

BASE=Path('/home/agent/outputs/furkastrasse_pl_jourfix_20260812')
DRAFT=BASE/'draft'; ART=BASE/'artifacts'; ART.mkdir(parents=True,exist_ok=True)
TEMPLATE=Path('/home/agent/jarvis_memory/work/projects/furkastrasse/meetings/2026-07-01_interner_baumanagement_pl_jourfix/artifacts/260701_Furkastrasse_Protokoll_interner_BM_PL_Jourfix_ERNE_CI.docx')
BLUE='365294'; LIGHT='F6F1EC'

def shade(cell,fill):
    tcPr=cell._tc.get_or_add_tcPr(); shd=tcPr.find(qn('w:shd'))
    if shd is None: shd=OxmlElement('w:shd'); tcPr.append(shd)
    shd.set(qn('w:fill'),fill)

def no_split(row):
    trPr=row._tr.get_or_add_trPr(); trPr.append(OxmlElement('w:cantSplit'))

def clear_body(doc):
    body=doc._body._element
    for child in list(body):
        if child.tag != qn('w:sectPr'): body.remove(child)

def style_doc(doc):
    sec=doc.sections[0]
    sec.page_width=Cm(21); sec.page_height=Cm(29.7)
    sec.top_margin=Cm(2.35); sec.bottom_margin=Cm(1.85); sec.left_margin=Cm(1.65); sec.right_margin=Cm(1.65)
    sec.header_distance=Cm(.85); sec.footer_distance=Cm(.85)
    doc.styles['Normal'].font.name='Arial'; doc.styles['Normal'].font.size=Pt(8.5)

def add_table(doc,lines):
    rows=[]
    for line in lines:
        cells=[c.strip() for c in line.strip().strip('|').split('|')]
        if all(re.fullmatch(r':?-{3,}:?',c.replace(' ','')) for c in cells): continue
        rows.append(cells)
    if not rows:return
    cols=max(map(len,rows)); t=doc.add_table(rows=len(rows),cols=cols); t.alignment=WD_TABLE_ALIGNMENT.CENTER
    try:t.style='Table Grid'
    except KeyError:pass
    for i,row in enumerate(rows):
        no_split(t.rows[i])
        for j in range(cols):
            c=t.cell(i,j); c.vertical_alignment=WD_CELL_VERTICAL_ALIGNMENT.TOP; c.text=row[j] if j<len(row) else ''
            for p in c.paragraphs:
                p.paragraph_format.space_after=Pt(0)
                for r in p.runs:r.font.name='Arial';r.font.size=Pt(7.7)
            if i==0:
                shade(c,BLUE)
                for p in c.paragraphs:
                    for r in p.runs:r.font.color.rgb=RGBColor(255,255,255);r.bold=True
            elif i%2==0:shade(c,LIGHT)
    doc.add_paragraph('')

def para(doc,text,style=None):
    try:p=doc.add_paragraph(style=style) if style else doc.add_paragraph()
    except KeyError:p=doc.add_paragraph()
    for part in re.split(r'(\*\*.*?\*\*)',text):
        r=p.add_run(part[2:-2] if part.startswith('**') and part.endswith('**') else part)
        r.bold=part.startswith('**') and part.endswith('**');r.font.name='Arial'
        if not style:r.font.size=Pt(8.5)
    if style:
        p.paragraph_format.keep_with_next=True;p.paragraph_format.space_before=Pt(8);p.paragraph_format.space_after=Pt(4)
        size={'Heading 1':16,'Heading 2':13,'Heading 3':10}.get(style,10)
        for r in p.runs:r.font.size=Pt(size);r.font.color.rgb=RGBColor.from_string(BLUE);r.bold=True
        # avoid orphaned major blocks; explicit clean starts for long/high-value sections
        if text.strip() in {'4. Ampelstatus','5. Traktanden / Protokoll','6. Entscheide','7. Termine / Meilensteine','8. Pendenzenliste'}:p.paragraph_format.page_break_before=True
    else:p.paragraph_format.space_after=Pt(3)
    return p

def convert(md,out):
    doc=Document(str(TEMPLATE)) if TEMPLATE.exists() else Document();clear_body(doc);style_doc(doc)
    lines=md.read_text(encoding='utf-8').splitlines();i=0
    while i<len(lines):
        line=lines[i].rstrip()
        if not line.strip() or line.strip()=='---':i+=1;continue
        if line.startswith('|'):
            tbl=[]
            while i<len(lines) and lines[i].strip().startswith('|'):tbl.append(lines[i]);i+=1
            add_table(doc,tbl);continue
        img=re.fullmatch(r'!\[(.*?)\]\((.*?)\)',line.strip())
        if img:
            p=doc.add_paragraph();p.alignment=WD_ALIGN_PARAGRAPH.CENTER
            path=Path(img.group(2));r=p.add_run();r.add_picture(str(path),width=Cm(16.8))
            cap=doc.add_paragraph(img.group(1));cap.alignment=WD_ALIGN_PARAGRAPH.CENTER
            for rr in cap.runs:rr.italic=True;rr.font.name='Arial';rr.font.size=Pt(7.5);rr.font.color.rgb=RGBColor.from_string(BLUE)
        elif line.startswith('# '):p=para(doc,line[2:].strip(),'Heading 1');p.alignment=WD_ALIGN_PARAGRAPH.CENTER
        elif line.startswith('## '):para(doc,line[3:].strip(),'Heading 2')
        elif line.startswith('#### '):para(doc,line[5:].strip(),'Heading 3')
        elif line.startswith('### '):para(doc,line[4:].strip(),'Heading 3')
        elif line.startswith('- '):para(doc,'• '+line[2:].strip())
        else:para(doc,line.strip())
        i+=1
    doc.save(out)

files=[
(DRAFT/'260812_Furkastrasse_PL_Jourfix_Protokoll.md',ART/'260812_Furkastrasse_Protokoll_interner_BM_PL_Jourfix_ERNE_CI.docx'),
(DRAFT/'260812_Furkastrasse_PL_Jourfix_bereinigtes_Transkript.md',ART/'260812_Furkastrasse_bereinigtes_Transkript_interner_BM_PL_Jourfix_ERNE_CI.docx')]
for md,out in files:convert(md,out)
lo=shutil.which('libreoffice') or shutil.which('soffice')
if not lo:raise SystemExit('LibreOffice fehlt')
for _,out in files:subprocess.run([lo,'--headless','--convert-to','pdf','--outdir',str(ART),str(out)],check=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
for p in sorted(ART.iterdir()):print(p.name,p.stat().st_size)
