#!/usr/bin/env python3
"""Assemble a print-ready, double-sided, 3-hole-punch MASTER EVIDENTIARY SUPPORT BINDER.

- Cover sheet, paginated exhibit index with real 'begins at' page references.
- Each exhibit preceded by a divider that always lands on a right-hand (recto/odd) page.
- Blank pages auto-inserted so double-sided printing keeps dividers on the right.
- Every page numbered bottom-right (clear of the left-edge punch holes).
Output: one PDF -> print double-sided, 3-hole punched, in one pass.
"""
import json, io
import fitz  # PyMuPDF
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch
from reportlab.lib.colors import HexColor, white
from reportlab.lib.enums import TA_LEFT
from reportlab.lib.styles import ParagraphStyle
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
from reportlab.pdfgen import canvas

FOLDER = '/Users/icloudabe/GLAS_Rosenwald_Deep_Dive/JOINT_INQUIRY_PACKAGE/MASTER_EVIDENTIARY_SUPPORT_BINDER'
MANIFEST = json.load(open(f'{FOLDER}/manifest.json'))
OUT = f'{FOLDER}/MASTER_EVIDENTIARY_SUPPORT_BINDER_PRINT_READY.pdf'
DATE = 'July 10, 2026'

NAVY = HexColor('#050a1a'); CYAN = HexColor('#0089a8'); GOLD = HexColor('#9a7212')
CYAN_B = HexColor('#00d4ff'); GOLD_B = HexColor('#f0b429'); INK = HexColor('#1d2336'); DIM = HexColor('#51607a')
PW, PH = letter          # 612 x 792
LM = 1.05 * inch         # generous left margin for the 3-hole punch
RM = 0.8 * inch

def spine(c):
    """AVOWAL cyan/gold left spine (kept inside so punch holes miss it)."""
    c.setFillColor(CYAN_B); c.rect(0, PH*0.40, 6, PH*0.60, stroke=0, fill=1)
    c.setFillColor(GOLD_B); c.rect(0, 0, 6, PH*0.40, stroke=0, fill=1)

def wrap(c, text, x, y, width, font='Helvetica', size=10, leading=13, color=INK):
    from reportlab.lib.utils import simpleSplit
    c.setFont(font, size); c.setFillColor(color)
    for line in simpleSplit(text, font, size, width):
        c.drawString(x, y, line); y -= leading
    return y

def cover_bytes():
    buf = io.BytesIO(); c = canvas.Canvas(buf, pagesize=letter)
    spine(c)
    c.setStrokeColor(NAVY); c.setLineWidth(1.4); c.line(LM, PH-1.5*inch, PW-RM, PH-1.5*inch)
    c.setFont('Helvetica-Bold', 9); c.setFillColor(CYAN)
    c.drawString(LM, PH-1.35*inch, 'A.R.  PRO SE  ·  STRATEGIC OPERATIONS')
    c.setFont('Helvetica-Bold', 27); c.setFillColor(NAVY)
    c.drawString(LM, PH-2.55*inch, 'MASTER EVIDENTIARY')
    c.drawString(LM, PH-3.05*inch, 'SUPPORT BINDER')
    c.setFont('Helvetica', 13); c.setFillColor(DIM)
    c.drawString(LM, PH-3.5*inch, 'Primary public records supporting the coordinated inquiries')
    c.setFont('Helvetica-Bold', 12); c.setFillColor(GOLD)
    c.drawString(LM, PH-3.9*inch, 'Dalton  ·  RCM  ·  Kings Bay  ·  Beach Front  ·  Glass House')
    y = PH-4.7*inch
    c.setFont('Helvetica-Bold', 10.5); c.setFillColor(INK); c.drawString(LM, y, f'Date:  {DATE}')
    y -= 16; c.drawString(LM, y, '10 exhibits  ·  482 pages of primary source records')
    y -= 28
    note = ('This binder contains primary public records that provide the good-faith foundation for the '
            'accompanying inquiries. It is not offered as proof of wrongdoing. A document proves only what it '
            'states; absence from a public filing is not proof that a relationship or transaction does not '
            'exist. First-hand observations are separately attributed in the letters, not converted into '
            'public-record facts.')
    y = wrap(c, note, LM, y, PW-LM-RM, 'Helvetica', 10, 14, DIM)
    y -= 26
    c.setStrokeColor(HexColor('#cccccc')); c.setLineWidth(0.75); c.line(LM, y, PW-RM, y); y -= 20
    c.setFont('Helvetica', 10.5); c.setFillColor(INK)
    for ln in ['Prepared by:  Abraham Rosenwald, Self-Represented Party',
               '1127 High Ridge Road, Suite 151, Stamford, CT 06905',
               'abe@avowal.ai  ·  (203) 391-1041']:
        c.drawString(LM, y, ln); y -= 15
    c.showPage(); c.save(); return buf.getvalue()

