#!/usr/bin/env python3
"""Create an editable, paginated company report while preserving the branded header."""
from pathlib import Path
import json,zipfile,hashlib
from docx import Document
from docx.shared import Pt,Cm,RGBColor
from docx.enum.style import WD_STYLE_TYPE
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
OUT=Path(__file__).resolve().parent
ROOT=OUT.parents[1]
TEMPLATE=ROOT/'standards-stack/agent-skills/skills/kangbite-word-template/assets/kangbite-digital-sports-word-template.docx'
STARTER=OUT/'tmp/starter.docx'
DEST=OUT/'output/数字技术中心AI已落地应用与跨团队复制指南_20260926.docx'
EXPECTED='3c3a53327faccaec22b753a8a2a6d55f399f83aff2c9d4791b7c8fceefbd7f13'
assert hashlib.sha256(TEMPLATE.read_bytes()).hexdigest()==EXPECTED
pages=json.loads((OUT/'report-content.json').read_text())
doc=Document(STARTER)
for p in list(doc.paragraphs):
 if not p.text:p._element.getparent().remove(p._element)
# New styles only: preserve the template's Header style and original page geometry.
def sty(name,size,bold=False,color='30343B',before=0,after=5):
 s=doc.styles.add_style(name,WD_STYLE_TYPE.PARAGRAPH);s.font.name='Arial';s.font.size=Pt(size);s.font.bold=bold;s.font.color.rgb=RGBColor.from_string(color)
 s.element.get_or_add_rPr().get_or_add_rFonts().set(qn('w:eastAsia'),'Microsoft YaHei')
 f=s.paragraph_format;f.space_before=Pt(before);f.space_after=Pt(after);f.line_spacing=Pt(16.5 if size<=11.5 else size*1.3)
 f.widow_control=True
 if name in ['CPTTitle','CPTPageTitle','CPTHeading']:f.keep_with_next=True
 return s
sty('CPTTitle',23,True,'E65C1E',after=9)
sty('CPTSubtitle',12,False,'606773',after=10)
sty('CPTPageTitle',17,True,'E65C1E',after=12)
sty('CPTHeading',12.5,True,'AD451D',before=7,after=5)
sty('CPTBody',11,after=5)
sty('CPTNote',10.5,False,'606773',before=3,after=7)
sty('CPTSmall',9.5,False,'606773',after=3)
sty('CPTTable',10.5,after=1)
def para(text,style='CPTBody'):
 p=doc.add_paragraph(text,style);p.paragraph_format.line_spacing=Pt(15.5 if style in ['CPTTable','CPTSmall'] else p.paragraph_format.line_spacing.pt if p.paragraph_format.line_spacing else 16.5)
 return p
def table(head,rows):
 n=len(head); t=doc.add_table(rows=1,cols=n);t.autofit=False
 widths=[3.1,11.55] if n==2 else [3.0,7.9,3.75]
 if head[0]=='编号':widths=[1.1,7.1,6.45]
 if head[0]=='阶段':widths=[3.3,7.0,4.35]
 for c,w in zip(t.columns,widths):c.width=Cm(w)
 for ri,vals in enumerate([head]+rows):
  cells=t.rows[0].cells if ri==0 else t.add_row().cells
  for j,(c,v) in enumerate(zip(cells,vals)):
   c.width=Cm(widths[j]);pr=c._tc.get_or_add_tcPr()
   marg=OxmlElement('w:tcMar')
   for side,size in [('top',65),('bottom',65),('left',90),('right',90)]:
    el=OxmlElement('w:'+side);el.set(qn('w:w'),str(size));el.set(qn('w:type'),'dxa');marg.append(el)
   pr.append(marg)
   borders=OxmlElement('w:tcBorders')
   for side in ['top','bottom','left','right']:
    el=OxmlElement('w:'+side);el.set(qn('w:val'),'single');el.set(qn('w:sz'),'4');el.set(qn('w:color'),'E8DDD5');borders.append(el)
   pr.append(borders)
   if ri==0:
    sh=OxmlElement('w:shd');sh.set(qn('w:fill'),'FDEFE4');pr.append(sh)
   p=c.paragraphs[0];p.style=doc.styles['CPTTable'];p.paragraph_format.line_spacing=Pt(14.5)
   r=p.add_run(v);r.bold=(ri==0)
  trp=t.rows[ri]._tr.get_or_add_trPr();trp.append(OxmlElement('w:cantSplit'))
  if ri==0:trp.append(OxmlElement('w:tblHeader'))
 para('', 'CPTSmall').paragraph_format.space_after=Pt(1)
 return t
