# -*- coding: utf-8 -*-
from docx import Document
from docx.shared import Mm, Pt, RGBColor, Emu
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL
from docx.enum.section import WD_SECTION
from docx.oxml.ns import qn
from docx.oxml import OxmlElement

PURPLE="7E217F"; PURPLE_DK="5E1860"; TEAL="1C9AA8"
GREEN="2E7D32"; GREEN_BG="E7F4EA"; RED="C0392B"; RED_BG="FBE9E7"
HDR_TXT="FFFFFF"; LIGHT="F4EEF5"; GREY="666666"; BORDER="D9D9D9"
LOGO="/tmp/breact_logo.png"

doc=Document()
# ---- base styles ----
st=doc.styles['Normal']; st.font.name='Calibri'; st.font.size=Pt(10.5); st.font.color.rgb=RGBColor.from_string('222222')
for h,sz in (('Heading 1',16),('Heading 2',13),('Heading 3',11)):
    s=doc.styles[h]; s.font.name='Calibri'; s.font.bold=True; s.font.size=Pt(sz)
    s.font.color.rgb=RGBColor.from_string(PURPLE)

sec=doc.sections[0]
sec.page_width=Mm(210); sec.page_height=Mm(297)
sec.top_margin=Mm(22); sec.bottom_margin=Mm(18); sec.left_margin=Mm(20); sec.right_margin=Mm(20)
sec.header_distance=Mm(10); sec.footer_distance=Mm(10)
CW=170  # content width mm

def shade(cell,hexv):
    tcPr=cell._tc.get_or_add_tcPr(); shd=OxmlElement('w:shd')
    shd.set(qn('w:val'),'clear'); shd.set(qn('w:color'),'auto'); shd.set(qn('w:fill'),hexv); tcPr.append(shd)

def vcenter(cell):
    cell.vertical_alignment=WD_ALIGN_VERTICAL.CENTER

def cell_text(cell,text,bold=False,color=None,size=10,align=None,italic=False):
    cell.text=''
    p=cell.paragraphs[0]
    if align is not None: p.alignment=align
    p.paragraph_format.space_after=Pt(1); p.paragraph_format.space_before=Pt(1)
    r=p.add_run(text); r.bold=bold; r.italic=italic; r.font.size=Pt(size)
    if color: r.font.color.rgb=RGBColor.from_string(color)
    return p

def set_borders(table,color=BORDER,sz=4):
    tbl=table._tbl; tblPr=tbl.tblPr
    bd=OxmlElement('w:tblBorders')
    for edge in ('top','left','bottom','right','insideH','insideV'):
        e=OxmlElement('w:'+edge); e.set(qn('w:val'),'single'); e.set(qn('w:sz'),str(sz))
        e.set(qn('w:space'),'0'); e.set(qn('w:color'),color); bd.append(e)
    tblPr.append(bd)

def setw(table,widths):
    table.allow_autofit=False
    for r in table.rows:
        for i,w in enumerate(widths):
            r.cells[i].width=Mm(w)
    for i,w in enumerate(widths):
        table.columns[i].width=Mm(w)

def para(text="",bold=False,size=10.5,color=None,align=None,space_after=6,space_before=0,italic=False):
    p=doc.add_paragraph()
    if align is not None: p.alignment=align
    p.paragraph_format.space_after=Pt(space_after); p.paragraph_format.space_before=Pt(space_before)
    if text:
        r=p.add_run(text); r.bold=bold; r.italic=italic; r.font.size=Pt(size)
        if color: r.font.color.rgb=RGBColor.from_string(color)
    return p

def bullet(text,size=10.5):
    p=doc.add_paragraph(style='List Bullet')
    p.paragraph_format.space_after=Pt(2)
    r=p.add_run(text); r.font.size=Pt(size); return p

def rule(color=PURPLE,sz=18,space=4):
    p=doc.add_paragraph(); p.paragraph_format.space_after=Pt(space); p.paragraph_format.space_before=Pt(0)
    pPr=p._p.get_or_add_pPr(); pbd=OxmlElement('w:pBdr'); b=OxmlElement('w:bottom')
    b.set(qn('w:val'),'single'); b.set(qn('w:sz'),str(sz)); b.set(qn('w:space'),'1'); b.set(qn('w:color'),color)
    pbd.append(b); pPr.append(pbd); return p