def index_bytes(refs):
    buf = io.BytesIO()
    doc = SimpleDocTemplate(buf, pagesize=letter, leftMargin=LM, rightMargin=RM,
                            topMargin=0.8*inch, bottomMargin=0.9*inch)
    h = ParagraphStyle('h', fontName='Helvetica-Bold', fontSize=17, textColor=NAVY, spaceAfter=4)
    sub = ParagraphStyle('sub', fontName='Helvetica', fontSize=9.5, textColor=DIM, spaceAfter=12, leading=13)
    cell = ParagraphStyle('cell', fontName='Helvetica', fontSize=8.6, textColor=INK, leading=11)
    cellb = ParagraphStyle('cellb', fontName='Helvetica-Bold', fontSize=8.6, textColor=NAVY, leading=11)
    hd = ParagraphStyle('hd', fontName='Helvetica-Bold', fontSize=8.2, textColor=white, leading=10)
    note_h = ParagraphStyle('nh', fontName='Helvetica-Bold', fontSize=10, textColor=NAVY, spaceBefore=12, spaceAfter=3)
    note = ParagraphStyle('n', fontName='Helvetica', fontSize=8.6, textColor=DIM, leading=12, spaceAfter=2)
    story = [Paragraph('EXHIBIT INDEX', h),
             Paragraph('Master Evidentiary Support Binder  ·  ' + DATE + '  ·  double-sided; each exhibit tab begins on a right-hand page.', sub)]
    rows = [[Paragraph('TAB', hd), Paragraph('PRIMARY SOURCE', hd), Paragraph('PP.', hd), Paragraph('BEGINS AT', hd)]]
    for i, x in enumerate(MANIFEST, 1):
        rows.append([Paragraph(f'EX-{i:02d}', cellb),
                     Paragraph(x['title'], cell),
                     Paragraph(str(x['pages']), cell),
                     Paragraph(f"p. {refs.get(x['id'], 0)}", cellb)])
    t = Table(rows, colWidths=[0.6*inch, 4.35*inch, 0.55*inch, 0.85*inch], repeatRows=1)
    t.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), NAVY),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [white, HexColor('#f4f7fc')]),
        ('LINEBELOW', (0,0), (-1,-1), 0.4, HexColor('#cccccc')),
        ('LINEABOVE', (0,0), (-1,0), 0, white),
        ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
        ('ALIGN', (2,0), (3,-1), 'CENTER'),
        ('LEFTPADDING', (0,0), (-1,-1), 6), ('RIGHTPADDING', (0,0), (-1,-1), 6),
        ('TOPPADDING', (0,0), (-1,-1), 5), ('BOTTOMPADDING', (0,0), (-1,-1), 5),
    ]))
    story.append(t)
    story.append(Paragraph('Evidentiary limits', note_h))
    story.append(Paragraph('This binder is not offered as proof of wrongdoing. Each document proves only what it states. '
                           'Absence of a fact from a public filing is not proof the fact does not exist. Inferences and '
                           'first-hand observations are identified as such in the accompanying letters.', note))
    story.append(Paragraph('Records requested but not supplied here as primary exhibits', note_h))
    for g in ['The complete June 2026 SEC deconsolidation package and the unavailable consulting/management, note, '
              'source-of-funds, side-letter and audit-workpaper records (requested from GLAS, NSJB, GHR, MGO and others).',
              'Complete DCC citation and ownership/financial-interest files (requested by CPRA).',
              'Certified California entity and UCC histories (requested from the Secretary of State).',
              'Nonpublic investor identities, personal trading records, adviser compliance files, board minutes, and '
              'auditor workpapers (voluntary requests unless obtained through lawful process).']:
        story.append(Paragraph('&bull;&nbsp;&nbsp;' + g, note))
    doc.build(story)
    return buf.getvalue()