md=[]
for i,page in enumerate(pages):
 if i:doc.add_page_break()
 spacer=doc.add_paragraph(style='CPTSmall');spacer.paragraph_format.line_spacing=Pt(8);spacer.paragraph_format.space_after=Pt(0);spacer.add_run('').font.size=Pt(8)
 para(page['title'],'CPTTitle' if i==0 else 'CPTPageTitle');md+=['# '+page['title'],'']
 if page.get('subtitle'):para(page['subtitle'],'CPTSubtitle');md += [page['subtitle'],'']
 if i==0:para('CPTAI native  |  2026年9月26日  |  公司内部交流','CPTSmall')
 num=0
 for block in page['blocks']:
  kind=block[0]
  if kind=='h':para(block[1],'CPTHeading');md+=['## '+block[1],''];num=0
  elif kind=='p':para(block[1]);md += [block[1],'']
  elif kind in ['small','note']:
   p=para(block[1],'CPTSmall' if kind=='small' else 'CPTNote')
   if kind=='note':
    sh=OxmlElement('w:shd');sh.set(qn('w:fill'),'FFF7F1');p._p.get_or_add_pPr().append(sh)
   md += [block[1],'']
  elif kind=='label':
   p=doc.add_paragraph(style='CPTBody');p.add_run(block[1]+'：').bold=True;p.add_run(block[2]);md += ['**'+block[1]+'：**'+block[2],'']
  elif kind=='num':
   num+=1;p=doc.add_paragraph(style='CPTBody');p.add_run(str(num)+'. ').bold=True;p.add_run(block[1]);md += [str(num)+'. '+block[1],'']
  elif kind=='table':
   table(block[1],block[2]);md += ['| '+' | '.join(block[1])+' |','|'+'|'.join('---' for _ in block[1])+'|',*['| '+' | '.join(row)+' |' for row in block[2]],'']
footer=doc.sections[0].footer.paragraphs[0];footer.style=doc.styles['CPTSmall'];footer.alignment=WD_ALIGN_PARAGRAPH.CENTER
footer.add_run('数字技术中心 · AI应用复制指南   |   ')
fld=OxmlElement('w:fldSimple');fld.set(qn('w:instr'),'PAGE');footer._p.append(fld)
doc.core_properties.title='数字技术中心AI已落地应用与跨团队复制指南'
doc.core_properties.subject='已应用内容、真实产出、复制步骤、人员分工与试点验收'
doc.core_properties.author='数字技术中心'
doc.core_properties.keywords='AI应用,跨团队复制,康比特,内部交流'
DEST.parent.mkdir(exist_ok=True);doc.save(DEST)
# Preserve the three header package parts byte-for-byte after library serialization.
parts=['word/header1.xml','word/_rels/header1.xml.rels','word/media/image1.png']
with zipfile.ZipFile(TEMPLATE) as z:original={n:z.read(n) for n in parts}
with zipfile.ZipFile(DEST) as z:files={n:z.read(n) for n in z.namelist()}
files.update(original)
with zipfile.ZipFile(DEST,'w',zipfile.ZIP_DEFLATED) as z:
 for n,data in files.items():z.writestr(n,data)
(OUT/'report.md').write_text('\n'.join(md).rstrip()+'\n')
print(DEST)