def add_page_number_footer():
    f=doc.sections[0].footer
    p=f.paragraphs[0]; p.alignment=WD_ALIGN_PARAGRAPH.CENTER
    r=p.add_run("BReact GmbH  ·  Vertraulich  ·  Angebot KI-Assistenzplattform  ·  Seite ")
    r.font.size=Pt(8); r.font.color.rgb=RGBColor.from_string(GREY)
    run=p.add_run()
    for t,v in (('begin',None),):
        fc=OxmlElement('w:fldChar'); fc.set(qn('w:fldCharType'),'begin'); run._r.append(fc)
    it=OxmlElement('w:instrText'); it.set(qn('xml:space'),'preserve'); it.text='PAGE'; run._r.append(it)
    fe=OxmlElement('w:fldChar'); fe.set(qn('w:fldCharType'),'end'); run._r.append(fe)
    run.font.size=Pt(8); run.font.color.rgb=RGBColor.from_string(GREY)

add_page_number_footer()

# ================= COVER / HEADER =================
ht=doc.add_table(rows=1,cols=2); ht.allow_autofit=False
ht.columns[0].width=Mm(26); ht.columns[1].width=Mm(CW-26)
ht.rows[0].cells[0].width=Mm(26); ht.rows[0].cells[1].width=Mm(CW-26)
lc=ht.rows[0].cells[0]; lc.text=''
try:
    lc.paragraphs[0].add_run().add_picture(LOGO,width=Mm(20))
except Exception as e:
    lc.paragraphs[0].add_run("BReact")
rc=ht.rows[0].cells[1]; rc.text=''; vcenter(rc)
p=rc.paragraphs[0]; p.alignment=WD_ALIGN_PARAGRAPH.RIGHT
r=p.add_run("BReact GmbH"); r.bold=True; r.font.size=Pt(15); r.font.color.rgb=RGBColor.from_string(PURPLE)
p2=rc.add_paragraph(); p2.alignment=WD_ALIGN_PARAGRAPH.RIGHT
r2=p2.add_run("KI- & Automatisierungslösungen"); r2.font.size=Pt(9); r2.font.color.rgb=RGBColor.from_string(TEAL)
rule(PURPLE,20,2)

para("ANGEBOT",bold=True,size=24,color=PURPLE,space_after=0,space_before=6)
para("Betrieb der KI-Assistenzplattform",bold=True,size=15,color="333333",space_after=2)
para("Leistungen und monatliche Kosten — drei Betriebsvarianten",size=11,color=GREY,space_after=10,italic=True)

# Anbieter / Kunde box
box=doc.add_table(rows=1,cols=2); set_borders(box); setw(box,[CW/2,CW/2])
ac=box.rows[0].cells[0]; kc=box.rows[0].cells[1]
shade(ac,LIGHT); shade(kc,LIGHT)
for c,title,lines in ((ac,"ANBIETER",["BReact GmbH","Esslinggasse 5/9, 1010 Wien","FN 589698d · UID ATU79912427","Ansprechpartner: Nemanja Klincov","nemanja@breact.ai  ·  +43 677 615 915 36"]),
                      (kc,"KUNDE",["Stadtwerke Klagenfurt AG","z. H. Ing. Peter Weratschnig","St. Veiter Straße 31","9020 Klagenfurt am Wörthersee"])):
    c.text=''
    h=c.paragraphs[0]; h.paragraph_format.space_after=Pt(3)
    rr=h.add_run(title); rr.bold=True; rr.font.size=Pt(9); rr.font.color.rgb=RGBColor.from_string(PURPLE)
    for ln in lines:
        pp=c.add_paragraph(); pp.paragraph_format.space_after=Pt(0); pr=pp.add_run(ln); pr.font.size=Pt(9.5)