def divider_bytes(i, x):
    buf = io.BytesIO(); c = canvas.Canvas(buf, pagesize=letter)
    spine(c)
    # tab block, right side
    c.setFillColor(NAVY); c.rect(PW-1.9*inch, PH-2.5*inch, 1.9*inch, 0.9*inch, stroke=0, fill=1)
    c.setFillColor(white); c.setFont('Helvetica-Bold', 30)
    c.drawRightString(PW-0.55*inch, PH-2.12*inch, f'EX-{i:02d}')
    c.setStrokeColor(GOLD_B); c.setLineWidth(3); c.line(LM, PH-2.05*inch, LM+2.6*inch, PH-2.05*inch)
    c.setFont('Helvetica-Bold', 11); c.setFillColor(CYAN); c.drawString(LM, PH-1.7*inch, f'EXHIBIT {i}')
    y = PH-2.6*inch
    y = wrap(c, x['title'], LM, y, PW-LM-2.2*inch, 'Helvetica-Bold', 16, 20, NAVY)
    y -= 14
    c.setFont('Helvetica-Bold', 10); c.setFillColor(GOLD); c.drawString(LM, y, f"{x['pages']} pages"); y -= 22
    c.setFont('Helvetica-Bold', 9); c.setFillColor(INK); c.drawString(LM, y, 'Relevance to inquiry'); y -= 14
    y = wrap(c, x['use'], LM, y, PW-LM-RM, 'Helvetica', 10, 14, DIM); y -= 20
    c.setFont('Helvetica-Bold', 9); c.setFillColor(INK); c.drawString(LM, y, 'Preserved source'); y -= 13
    y = wrap(c, x['source'], LM, y, PW-LM-RM, 'Helvetica', 7.6, 10, DIM); y -= 16
    c.setFont('Helvetica-Bold', 9); c.setFillColor(INK); c.drawString(LM, y, 'SHA-256'); y -= 13
    y = wrap(c, x['sha256'], LM, y, PW-LM-RM, 'Courier', 8, 11, DIM)
    c.showPage(); c.save(); return buf.getvalue()

# ---- Pass A: index page count with placeholder refs ----
N_IDX = fitz.open('pdf', index_bytes({x['id']: 0 for x in MANIFEST})).page_count

# ---- layout pass: cover(1) + blank(1) + index(N_IDX) + per-exhibit[blank?]+divider+pages ----
running = 1 + 1 + N_IDX
refs = {}
for x in MANIFEST:
    if running % 2 == 1:          # odd -> next page is verso; pad so divider is recto
        running += 1
    running += 1                  # divider (recto/odd)
    refs[x['id']] = running
    running += x['pages']

# ---- Pass B: final index carrying the computed 'begins at' pages ----
idx_final = index_bytes(refs)
if fitz.open('pdf', idx_final).page_count != N_IDX:
    raise SystemExit('index page count shifted; adjust layout')

# ---- assemble ----
final = fitz.open(); blanks = set()
def add_bytes(b): final.insert_pdf(fitz.open('pdf', b))
def add_file(p): final.insert_pdf(fitz.open(p))
def add_blank():
    final.new_page(width=PW, height=PH); blanks.add(final.page_count - 1)

add_bytes(cover_bytes())          # p1
add_blank()                       # p2
add_bytes(idx_final)              # index
for i, x in enumerate(MANIFEST, 1):
    if final.page_count % 2 == 1: # pad so divider is recto
        add_blank()
    add_bytes(divider_bytes(i, x))
    add_file(x['binder_file'])

# pad to an even sheet count so the final double-sided sheet is clean
if final.page_count % 2 == 1:
    add_blank()
TOTAL = final.page_count

# ---- number every page (bottom-right, clear of left punch holes) ----
for idx, page in enumerate(final):
    r = page.rect; n = idx + 1
    label = f'Page {n} of {TOTAL}'
    tw = fitz.get_text_length(label, fontname='helv', fontsize=8)
    x1 = r.width - 0.55*72; y1 = r.height - 0.34*72
    page.draw_rect(fitz.Rect(x1 - tw - 6, y1 - 11, x1 + 4, y1 + 3), color=None, fill=(1,1,1), overlay=True)
    page.insert_text(fitz.Point(x1 - tw, y1 - 2), label, fontname='helv', fontsize=8, color=(0.32,0.38,0.48))
    if idx in blanks:
        page.insert_textbox(fitz.Rect(0, r.height/2 - 8, r.width, r.height/2 + 8),
                            'This page intentionally left blank',
                            fontname='helv', fontsize=9, color=(0.7,0.74,0.8), align=1)

final.save(OUT, garbage=4, deflate=True)
print(f'WROTE {OUT}')
print(f'  total pages: {TOTAL} (even={TOTAL%2==0})  index pages: {N_IDX}  blanks: {len(blanks)}')
print('  exhibit tab pages:', ', '.join(f"EX-{i:02d}=p{refs[x['id']]}" for i, x in enumerate(MANIFEST, 1)))
