"""Render the final Markdown research note as a compact, linked PDF.

Uses reportlab 4.4.9. No model calls, source edits or network requests.
"""
import argparse
from html import escape
from pathlib import Path
import re

from reportlab import rl_config
from reportlab.lib import colors
from reportlab.lib.enums import TA_LEFT
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import ParagraphStyle,getSampleStyleSheet
from reportlab.platypus import SimpleDocTemplate,Paragraph,Spacer,Table,TableStyle,Image,KeepTogether,Preformatted,CondPageBreak


def inline(text):
 text=text.replace('−','-').replace('–','-').replace('—','-').replace('’',"'").replace('“','"').replace('”','"')
 pattern=r'(`[^`]+`|\*\*[^*]+\*\*|\[[^\]]+\]\([^)]+\))'
 out=[]
 for part in re.split(pattern,text):
  if part.startswith('`') and part.endswith('`'):out.append('<font name="Courier" size="8.3">'+escape(part[1:-1])+'</font>')
  elif part.startswith('**') and part.endswith('**'):out.append('<b>'+escape(part[2:-2])+'</b>')
  elif re.fullmatch(r'\[[^\]]+\]\([^)]+\)',part):
   match=re.fullmatch(r'\[([^\]]+)\]\(([^)]+)\)',part);label,url=match.groups();out.append('<link href="'+escape(url,quote=True)+'" color="#274e76">'+escape(label)+'</link>')
  else:out.append(escape(part))
 return ''.join(out)


def build(source,destination):
 source=Path(source);destination=Path(destination);destination.parent.mkdir(parents=True,exist_ok=True)
 styles=getSampleStyleSheet()
 styles.add(ParagraphStyle(name='ResearchBody',fontName='Times-Roman',fontSize=10.1,leading=14,spaceAfter=8,textColor=colors.HexColor('#202531')))
 styles.add(ParagraphStyle(name='ResearchTitle',fontName='Helvetica-Bold',fontSize=23,leading=28,spaceAfter=16,textColor=colors.HexColor('#182c42')))
 styles.add(ParagraphStyle(name='ResearchH2',fontName='Helvetica-Bold',fontSize=13.3,leading=17,spaceBefore=17,spaceAfter=8,keepWithNext=True,textColor=colors.HexColor('#182c42')))
 styles.add(ParagraphStyle(name='ResearchH3',fontName='Helvetica-Bold',fontSize=10.7,leading=15,spaceBefore=10,spaceAfter=6,keepWithNext=True,textColor=colors.HexColor('#182c42')))
 styles.add(ParagraphStyle(name='ResearchCell',fontName='Helvetica',fontSize=7.5,leading=10.3,spaceAfter=0))
 styles.add(ParagraphStyle(name='ResearchCaption',fontName='Helvetica',fontSize=8,leading=11,spaceAfter=12,textColor=colors.HexColor('#526174')))
 width=A4[0]-100;story=[];lines=source.read_text(encoding='utf-8').splitlines();i=0
 while i<len(lines):
  line=lines[i].strip()
  if not line:i+=1;continue
  if line.startswith('# '):story.append(Paragraph(inline(line[2:]),styles['ResearchTitle']));i+=1;continue
  if line.startswith('## '):story += [CondPageBreak(120),Paragraph(inline(line[3:]),styles['ResearchH2'])];i+=1;continue
  if line.startswith('### '):story += [CondPageBreak(85),Paragraph(inline(line[4:]),styles['ResearchH3'])];i+=1;continue
  if line.startswith('!['):
   match=re.fullmatch(r'!\[([^\]]*)\]\(([^)]+)\)',line)
   if not match:raise ValueError('Invalid figure line: '+line)
   label,path=match.groups();image=Image(str(source.parent/path));image.drawHeight=image.imageHeight*width/image.imageWidth;image.drawWidth=width
   story.append(KeepTogether([Spacer(1,7),image,Spacer(1,5),Paragraph(escape(label)+'. Full-resolution PNG and vector SVG are included with the evidence.',styles['ResearchCaption'])]));i+=1;continue
  if line.startswith('|'):
   raw=[]
   while i<len(lines) and lines[i].strip().startswith('|'):
    cells=[x.strip() for x in lines[i].strip().strip('|').split('|')]
    if not all(re.fullmatch(r':?-+:?',x) for x in cells):raw.append(cells)
    i+=1
   n=len(raw[0]);weights=[max(10,min(45,max(len(row[j]) for row in raw))) for j in range(n)];widths=[width*x/sum(weights) for x in weights]
   table=Table([[Paragraph(('<b>'+inline(x)+'</b>') if r==0 else inline(x),styles['ResearchCell']) for x in row] for r,row in enumerate(raw)],colWidths=widths,repeatRows=1,hAlign='LEFT')
   table.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),colors.HexColor('#e9eef3')),('TEXTCOLOR',(0,0),(-1,0),colors.HexColor('#182c42')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),6),('RIGHTPADDING',(0,0),(-1,-1),6),('TOPPADDING',(0,0),(-1,-1),6),('BOTTOMPADDING',(0,0),(-1,-1),6),('LINEBELOW',(0,0),(-1,0),.6,colors.HexColor('#8193a7')),('LINEBELOW',(0,1),(-1,-1),.25,colors.HexColor('#d8dfe7'))]))
   table.spaceBefore=5
   story += [KeepTogether([table]) if len(raw)<=5 else table,Spacer(1,12)];continue
  if line.startswith('```'):
   i+=1;code=[]
   while i<len(lines) and not lines[i].startswith('```'):code.append(lines[i]);i+=1
   story.append(Preformatted('\n'.join(code),ParagraphStyle(name='CodeBlock',fontName='Courier',fontSize=8,leading=11,spaceAfter=10)));i+=1;continue
  paragraph=[]
  while i<len(lines) and lines[i].strip() and not lines[i].startswith(('#','|','![','```')):
   paragraph.append(lines[i].strip());i+=1
  story.append(Paragraph(inline(' '.join(paragraph)),styles['ResearchBody']))
 def footer(canvas,doc):
  canvas.saveState();canvas.setStrokeColor(colors.HexColor('#d5dde5'));canvas.setLineWidth(.5);canvas.line(50,40,A4[0]-50,40);canvas.setFont('Helvetica',8);canvas.setFillColor(colors.HexColor('#647184'));canvas.drawString(50,27,'AgentCollusion | Research note | 6 September 2026');canvas.drawRightString(A4[0]-50,27,str(doc.page));canvas.restoreState()
 rl_config.warnOnMissingFontGlyphs=1
 doc=SimpleDocTemplate(str(destination),pagesize=A4,rightMargin=50,leftMargin=50,topMargin=44,bottomMargin=54,title='Model Configurations, Information Displays, and Price Coordination in A2A Transactions',author='Kotaro OKUYAMA / AgentCollusion',subject='AI-assisted synthetic experiments; not peer reviewed')
 doc.build(story,onFirstPage=footer,onLaterPages=footer)
 print('Wrote '+str(destination))


if __name__=='__main__':
 ap=argparse.ArgumentParser();ap.add_argument('source');ap.add_argument('output');args=ap.parse_args();build(args.source,args.output)