# fix anbieter email (use breact)
para("",space_after=2)
meta=doc.add_table(rows=1,cols=3); set_borders(meta); setw(meta,[CW/3]*3)
for c,(k,v) in zip(meta.rows[0].cells,[("Angebotsnr.","ANG-2026-STW-01"),("Datum","24.06.2026"),("Gültigkeit","30 Tage ab Datum")]):
    c.text=''; shade(c,PURPLE)
    p=c.paragraphs[0]; p.alignment=WD_ALIGN_PARAGRAPH.CENTER; p.paragraph_format.space_after=Pt(0)
    r=p.add_run(k+":  "); r.bold=True; r.font.size=Pt(9.5); r.font.color.rgb=RGBColor.from_string(HDR_TXT)
    r2=p.add_run(v); r2.font.size=Pt(9.5); r2.font.color.rgb=RGBColor.from_string(HDR_TXT)

para("",space_after=6)
para("Sehr geehrter Herr Ing. Weratschnig, sehr geehrte Damen und Herren,",size=10.5,space_after=4)
para("nachstehend erhalten Sie unser Angebot für den laufenden Betrieb der KI-Assistenzplattform in drei Varianten. "
     "Für jede Variante sind die monatlichen Kosten nach Positionen (Inferenz, Betrieb, Wartung) sowie der jeweilige "
     "Leistungsumfang dargestellt. Im Anschluss finden Sie die in allen Varianten enthaltenen Leistungen, optionale "
     "Zusatzleistungen, die nicht enthaltenen Leistungen sowie eine Vergleichsübersicht.",space_after=4)
para("Alle Preise verstehen sich netto, zzgl. gesetzlicher Umsatzsteuer.",bold=True,size=10,space_after=8)

# Kostenpositionen overview
doc.add_heading("Die Kostenpositionen im Überblick",level=2)
ov=doc.add_table(rows=3,cols=2); set_borders(ov); setw(ov,[40,CW-40])
rows=[("Inferenz","Bereitstellung der KI-Rechenkapazität — token-basiert über einen zertifizierten EU-Partner (Variante 1) oder als dedizierte, private GPU-Kapazität auf eigener Infrastruktur (Varianten 2 und 3)."),
      ("Betrieb (24/7)","Kontinuierlicher Betrieb der Plattform inkl. Wissensdatenbank (RAG), Vektordatenbank und Embeddings, Netzwerk, Sicherheit, Backups, Monitoring und Kapazitätssteuerung."),
      ("Wartung & Support","Software- und Sicherheitsupdates, Sicherheitsprüfungen, vierteljährliche Modellprüfung, Störungsbehebung und Anwendersupport (Reaktionszeit 4 Std. zu Geschäftszeiten).")]
for i,(k,v) in enumerate(rows):
    kc=ov.rows[i].cells[0]; shade(kc,LIGHT); cell_text(kc,k,bold=True,color=PURPLE,size=10)
    cell_text(ov.rows[i].cells[1],v,size=10)

# ================= VARIANT SECTIONS =================
def kost_table(rows,total_label,total_val):
    t=doc.add_table(rows=1,cols=5); set_borders(t); setw(t,[74,26,18,26,26])
    hdr=t.rows[0].cells
    for c,txt,al in zip(hdr,["Position","Einheit","Menge","Einzelpreis","Gesamt / Monat"],
                        [WD_ALIGN_PARAGRAPH.LEFT,WD_ALIGN_PARAGRAPH.CENTER,WD_ALIGN_PARAGRAPH.CENTER,WD_ALIGN_PARAGRAPH.RIGHT,WD_ALIGN_PARAGRAPH.RIGHT]):
        shade(c,PURPLE); cell_text(c,txt,bold=True,color=HDR_TXT,size=9.5,align=al)
    for pos,ein,men,ep,ges in rows:
        cells=t.add_row().cells
        cell_text(cells[0],pos,size=9.5)
        cell_text(cells[1],ein,size=9.5,align=WD_ALIGN_PARAGRAPH.CENTER)
        cell_text(cells[2],men,size=9.5,align=WD_ALIGN_PARAGRAPH.CENTER)
        cell_text(cells[3],ep,size=9.5,align=WD_ALIGN_PARAGRAPH.RIGHT)
        cell_text(cells[4],ges,size=9.5,align=WD_ALIGN_PARAGRAPH.RIGHT)
    cells=t.add_row().cells
    for c in cells: shade(c,LIGHT)
    cell_text(cells[0],total_label,bold=True,color=PURPLE,size=10.5)
    for i in (1,2,3): cell_text(cells[i],"",size=10)
    cell_text(cells[4],total_val,bold=True,color=PURPLE,size=11,align=WD_ALIGN_PARAGRAPH.RIGHT)
    return t

def leistung_table(rows):
    t=doc.add_table(rows=1,cols=2); set_borders(t); setw(t,[44,CW-44])
    c=t.rows[0].cells; shade(c[0],TEAL); shade(c[1],TEAL)
    cell_text(c[0],"Leistungsumfang",bold=True,color=HDR_TXT,size=9.5)
    cell_text(c[1],"",size=9.5)
    for k,v in rows:
        cells=t.add_row().cells
        shade(cells[0],LIGHT); cell_text(cells[0],k,bold=True,size=9.5,color="333333")
        cell_text(cells[1],v,size=9.5)
    return t

doc.add_paragraph().paragraph_format.space_after=Pt(2)
doc.add_heading("Variante 1 — „Multi-Modell“ (Cloud-Inferenz)",level=2)
para("Betrieb mit token-basierter Inferenz über einen zertifizierten EU-Inferenzpartner. Mehrere Modelle und ein großer "
     "Kontext stehen zur Verfügung; die Rechenkapazität skaliert automatisch mit der Nachfrage.",size=10,space_after=6)
kost_table([
    ("Inferenz & Infrastruktur (Embedding-/Rerank-GPU, Plattform-VMs)","Pauschale / Monat","1","915,72 €","915,72 €"),
    ("API-Endpoint-Nutzung (mehrere Modelle, EU-Partner; bis 100 Mio. Token / Monat)","Pauschale / Monat","1","800,00 €","800,00 €"),
    ("Betrieb (24/7)","Pauschale / Monat","1","2.250,00 €","2.250,00 €"),
    ("Wartung & Support","Pauschale / Monat","1","1.500,00 €","1.500,00 €"),
],"Gesamt — Variante 1 (netto / Monat)","5.465,72 €")
para("",space_after=4)
leistung_table([
    ("Modelle","Mehrere Modelle wählbar"),
    ("Gleichzeitige Nutzer","Hohe Parallelität durch Autoskalierung des EU-Partners"),
    ("Kontext","Großer Kontext (bis zu 256.000 Token)"),
    ("Datenhaltung","EU (Italien), DSGVO-konform, Zero Data Retention, ISO 27001/27017/27018, CISPE-zertifiziert; Verarbeitung beim EU-Partner"),
    ("Reaktionszeit Support","4 Stunden zu Geschäftszeiten"),
    ("Modellprüfung","Vierteljährliche Prüfung der über den EU-Partner verfügbaren Modelle"),
])

doc.add_paragraph().add_run().add_break()
doc.add_heading("Variante 2 — „Private GPU – bis zu 30 gleichzeitige Nutzer“",level=2)
para("Betrieb auf dedizierter, privater GPU-Infrastruktur mit einem fest bereitgestellten Modell; die Inferenz erfolgt "
     "vollständig auf eigener Infrastruktur. Ausgelegt für bis zu 30 gleichzeitige Nutzer.",size=10,space_after=6)
kost_table([
    ("Infrastruktur (dedizierte GPU-Kapazität, ausgelegt für bis zu 30 gleichzeitige Nutzer)","Pauschale / Monat","1","4.929,50 €","4.929,50 €"),
    ("Betrieb (24/7)","Pauschale / Monat","1","2.250,00 €","2.250,00 €"),
    ("Wartung & Support","Pauschale / Monat","1","2.250,00 €","2.250,00 €"),
],"Gesamt — Variante 2 (netto / Monat)","9.429,50 €")
para("",space_after=4)
leistung_table([
    ("Modelle","1 dediziertes Modell (fix bereitgestellt)"),
    ("Gleichzeitige Nutzer","bis zu 30"),
    ("Kontext","32k (modellabhängig)"),
    ("Datenhaltung","Vollständig auf eigener / privater GPU-Infrastruktur (keine Verarbeitung durch Dritte)"),
    ("Reaktionszeit Support","4 Stunden zu Geschäftszeiten"),
    ("Modellprüfung","Vierteljährliche Prüfung der für die dedizierte GPU geeigneten Modelle"),
])

doc.add_paragraph().add_run().add_break()
doc.add_heading("Variante 3 — „Private GPU – bis zu 50 gleichzeitige Nutzer“",level=2)
para("Identischer Betriebs- und Leistungsumfang wie Variante 2, jedoch mit höherer dedizierter Rechenkapazität für bis zu "
     "50 gleichzeitige Nutzer. Der Unterschied liegt ausschließlich in der bereitgestellten Inferenzkapazität.",size=10,space_after=6)
kost_table([
    ("Infrastruktur (dedizierte GPU-Kapazität, ausgelegt für bis zu 50 gleichzeitige Nutzer)","Pauschale / Monat","1","7.051,39 €","7.051,39 €"),
    ("Betrieb (24/7)","Pauschale / Monat","1","2.250,00 €","2.250,00 €"),
    ("Wartung & Support","Pauschale / Monat","1","2.250,00 €","2.250,00 €"),
],"Gesamt — Variante 3 (netto / Monat)","11.551,39 €")
para("",space_after=4)
leistung_table([
    ("Modelle","1 dediziertes Modell (fix bereitgestellt)"),
    ("Gleichzeitige Nutzer","bis zu 50"),
    ("Kontext","32k (modellabhängig)"),
    ("Datenhaltung","Vollständig auf eigener / privater GPU-Infrastruktur (keine Verarbeitung durch Dritte)"),
    ("Reaktionszeit Support","4 Stunden zu Geschäftszeiten"),
    ("Modellprüfung","Vierteljährliche Prüfung der für die dedizierte GPU geeigneten Modelle"),
])

# ================= INCLUDED / OPTIONAL / EXCLUDED =================
doc.add_paragraph().add_run().add_break()
doc.add_heading("In allen Varianten enthalten",level=2)
for b in ["Kontinuierlicher Betrieb (24/7) der KI-Assistenzplattform",
          "Bereitstellung des KI-Chat-Assistenten für Mitarbeitende",
          "Anbindung und Betrieb der Wissensdatenbank (RAG) inkl. Vektordatenbank und Embeddings",
          "Bereitstellung der Inferenz- bzw. Rechenkapazität gemäß gewählter Variante",
          "Laufendes Monitoring und Betriebsführung",
          "Software- und Sicherheitsupdates sowie regelmäßige Sicherheitsprüfungen",
          "Vierteljährliche Modellprüfung",
          "Störungsbehebung und Anwendersupport, Reaktionszeit 4 Stunden zu Geschäftszeiten"]:
    bullet(b)

doc.add_heading("Optionale Zusatzleistungen",level=2)
para("Nicht im monatlichen Grundpreis enthalten; werden nur bei tatsächlicher Inanspruchnahme berechnet. Gilt für alle Varianten.",size=10,italic=True,space_after=4)
t=doc.add_table(rows=1,cols=5); set_borders(t); setw(t,[66,38,16,24,26])
for c,txt,al in zip(t.rows[0].cells,["Optionale Zusatzleistung","Detail","Menge","Einzelpreis","Gesamt"],
                    [WD_ALIGN_PARAGRAPH.LEFT,WD_ALIGN_PARAGRAPH.LEFT,WD_ALIGN_PARAGRAPH.CENTER,WD_ALIGN_PARAGRAPH.RIGHT,WD_ALIGN_PARAGRAPH.RIGHT]):
    shade(c,PURPLE); cell_text(c,txt,bold=True,color=HDR_TXT,size=9.5,align=al)
for pos,det,men,ep,ges in [
    ("Internet-Integration & -Nutzung","Pauschale bis 10.000 Anfragen / Monat","1","300,00 €","300,00 € / Monat"),
    ("Modellmigration (bei tatsächlichem Modellwechsel)","inkl. Tests, Datenintegration und Validierung","5 PT","1.500,00 €","7.500,00 € einmalig")]:
    cells=t.add_row().cells
    cell_text(cells[0],pos,size=9.5); cell_text(cells[1],det,size=9.5)
    cell_text(cells[2],men,size=9.5,align=WD_ALIGN_PARAGRAPH.CENTER)
    cell_text(cells[3],ep,size=9.5,align=WD_ALIGN_PARAGRAPH.RIGHT)
    cell_text(cells[4],ges,size=9.5,align=WD_ALIGN_PARAGRAPH.RIGHT)
para("",space_after=2)
para("Weitere optionale Leistungen auf Anfrage:",bold=True,size=10,space_after=2)
for b in ["Bereitstellung zusätzlicher Modelle (parallel)",
          "Erhöhung der Inferenzkapazität bzw. höhere Parallelität — nach Aufwand",
          "Standortübergreifende Hochverfügbarkeit / Geo-Redundanz",
          "Vertragliche Verfügbarkeitsgarantie (Uptime-SLA) — optional vereinbar",
          "Erweiterte Support-Zeiten bzw. 24/7-Support",
          "Zusätzliche Schulungen und Onboarding-Workshops — nach Aufwand (Tagessatz 1.500,00 € / PT)"]:
    bullet(b)

doc.add_heading("Nicht im Leistungsumfang enthalten",level=2)
para("Zur Klarstellung des Leistungsumfangs sind die folgenden Leistungen nicht enthalten (teils optional vereinbar):",size=10,italic=True,space_after=4)
for b in ["Internet-/Webzugriff des Assistenten (optional verfügbar, siehe Zusatzleistungen)",
          "Modellmigration auf ein neues Modell (optional verfügbar, siehe Zusatzleistungen)",
          "Standortübergreifende Hochverfügbarkeit / Geo-Redundanz (optional vereinbar)",
          "Vertragliche Verfügbarkeitsgarantie (Uptime-SLA) über die zugesagte Reaktionszeit hinaus (optional vereinbar)",
          "Support außerhalb der Geschäftszeiten bzw. 24/7-Support (optional vereinbar)",
          "Anbindung an Drittsysteme oder Schnittstellen, die nicht ausdrücklich vereinbart wurden",
          "Individuelle Software-Entwicklung bzw. neue Funktionen außerhalb des vereinbarten Umfangs",
          "Endgeräte, Client-Software und Netzwerk-Infrastruktur auf Kundenseite",
          "Datenmigration aus bestehenden Altsystemen"]:
    bullet(b)

# ================= VERGLEICHSÜBERSICHT (green/red) =================
doc.add_paragraph().add_run().add_break()
doc.add_heading("Vergleichsübersicht der Varianten",level=2)
para("Auf einen Blick: ✓ = enthalten / Vorteil   ·   ✗ = nicht enthalten",size=9.5,italic=True,color=GREY,space_after=4)
cmp=doc.add_table(rows=1,cols=4); set_borders(cmp); setw(cmp,[58,38,38,36])
heads=["Merkmal","V1 · Multi-Modell","V2 · Private GPU","V3 · Private GPU"]
for c,txt in zip(cmp.rows[0].cells,heads):
    shade(c,PURPLE); cell_text(c,txt,bold=True,color=HDR_TXT,size=9.5,align=WD_ALIGN_PARAGRAPH.CENTER)
# price row
pr=cmp.add_row().cells
cell_text(pr[0],"Monatspreis (netto)",bold=True,size=9.5)
for i,v in zip((1,2,3),["5.465,72 €","9.429,50 €","11.551,39 €"]):
    shade(pr[i],LIGHT); cell_text(pr[i],v,bold=True,color=PURPLE,size=10,align=WD_ALIGN_PARAGRAPH.CENTER)

def cmp_row(label,vals):
    # vals: list of (kind,text) kind in 'y','n','v'
    cells=cmp.add_row().cells
    cell_text(cells[0],label,bold=True,size=9.5,color="333333")
    for i,(kind,text) in zip((1,2,3),vals):
        if kind=='y':
            shade(cells[i],GREEN_BG); cell_text(cells[i],"✓ "+text if text else "✓",bold=True,color=GREEN,size=9.5,align=WD_ALIGN_PARAGRAPH.CENTER)
        elif kind=='n':
            shade(cells[i],RED_BG); cell_text(cells[i],"✗ "+text if text else "✗",bold=True,color=RED,size=9.5,align=WD_ALIGN_PARAGRAPH.CENTER)
        else:
            cell_text(cells[i],text,size=9.5,align=WD_ALIGN_PARAGRAPH.CENTER)

cmp_row("Inferenz-Art",[('v',"Cloud / Token (EU-Partner)"),('v',"Dedizierte private GPU"),('v',"Dedizierte private GPU")])
cmp_row("Mehrere Modelle wählbar",[('y',""),('n',"1 fix"),('n',"1 fix")])
cmp_row("Daten 100 % auf eigener/privater Infrastruktur",[('n',"EU-Partner"),('y',""),('y',"")])
cmp_row("Großer Kontext (bis 256k Token)",[('y',""),('n',"32k"),('n',"32k")])
cmp_row("Automatische Skalierung / hohe Parallelität",[('y',""),('n',""),('n',"")])
cmp_row("Gleichzeitige Nutzer",[('v',"Hoch (autoskaliert)"),('v',"bis 30"),('v',"bis 50")])
cmp_row("24/7-Betrieb",[('y',""),('y',""),('y',"")])
cmp_row("Wartung & Support (Reaktion 4 h)",[('y',""),('y',""),('y',"")])
cmp_row("Vierteljährliche Modellprüfung",[('y',""),('y',""),('y',"")])
cmp_row("DSGVO-konforme Datenhaltung",[('y',"EU, Zero Retention"),('y',"eigene GPU"),('y',"eigene GPU")])

# ================= HINWEISE =================
para("",space_after=6)
doc.add_heading("Hinweise",level=2)
for b in ["Tagessatz für optionale Leistungen nach Aufwand: 1.500,00 € pro Personentag (PT). Alle Preise netto, zzgl. gesetzlicher USt.",
          "Variante 1: Die API-Endpoint-Nutzung ist bis 100 Mio. Token pro Monat abgedeckt; darüber hinausgehende Nutzung wird nach Aufwand berechnet.",
          "Variante 2 und Variante 3 enthalten identische Betriebs- und Wartungsleistungen; der Preisunterschied ergibt sich ausschließlich aus der bereitgestellten Inferenzkapazität (bis zu 30 bzw. 50 gleichzeitige Nutzer).",
          "Optionale Zusatzleistungen werden nur bei tatsächlicher Inanspruchnahme berechnet.",
          "Abrechnung monatlich. Vertragslaufzeit: 6 Monate, anschließend verlängerbar.",
          "Dieses Angebot ist freibleibend. Gültigkeit: 30 Tage ab Angebotsdatum."]:
    bullet(b)

para("",space_after=6)
para("Für Rückfragen sowie zur gemeinsamen Auswahl der passenden Variante stehen wir Ihnen gerne zur Verfügung.",size=10.5,space_after=10)
para("Mit freundlichen Grüßen",size=10.5,space_after=14)
para("Nemanja Klincov",bold=True,size=10.5,space_after=0,color=PURPLE)
para("Geschäftsführer · BReact GmbH",size=9.5,color=GREY,space_after=0)

# fix anbieter email line typo (helloplappi -> breact) by editing in place is hard; set correctly above
out="/tmp/angebot_STW_neu.docx"
doc.save(out)
# verify reopen
d2=Document(out); print("OK paragraphs:",len(d2.paragraphs),"tables:",len(d2.tables),"->",out)
