import io
import os
import re
import json
import datetime
import asyncio
import subprocess
import tempfile
from typing import Optional
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter, A4, landscape
from reportlab.lib.units import inch, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT, TA_JUSTIFY
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle,
    PageBreak, HRFlowable, KeepTogether, Frame, PageTemplate, BaseDocTemplate,
    NextPageTemplate, Flowable
)
from reportlab.graphics.shapes import Drawing, Rect, String, Line
from reportlab.graphics import renderPDF
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont


def _register_luxury_fonts():
    paths = {
        'LuxSerif-Bold': '/usr/share/fonts/truetype/dejavu/DejaVuSerif-Bold.ttf',
        'LuxSerif': '/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf',
        'LuxSans': '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
        'LuxSans-Bold': '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf',
    }
    registered = {}
    for name, path in paths.items():
        try:
            if os.path.exists(path):
                pdfmetrics.registerFont(TTFont(name, path))
                registered[name] = True
        except Exception:
            pass
    return registered


_FONTS = _register_luxury_fonts()
HEADING_BOLD = 'LuxSerif-Bold' if 'LuxSerif-Bold' in _FONTS else 'Times-Bold'
HEADING_REG = 'LuxSerif' if 'LuxSerif' in _FONTS else 'Times-Roman'
BODY_SANS = 'LuxSans' if 'LuxSans' in _FONTS else 'Helvetica'
BODY_SANS_BOLD = 'LuxSans-Bold' if 'LuxSans-Bold' in _FONTS else 'Helvetica-Bold'


BRAND_PURPLE = colors.HexColor("#6366f1")
BRAND_PURPLE_DARK = colors.HexColor("#4338ca")
BRAND_PURPLE_LIGHT = colors.HexColor("#a5b4fc")
BRAND_VIOLET = colors.HexColor("#8b5cf6")
BRAND_AMBER = colors.HexColor("#f59e0b")
BRAND_EMERALD = colors.HexColor("#10b981")
DARK_BG = colors.HexColor("#0f172a")
DARK_CARD = colors.HexColor("#1e1b4b")
TEXT_WHITE = colors.HexColor("#f1f5f9")
TEXT_GRAY = colors.HexColor("#94a3b8")
TEXT_LIGHT = colors.HexColor("#e2e8f0")
TEXT_DARK = colors.HexColor("#1e293b")
TEXT_BODY = colors.HexColor("#334155")
TEXT_MUTED = colors.HexColor("#64748b")
BORDER_LIGHT = colors.HexColor("#e2e8f0")
BG_LIGHT = colors.HexColor("#f8fafc")
BG_SECTION = colors.HexColor("#f1f5f9")

SECTION_LABELS = {
    "hero": "Hero Section",
    "problem": "Problem Statement",
    "solution": "Solution / Value Proposition",
    "about": "About / Our Story",
    "features": "Features",
    "benefits": "Benefits",
    "how_it_works": "How It Works",
    "testimonials": "Testimonials",
    "pricing": "Pricing",
    "faq": "FAQ",
    "cta": "Call to Action",
    "social_proof": "Social Proof",
    "comparison": "Comparison",
    "guarantee": "Guarantee",
    "team": "Team",
    "contact": "Contact",
    "offer": "Offer",
    "stats": "Statistics",
    "newsletter": "Newsletter",
    "gallery": "Gallery",
    "blog_preview": "Blog Preview",
    "partner_logos": "Partner Logos",
}

DOC_TIER_COLORS = {
    "business_docs": colors.HexColor("#3B82F6"),
    "legal": colors.HexColor("#EF4444"),
    "contracts": colors.HexColor("#F59E0B"),
    "marketing": colors.HexColor("#8B5CF6"),
    "operations": colors.HexColor("#10B981"),
    "calculators": colors.HexColor("#EC4899"),
}

DOC_TIER_LABELS = {
    "business_docs": "Business Documents",
    "legal": "Legal & Compliance",
    "contracts": "Client Contracts",
    "marketing": "Marketing Arsenal",
    "operations": "Operations Toolkit",
    "calculators": "Calculators & Quoting",
}


class GradientRect(Flowable):
    def __init__(self, width, height, color1, color2):
        Flowable.__init__(self)
        self.width = width
        self.height = height
        self.color1 = color1
        self.color2 = color2

    def draw(self):
        c = self.canv
        steps = 50
        for i in range(steps):
            r = self.color1.red + (self.color2.red - self.color1.red) * i / steps
            g = self.color1.green + (self.color2.green - self.color1.green) * i / steps
            b = self.color1.blue + (self.color2.blue - self.color1.blue) * i / steps
            c.setFillColor(colors.Color(r, g, b))
            x = self.width * i / steps
            w = self.width / steps + 1
            c.rect(x, 0, w, self.height, fill=True, stroke=False)


class FullBleedCover(Flowable):
    """Legendary full-bleed dark cover page with brand colors and hero image."""
    def __init__(self, page_width, page_height, left_margin, top_margin, bottom_margin,
                 brand_name, tagline, domain, niche, gen_date,
                 color_primary, color_secondary, color_accent,
                 hero_image_path=None):
        Flowable.__init__(self)
        self.page_width = page_width
        self.page_height = page_height
        self.left_margin = left_margin
        self.top_margin = top_margin
        self.bottom_margin = bottom_margin
        self.brand_name = brand_name
        self.tagline = tagline
        self.domain = domain
        self.niche = niche
        self.gen_date = gen_date
        self.color_primary = color_primary
        self.color_secondary = color_secondary
        self.color_accent = color_accent
        self.hero_image_path = hero_image_path
        # Must fit exactly within the SimpleDocTemplate frame (12pt internal reduction)
        self.width = page_width - 2 * left_margin - 12
        self.height = page_height - top_margin - bottom_margin - 12

    def _lerp_color(self, c1, c2, t):
        return colors.Color(
            c1.red + (c2.red - c1.red) * t,
            c1.green + (c2.green - c1.green) * t,
            c1.blue + (c2.blue - c1.blue) * t,
        )

    def draw(self):
        c = self.canv
        c.saveState()
        c.translate(-self.left_margin, -self.bottom_margin)

        pw = self.page_width
        ph = self.page_height
        dark_bg = colors.HexColor("#060B14")
        mid_bg = colors.HexColor("#0A1220")
        gold = self.color_accent

        # Full dark background
        c.setFillColor(dark_bg)
        c.rect(0, 0, pw, ph, fill=True, stroke=False)

        # Upper two-thirds: gradient from primary color to dark
        upper_h = ph * 0.62
        steps = 80
        for i in range(steps):
            t = i / steps
            col = self._lerp_color(self.color_primary, dark_bg, t ** 0.6)
            c.setFillColor(colors.Color(col.red, col.green, col.blue, 0.18 + (1 - t) * 0.22))
            y = ph - upper_h + upper_h * (1 - t)
            h = upper_h / steps + 1
            c.rect(0, y, pw, h, fill=True, stroke=False)

        # Hero image if available — upper portion
        if self.hero_image_path and os.path.exists(self.hero_image_path):
            try:
                img_y = ph * 0.42
                img_h = ph * 0.58
                c.drawImage(self.hero_image_path, 0, img_y, pw, img_h,
                            preserveAspectRatio=True, anchor='c', mask='auto')
                # Dark gradient overlay from bottom of image upward
                for i in range(40):
                    t = i / 40
                    c.setFillColor(colors.Color(dark_bg.red, dark_bg.green, dark_bg.blue, 1 - t * 0.7))
                    band_h = img_h * 0.45 / 40
                    c.rect(0, img_y + band_h * i, pw, band_h + 1, fill=True, stroke=False)
            except Exception:
                pass

        # Left accent stripe (brand primary, luxury hardcover feel)
        c.setFillColor(self.color_primary)
        c.rect(0, 0, 5, ph, fill=True, stroke=False)

        # Bottom panel: slightly lighter dark band for text legibility
        panel_h = ph * 0.42
        c.setFillColor(colors.Color(dark_bg.red, dark_bg.green, dark_bg.blue, 0.92))
        c.rect(0, 0, pw, panel_h, fill=True, stroke=False)

        # Gold accent line above text area
        line_y = panel_h + 1
        c.setStrokeColor(gold)
        c.setLineWidth(1.5)
        c.line(0.75 * inch, line_y, pw - 0.75 * inch, line_y)

        # ── TEXT BLOCK ──
        text_start_y = panel_h - 0.55 * inch

        # Brand name
        brand_display = self.brand_name[:42] if len(self.brand_name) > 42 else self.brand_name
        c.setFillColor(colors.HexColor("#FFFFFF"))
        c.setFont(HEADING_BOLD, 40)
        c.drawString(0.85 * inch, text_start_y, brand_display)

        # Tagline
        if self.tagline:
            tag_display = f'"{self.tagline[:72]}"' if len(self.tagline) <= 72 else f'"{self.tagline[:69]}..."'
            c.setFillColor(colors.HexColor("#A5B4FC"))
            c.setFont(HEADING_REG, 13)
            c.drawString(0.85 * inch, text_start_y - 0.42 * inch, tag_display)

        # Short divider rule in gold
        c.setStrokeColor(gold)
        c.setLineWidth(1.5)
        c.line(0.85 * inch, text_start_y - 0.65 * inch,
               0.85 * inch + 2.5 * inch, text_start_y - 0.65 * inch)

        # Domain + niche metadata
        meta = self.domain
        if self.niche:
            meta += f"   ·   {self.niche}"
        c.setFillColor(colors.HexColor("#6B7280"))
        c.setFont(BODY_SANS, 9)
        c.drawString(0.85 * inch, text_start_y - 0.95 * inch, meta)

        # ── BADGE: COMPLETE BUSINESS PACKAGE ──
        badge_w = 2.0 * inch
        badge_h = 0.28 * inch
        badge_x = pw - badge_w - 0.75 * inch
        badge_y = 0.75 * inch
        c.setFillColor(gold)
        c.roundRect(badge_x, badge_y, badge_w, badge_h, 3, fill=True, stroke=False)
        c.setFillColor(colors.HexColor("#000000"))
        c.setFont(BODY_SANS_BOLD, 7)
        c.drawCentredString(badge_x + badge_w / 2, badge_y + 0.09 * inch,
                            "COMPLETE BUSINESS PACKAGE")

        # ── Tiny "CONFIDENTIAL — PREPARED BY AURA" footer ──
        c.setFillColor(colors.HexColor("#374151"))
        c.setFont(BODY_SANS, 7.5)
        c.drawString(0.85 * inch, 0.35 * inch,
                     f"Prepared by Aura  ·  {self.gen_date}  ·  Confidential")

        c.restoreState()


class ChapterBanner(Flowable):
    """Full-width solid chapter banner — luxury feel, replaces thin gradient bar."""
    def __init__(self, chapter_num, title, accent_color, icon=None):
        Flowable.__init__(self)
        self.chapter_num = chapter_num
        self.title = title
        self.accent_color = accent_color
        self.icon = icon
        self.width = letter[0] - 1.5 * inch
        self.height = 0.72 * inch

    def draw(self):
        c = self.canv
        c.saveState()

        # Shadow effect (thin darker band behind)
        shadow = colors.Color(0, 0, 0, 0.25)
        c.setFillColor(shadow)
        c.roundRect(2, -2, self.width, self.height, 6, fill=True, stroke=False)

        # Main background band
        c.setFillColor(self.accent_color)
        c.roundRect(0, 0, self.width, self.height, 6, fill=True, stroke=False)

        # Subtle right-side gradient fade to darker
        dark_accent = colors.Color(
            self.accent_color.red * 0.65,
            self.accent_color.green * 0.65,
            self.accent_color.blue * 0.65,
        )
        steps = 30
        fade_w = self.width * 0.45
        for i in range(steps):
            t = i / steps
            col = colors.Color(
                self.accent_color.red + (dark_accent.red - self.accent_color.red) * t,
                self.accent_color.green + (dark_accent.green - self.accent_color.green) * t,
                self.accent_color.blue + (dark_accent.blue - self.accent_color.blue) * t,
            )
            c.setFillColor(col)
            x = self.width - fade_w + fade_w * t / steps
            c.roundRect(x, 0, fade_w / steps + 2, self.height, 0, fill=True, stroke=False)

        # Chapter number: large, translucent, decorative
        c.setFillColor(colors.Color(0, 0, 0, 0.18))
        c.setFont(HEADING_BOLD, 52)
        num_str = str(self.chapter_num).zfill(2)
        c.drawRightString(self.width - 0.15 * inch, -0.1 * inch, num_str)

        # Chapter title in white
        c.setFillColor(colors.HexColor("#FFFFFF"))
        c.setFont(HEADING_BOLD, 15)
        c.drawString(0.22 * inch, 0.24 * inch, _safe_text(self.title))

        c.restoreState()


class PageNumCanvas(canvas.Canvas):
    def __init__(self, *args, **kwargs):
        self._brand_name = kwargs.pop('brand_name', 'Aura')
        self._domain = kwargs.pop('domain', '')
        canvas.Canvas.__init__(self, *args, **kwargs)
        self._saved_page_states = []

    def showPage(self):
        self._saved_page_states.append(dict(self.__dict__))
        self._startPage()

    def save(self):
        num_pages = len(self._saved_page_states)
        for state in self._saved_page_states:
            self.__dict__.update(state)
            self._draw_page_number(num_pages)
            canvas.Canvas.showPage(self)
        canvas.Canvas.save(self)

    def _draw_page_number(self, page_count):
        page_num = self._pageNumber
        if page_num <= 1:
            return
        self.setStrokeColor(colors.HexColor("#1E2D45"))
        self.setLineWidth(0.5)
        self.line(0.75 * inch, 0.55 * inch, letter[0] - 0.75 * inch, 0.55 * inch)
        self.setFont(BODY_SANS, 7.5)
        self.setFillColor(colors.HexColor("#6B7280"))
        self.drawString(0.75 * inch, 0.38 * inch, f"{self._brand_name}  ·  {self._domain}")
        self.setFillColor(colors.HexColor("#9CA3AF"))
        self.drawRightString(
            letter[0] - 0.75 * inch,
            0.38 * inch,
            f"Page {page_num} of {page_count}  ·  Confidential"
        )


def _build_styles():
    styles = getSampleStyleSheet()

    styles.add(ParagraphStyle(
        name='CoverTitle',
        fontName=HEADING_BOLD,
        fontSize=34,
        textColor=colors.HexColor("#FFFFFF"),
        alignment=TA_CENTER,
        spaceAfter=8,
        leading=40,
    ))
    styles.add(ParagraphStyle(
        name='CoverTagline',
        fontName=HEADING_REG,
        fontSize=14,
        textColor=colors.HexColor("#A5B4FC"),
        alignment=TA_CENTER,
        spaceAfter=6,
        leading=18,
    ))
    styles.add(ParagraphStyle(
        name='CoverDomain',
        fontName=BODY_SANS,
        fontSize=10,
        textColor=TEXT_MUTED,
        alignment=TA_CENTER,
        spaceAfter=30,
    ))
    styles.add(ParagraphStyle(
        name='CoverMeta',
        fontName=BODY_SANS,
        fontSize=8.5,
        textColor=TEXT_GRAY,
        alignment=TA_CENTER,
        spaceAfter=4,
    ))
    styles.add(ParagraphStyle(
        name='ChapterTitle',
        fontName=HEADING_BOLD,
        fontSize=22,
        textColor=BRAND_PURPLE_DARK,
        spaceBefore=0,
        spaceAfter=6,
        leading=26,
    ))
    styles.add(ParagraphStyle(
        name='SectionHeading',
        fontName=HEADING_BOLD,
        fontSize=15,
        textColor=BRAND_PURPLE_DARK,
        spaceBefore=16,
        spaceAfter=6,
        leading=19,
    ))
    styles.add(ParagraphStyle(
        name='SubHeading',
        fontName=HEADING_BOLD,
        fontSize=12,
        textColor=BRAND_VIOLET,
        spaceBefore=10,
        spaceAfter=4,
        leading=15,
    ))
    styles.add(ParagraphStyle(
        name='SubHeading3',
        fontName=BODY_SANS_BOLD,
        fontSize=11,
        textColor=TEXT_DARK,
        spaceBefore=8,
        spaceAfter=3,
        leading=14,
    ))
    styles.add(ParagraphStyle(
        name='BodyText2',
        fontName=BODY_SANS,
        fontSize=10,
        textColor=TEXT_BODY,
        leading=14.5,
        spaceAfter=6,
        alignment=TA_JUSTIFY,
    ))
    styles.add(ParagraphStyle(
        name='BodyTextSales',
        fontName=BODY_SANS,
        fontSize=10.5,
        textColor=TEXT_BODY,
        leading=15.5,
        spaceAfter=8,
        alignment=TA_JUSTIFY,
    ))
    styles.add(ParagraphStyle(
        name='SmallLabel',
        fontName=BODY_SANS_BOLD,
        fontSize=7.5,
        textColor=TEXT_MUTED,
        spaceBefore=4,
        spaceAfter=2,
        textTransform='uppercase',
    ))
    styles.add(ParagraphStyle(
        name='BulletItem',
        fontName=BODY_SANS,
        fontSize=10,
        textColor=TEXT_BODY,
        leftIndent=20,
        bulletIndent=8,
        spaceAfter=3,
        leading=14.5,
    ))
    styles.add(ParagraphStyle(
        name='MetaText',
        fontName=BODY_SANS,
        fontSize=8,
        textColor=TEXT_GRAY,
        alignment=TA_RIGHT,
    ))
    styles.add(ParagraphStyle(
        name='ScreenshotCaption',
        fontName=BODY_SANS,
        fontSize=8.5,
        textColor=TEXT_MUTED,
        alignment=TA_CENTER,
        spaceBefore=4,
        spaceAfter=10,
    ))
    styles.add(ParagraphStyle(
        name='BlockquoteText',
        fontName=HEADING_REG,
        fontSize=11,
        textColor=TEXT_MUTED,
        leftIndent=24,
        rightIndent=12,
        spaceBefore=6,
        spaceAfter=8,
        leading=16,
        borderLeftWidth=3,
        borderLeftColor=BRAND_PURPLE_LIGHT,
        borderPadding=8,
    ))
    styles.add(ParagraphStyle(
        name='DocTitle',
        fontName=HEADING_BOLD,
        fontSize=14,
        textColor=TEXT_DARK,
        spaceBefore=0,
        spaceAfter=4,
        leading=18,
    ))
    styles.add(ParagraphStyle(
        name='TierBadge',
        fontName=BODY_SANS_BOLD,
        fontSize=8,
        textColor=colors.white,
        alignment=TA_CENTER,
    ))
    styles.add(ParagraphStyle(
        name='TOCItem',
        fontName=BODY_SANS,
        fontSize=10,
        textColor=TEXT_BODY,
        leftIndent=16,
        spaceAfter=4,
        leading=14,
    ))
    styles.add(ParagraphStyle(
        name='TOCChapter',
        fontName=HEADING_BOLD,
        fontSize=11,
        textColor=BRAND_PURPLE_DARK,
        spaceBefore=10,
        spaceAfter=2,
        leading=14,
    ))
    return styles


def _safe_text(val):
    if val is None:
        return ""
    s = str(val)
    s = s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
    s = s.replace("\u2019", "'").replace("\u2018", "'")
    s = s.replace("\u201c", '"').replace("\u201d", '"')
    s = s.replace("\u2011", "-").replace("\u2013", "-").replace("\u2014", " - ")
    return s


def _color_swatch(hex_color, label, width=70, height=22):
    try:
        c = colors.HexColor(hex_color)
    except Exception:
        c = colors.gray
    d = Drawing(width + 100, height + 6)
    d.add(Rect(0, 3, width, height, fillColor=c, strokeColor=BORDER_LIGHT, strokeWidth=0.5, rx=3, ry=3))
    d.add(String(width + 8, 8, f"{label}: {hex_color}", fontName="Helvetica", fontSize=9, fillColor=TEXT_BODY))
    return d


def _section_divider(width=None):
    w = width or (letter[0] - 1.5 * inch)
    return HRFlowable(width="100%", thickness=0.5, color=BORDER_LIGHT, spaceAfter=8, spaceBefore=4)


def _chapter_header(title, styles, accent_color=None, chapter_num=None):
    accent = accent_color or BRAND_PURPLE
    elements = []
    num = chapter_num or 0
    elements.append(ChapterBanner(num, title, accent))
    elements.append(Spacer(1, 16))
    return elements


def _markdown_to_reportlab(md_text, styles, body_style_name='BodyTextSales'):
    elements = []
    if not md_text:
        return elements

    md_text = md_text.strip()
    if md_text.startswith("```markdown"):
        md_text = md_text[len("```markdown"):].strip()
    if md_text.startswith("```md"):
        md_text = md_text[len("```md"):].strip()
    if md_text.startswith("```"):
        md_text = md_text[3:].strip()
    if md_text.endswith("```"):
        md_text = md_text[:-3].strip()

    lines = md_text.split("\n")
    current_paragraph = []
    in_list = False
    in_blockquote = False
    blockquote_lines = []

    def flush_paragraph():
        nonlocal current_paragraph
        if current_paragraph:
            text = " ".join(current_paragraph).strip()
            if text:
                text = _apply_inline_formatting(_safe_text(text))
                elements.append(Paragraph(text, styles[body_style_name]))
            current_paragraph = []

    def flush_blockquote():
        nonlocal blockquote_lines, in_blockquote
        if blockquote_lines:
            text = " ".join(blockquote_lines).strip()
            if text:
                text = _apply_inline_formatting(_safe_text(text))
                elements.append(Paragraph(text, styles['BlockquoteText']))
            blockquote_lines = []
        in_blockquote = False

    for line in lines:
        stripped = line.strip()

        if not stripped:
            flush_paragraph()
            if in_blockquote:
                flush_blockquote()
            in_list = False
            continue

        if stripped.startswith(">"):
            flush_paragraph()
            bq_text = stripped.lstrip(">").strip()
            blockquote_lines.append(bq_text)
            in_blockquote = True
            continue

        if in_blockquote and not stripped.startswith(">"):
            flush_blockquote()

        heading_match = re.match(r'^(#{1,4})\s+(.*)', stripped)
        if heading_match:
            flush_paragraph()
            level = len(heading_match.group(1))
            heading_text = _safe_text(heading_match.group(2).strip())
            heading_text = re.sub(r'\*\*(.*?)\*\*', r'\1', heading_text)
            heading_text = re.sub(r'\*(.*?)\*', r'\1', heading_text)
            if level == 1:
                elements.append(Spacer(1, 8))
                elements.append(Paragraph(heading_text, styles['SectionHeading']))
                elements.append(HRFlowable(width="100%", thickness=1, color=BRAND_PURPLE, spaceAfter=8))
            elif level == 2:
                elements.append(Spacer(1, 6))
                elements.append(Paragraph(heading_text, styles['SubHeading']))
            elif level == 3:
                elements.append(Paragraph(heading_text, styles['SubHeading3']))
            else:
                elements.append(Paragraph(f"<b>{heading_text}</b>", styles[body_style_name]))
            continue

        if stripped.startswith("---") or stripped.startswith("***") or stripped.startswith("___"):
            flush_paragraph()
            elements.append(_section_divider())
            continue

        bullet_match = re.match(r'^[-*+]\s+(.*)', stripped)
        number_match = re.match(r'^\d+[.)]\s+(.*)', stripped)
        if bullet_match or number_match:
            flush_paragraph()
            item_text = (bullet_match or number_match).group(1).strip()
            item_text = _apply_inline_formatting(_safe_text(item_text))
            elements.append(Paragraph(f"&bull; {item_text}", styles['BulletItem']))
            in_list = True
            continue

        current_paragraph.append(stripped)

    flush_paragraph()
    if in_blockquote:
        flush_blockquote()

    return elements


def _apply_inline_formatting(text):
    text = re.sub(r'\*\*\*(.+?)\*\*\*', r'<b><i>\1</i></b>', text)
    text = re.sub(r'\*\*(.+?)\*\*', r'<b>\1</b>', text)
    text = re.sub(r'(?<!\*)\*([^*]+?)\*(?!\*)', r'<i>\1</i>', text)
    text = re.sub(r'__(.+?)__', r'<b>\1</b>', text)
    text = re.sub(r'(?<!_)_([^_]+?)_(?!_)', r'<i>\1</i>', text)
    text = re.sub(r'`([^`]+?)`', r'<font name="Courier" size="9">\1</font>', text)
    text = re.sub(r'\[([^\]]+)\]\([^\)]+\)', r'<u>\1</u>', text)
    text = _fix_tag_nesting(text)
    return text


def _fix_tag_nesting(text):
    tag_stack = []
    result = []
    i = 0
    while i < len(text):
        if text[i] == '<':
            end = text.find('>', i)
            if end == -1:
                result.append(text[i])
                i += 1
                continue
            tag_content = text[i+1:end]
            full_tag = text[i:end+1]
            if tag_content.startswith('/'):
                close_tag = tag_content[1:].split()[0].lower()
                if tag_stack and tag_stack[-1] == close_tag:
                    tag_stack.pop()
                    result.append(full_tag)
                elif close_tag in tag_stack:
                    tags_to_close = []
                    while tag_stack and tag_stack[-1] != close_tag:
                        tags_to_close.append(tag_stack.pop())
                    if tag_stack:
                        tag_stack.pop()
                    for t in tags_to_close:
                        result.append(f'</{t}>')
                    result.append(full_tag)
                    for t in reversed(tags_to_close):
                        result.append(f'<{t}>')
                        tag_stack.append(t)
                else:
                    pass
            else:
                tag_name = tag_content.split()[0].lower()
                if tag_name not in ('br', 'hr', 'img', 'para'):
                    tag_stack.append(tag_name)
                result.append(full_tag)
            i = end + 1
        else:
            result.append(text[i])
            i += 1
    while tag_stack:
        result.append(f'</{tag_stack.pop()}>')
    return ''.join(result)


def _extract_sales_letter_md(package):
    raw = package.sales_letter
    if not raw:
        return None

    if isinstance(raw, dict):
        parsed = raw
    elif isinstance(raw, str):
        stripped = raw.strip()
        if stripped.startswith("{"):
            try:
                parsed = json.loads(stripped)
            except (json.JSONDecodeError, ValueError):
                return raw if len(stripped) > 50 else None
        else:
            return raw if len(stripped) > 50 else None
    else:
        return None

    if isinstance(parsed, dict):
        sc = parsed.get("site_copy", {})
        if isinstance(sc, dict):
            res = sc.get("resources", {})
            if isinstance(res, dict):
                for k in ["sales_letter_md", "sales_letter_markdown", "sales_letter"]:
                    v = res.get(k)
                    if isinstance(v, str) and len(v.strip()) > 50:
                        return v

        for k in ["content_markdown", "sales_letter_md", "sales_letter_markdown", "sales_letter", "content", "markdown", "letter", "body", "text"]:
            v = parsed.get(k)
            if isinstance(v, str) and len(v.strip()) > 50:
                return v

        longest = ""
        for v in parsed.values():
            if isinstance(v, str) and len(v) > len(longest):
                longest = v
        if len(longest) > 100:
            return longest

    return None


def generate_package_pdf(package, screenshots: Optional[list] = None, include_biz_docs: bool = True) -> bytes:
    buffer = io.BytesIO()
    doc = SimpleDocTemplate(
        buffer,
        pagesize=letter,
        rightMargin=0.75 * inch,
        leftMargin=0.75 * inch,
        topMargin=0.6 * inch,
        bottomMargin=0.7 * inch,
    )
    styles = _build_styles()
    story = []

    brand = package.brand or {}
    site_copy = package.site_copy or {}
    domain = package.domain_name or "unknown"
    niche = package.chosen_niche or ""
    hero_url = package.hero_image_url

    brand_options = brand.get("options", [])
    recommended_idx = brand.get("recommended", 0)
    chosen_brand = brand_options[recommended_idx] if brand_options and recommended_idx < len(brand_options) else {}
    brand_name = chosen_brand.get("name", domain)
    tagline = chosen_brand.get("tagline", "")
    color_primary = brand.get("color_primary", "#6366f1")
    color_secondary = brand.get("color_secondary", "#8b5cf6")
    color_accent = brand.get("color_accent", "#f59e0b")
    industry_context = brand.get("industry_context", "")

    gen_date = datetime.datetime.utcnow().strftime("%B %d, %Y")

    business_box = package.business_box or {}
    business_docs = business_box.get("documents", {}) if isinstance(business_box, dict) else {}
    if not isinstance(business_docs, dict):
        business_docs = {}

    sales_letter_md = _extract_sales_letter_md(package)

    # ── Resolve brand colors as ReportLab Color objects ──
    def _hex_to_rl(h, fallback="#6366f1"):
        try:
            return colors.HexColor(h if h and h.startswith("#") else fallback)
        except Exception:
            return colors.HexColor(fallback)

    rl_primary = _hex_to_rl(color_primary)
    rl_secondary = _hex_to_rl(color_secondary, "#8b5cf6")
    rl_accent = _hex_to_rl(color_accent, "#f59e0b")

    # ── Resolve local hero image path ──
    hero_local_path = None
    if hero_url:
        candidate = hero_url.lstrip("/")
        static_path = os.path.join(os.path.dirname(__file__), "..", "static",
                                   candidate.replace("static/", "", 1))
        static_path = os.path.normpath(static_path)
        if os.path.exists(static_path):
            hero_local_path = static_path

    # ── LEGENDARY FULL-BLEED COVER PAGE ──
    lm = 0.75 * inch
    tm = 0.6 * inch
    bm = 0.7 * inch
    pw, ph = letter
    story.append(FullBleedCover(
        page_width=pw, page_height=ph,
        left_margin=lm, top_margin=tm, bottom_margin=bm,
        brand_name=brand_name,
        tagline=tagline,
        domain=domain,
        niche=niche,
        gen_date=gen_date,
        color_primary=rl_primary,
        color_secondary=rl_secondary,
        color_accent=rl_accent,
        hero_image_path=hero_local_path,
    ))

    # ── TABLE OF CONTENTS PAGE ──
    story.append(PageBreak())

    chapter_num = 1
    toc_items = []
    toc_items.append((chapter_num, "Brand Identity & Color Palette"))
    chapter_num += 1
    if industry_context:
        toc_items.append((chapter_num, "Industry Context"))
        chapter_num += 1
    section_count = len([k for k, v in site_copy.items() if v])
    toc_items.append((chapter_num, f"Site Content  ({section_count} sections)"))
    chapter_num += 1
    if sales_letter_md:
        toc_items.append((chapter_num, "Marketplace Sales Letter"))
        chapter_num += 1
    if business_docs:
        toc_items.append((chapter_num, f"Force Multiplier Business Documents  ({len(business_docs)} docs)"))
        chapter_num += 1
    if screenshots:
        toc_items.append((chapter_num, f"Site Preview Screenshots  ({len(screenshots)} pages)"))

    story.append(Spacer(1, 0.4 * inch))
    story.append(Paragraph("Contents", styles['ChapterTitle']))
    story.append(HRFlowable(width="100%", thickness=1.5, color=rl_primary, spaceAfter=14))

    for num, label in toc_items:
        toc_row = Table(
            [[
                Paragraph(str(num), ParagraphStyle('TN', fontName=HEADING_BOLD, fontSize=10,
                          textColor=rl_primary, alignment=TA_CENTER)),
                Paragraph(f"&nbsp;&nbsp;{label}", styles['TOCItem']),
            ]],
            colWidths=[0.35 * inch, None],
            hAlign='LEFT',
        )
        toc_row.setStyle(TableStyle([
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
            ('LINEBELOW', (0, 0), (-1, 0), 0.25, colors.HexColor("#E2E8F0")),
            ('TOPPADDING', (0, 0), (-1, -1), 5),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 5),
        ]))
        story.append(toc_row)

    story.append(PageBreak())

    chapter_num = 1
    story.extend(_chapter_header("Brand Identity", styles, rl_primary, chapter_num))
    chapter_num += 1

    if brand_options:
        for i, opt in enumerate(brand_options):
            prefix = "&#9733; " if i == recommended_idx else ""
            rec_tag = " (Recommended)" if i == recommended_idx else ""
            story.append(Paragraph(f"{prefix}Option {i+1}: {_safe_text(opt.get('name', ''))}{rec_tag}", styles['SubHeading']))
            if opt.get('tagline'):
                story.append(Paragraph(f'"{_safe_text(opt["tagline"])}"', ParagraphStyle(
                    'TaglineQ', fontName='Helvetica-Oblique', fontSize=10,
                    textColor=TEXT_MUTED, leftIndent=16, spaceAfter=8, leading=14
                )))
            if opt.get('description'):
                story.append(Paragraph(_safe_text(opt['description']), styles['BodyText2']))
        story.append(Spacer(1, 10))

    story.append(Paragraph("Color Palette", styles['SubHeading']))
    story.append(Spacer(1, 4))
    story.append(_color_swatch(color_primary, "Primary"))
    story.append(Spacer(1, 4))
    story.append(_color_swatch(color_secondary, "Secondary"))
    story.append(Spacer(1, 4))
    story.append(_color_swatch(color_accent, "Accent"))
    story.append(Spacer(1, 12))

    if industry_context:
        story.append(PageBreak())
        story.extend(_chapter_header("Industry Context", styles, rl_secondary, chapter_num))
        chapter_num += 1
        for para in industry_context.split("\n\n"):
            para = para.strip()
            if para:
                story.append(Paragraph(_safe_text(para), styles['BodyText2']))
                story.append(Spacer(1, 4))

    story.append(PageBreak())
    story.extend(_chapter_header("Site Content", styles, rl_primary, chapter_num))
    chapter_num += 1

    hero_fields = ["headline", "subheadline", "hero_body", "cta_text", "cta_secondary_text"]
    hero_data = {k: site_copy.get(k) for k in hero_fields if site_copy.get(k)}
    if hero_data:
        story.append(Paragraph("Hero Section", styles['SubHeading']))
        for field, value in hero_data.items():
            label = field.replace("_", " ").title()
            story.append(Paragraph(f"<b>{label}:</b>", styles['SmallLabel']))
            story.append(Paragraph(_safe_text(value), styles['BodyText2']))
        story.append(Spacer(1, 10))

    simple_text_sections = {
        "about_title": "About Title",
        "about": "About / Our Story",
        "mission_statement": "Mission Statement",
        "problem_title": "Problem Title",
        "problem_body": "Problem Statement",
        "solution_title": "Solution Title",
        "solution_body": "Solution",
        "guarantee_title": "Guarantee Title",
        "guarantee_body": "Guarantee",
        "newsletter_title": "Newsletter Title",
        "newsletter_body": "Newsletter Description",
        "offer": "Offer Details",
    }

    for key, label in simple_text_sections.items():
        val = site_copy.get(key)
        if val and isinstance(val, str):
            story.append(Paragraph(label, styles['SubHeading']))
            story.append(Paragraph(_safe_text(val), styles['BodyText2']))
            story.append(Spacer(1, 6))

    list_sections = {
        "problem_points": "Pain Points",
        "solution_points": "Key Benefits",
        "benefits": "Benefits",
        "how_it_works_steps": "How It Works",
    }
    for key, label in list_sections.items():
        val = site_copy.get(key)
        if val and isinstance(val, list):
            story.append(Paragraph(label, styles['SubHeading']))
            for item in val:
                if isinstance(item, str):
                    story.append(Paragraph(f"&bull; {_safe_text(item)}", styles['BulletItem']))
                elif isinstance(item, dict):
                    title = item.get("title") or item.get("step") or item.get("name", "")
                    desc = item.get("description") or item.get("body") or item.get("detail", "")
                    story.append(Paragraph(f"&bull; <b>{_safe_text(title)}</b>", styles['BulletItem']))
                    if desc:
                        story.append(Paragraph(_safe_text(desc), ParagraphStyle(
                            'BulletDesc2', parent=styles['BodyText2'], leftIndent=30, fontSize=9
                        )))
            story.append(Spacer(1, 8))

    features = site_copy.get("features")
    if features and isinstance(features, list):
        story.append(PageBreak())
        story.append(Paragraph("Features", styles['SectionHeading']))
        story.append(HRFlowable(width="100%", thickness=0.5, color=BRAND_PURPLE, spaceAfter=10))
        for feat in features:
            if isinstance(feat, dict):
                title = feat.get("title") or feat.get("name", "")
                desc = feat.get("description") or feat.get("body", "")
                feat_block = [
                    Paragraph(f"&#9670; {_safe_text(title)}", styles['SubHeading3']),
                ]
                if desc:
                    feat_block.append(Paragraph(_safe_text(desc), styles['BodyText2']))
                feat_block.append(Spacer(1, 4))
                story.append(KeepTogether(feat_block))
            elif isinstance(feat, str):
                story.append(Paragraph(f"&bull; {_safe_text(feat)}", styles['BulletItem']))
        story.append(Spacer(1, 8))

    testimonials = site_copy.get("testimonials")
    if testimonials and isinstance(testimonials, list):
        story.append(Paragraph("Testimonials", styles['SubHeading']))
        for t in testimonials:
            if isinstance(t, dict):
                quote = t.get("quote") or t.get("text", "")
                author = t.get("author") or t.get("name", "")
                role = t.get("role") or t.get("title", "")
                t_block = []
                t_block.append(Paragraph(f'"{_safe_text(quote)}"', styles['BlockquoteText']))
                attribution = f"&mdash; {_safe_text(author)}"
                if role:
                    attribution += f", <i>{_safe_text(role)}</i>"
                t_block.append(Paragraph(attribution, ParagraphStyle(
                    'TestAttr', fontName='Helvetica', fontSize=9,
                    textColor=TEXT_MUTED, leftIndent=24, spaceAfter=10
                )))
                story.append(KeepTogether(t_block))
        story.append(Spacer(1, 8))

    faq_items = site_copy.get("faq_items")
    if faq_items and isinstance(faq_items, list):
        story.append(Paragraph("FAQ", styles['SubHeading']))
        for faq in faq_items:
            if isinstance(faq, dict):
                q = faq.get("question", "")
                a = faq.get("answer", "")
                faq_block = [
                    Paragraph(f"<b>Q: {_safe_text(q)}</b>", ParagraphStyle(
                        'FAQQ', fontName='Helvetica-Bold', fontSize=10,
                        textColor=TEXT_DARK, spaceBefore=6, spaceAfter=2
                    )),
                    Paragraph(f"{_safe_text(a)}", ParagraphStyle(
                        'FAQA', fontName='Helvetica', fontSize=10,
                        textColor=TEXT_BODY, leftIndent=16, spaceAfter=8, leading=14
                    )),
                ]
                story.append(KeepTogether(faq_block))
        story.append(Spacer(1, 8))

    pricing = site_copy.get("pricing") or site_copy.get("pricing_plans")
    if pricing and isinstance(pricing, list):
        story.append(Paragraph("Pricing", styles['SubHeading']))
        for plan in pricing:
            if isinstance(plan, dict):
                name = plan.get("name") or plan.get("tier", "")
                price = plan.get("price", "")
                desc = plan.get("description", "")
                plan_block = [
                    Paragraph(f"&#9670; {_safe_text(name)} &mdash; {_safe_text(price)}", ParagraphStyle(
                        'PriceT', fontName='Helvetica-Bold', fontSize=10.5,
                        textColor=BRAND_PURPLE, spaceAfter=2
                    )),
                ]
                if desc:
                    plan_block.append(Paragraph(_safe_text(desc), ParagraphStyle(
                        'PriceD', fontName='Helvetica', fontSize=9,
                        textColor=TEXT_BODY, leftIndent=16, spaceAfter=4, leading=12
                    )))
                plan_features = plan.get("features", [])
                for pf in plan_features:
                    plan_block.append(Paragraph(f"  &bull; {_safe_text(pf)}", ParagraphStyle(
                        'PriceF', fontName='Helvetica', fontSize=9,
                        textColor=TEXT_MUTED, leftIndent=30, spaceAfter=1
                    )))
                plan_block.append(Spacer(1, 6))
                story.append(KeepTogether(plan_block))

    stats = site_copy.get("stats") or site_copy.get("statistics")
    if stats and isinstance(stats, list):
        story.append(Paragraph("Statistics", styles['SubHeading']))
        for stat in stats:
            if isinstance(stat, dict):
                val = stat.get("value") or stat.get("number", "")
                label = stat.get("label") or stat.get("description", "")
                story.append(Paragraph(f"<b>{_safe_text(val)}</b> &mdash; {_safe_text(label)}", styles['BulletItem']))
        story.append(Spacer(1, 8))

    remaining_keys = set(site_copy.keys()) - set(hero_fields) - set(simple_text_sections.keys()) - set(list_sections.keys()) - {
        "features", "testimonials", "faq_items", "pricing", "pricing_plans", "stats", "statistics", "resources"
    }
    for key in sorted(remaining_keys):
        val = site_copy[key]
        if val is None:
            continue
        label = SECTION_LABELS.get(key, key.replace("_", " ").title())
        if isinstance(val, str) and len(val) > 5:
            story.append(Paragraph(label, styles['SubHeading']))
            story.append(Paragraph(_safe_text(val), styles['BodyText2']))
            story.append(Spacer(1, 6))
        elif isinstance(val, list) and len(val) > 0:
            story.append(Paragraph(label, styles['SubHeading']))
            for item in val:
                if isinstance(item, str):
                    story.append(Paragraph(f"&bull; {_safe_text(item)}", styles['BulletItem']))
                elif isinstance(item, dict):
                    t = item.get("title") or item.get("name") or item.get("step", "")
                    d = item.get("description") or item.get("body") or item.get("detail", "")
                    if t:
                        story.append(Paragraph(f"&bull; <b>{_safe_text(t)}</b>", styles['BulletItem']))
                    if d:
                        story.append(Paragraph(_safe_text(d), ParagraphStyle(
                            'RmDesc', parent=styles['BodyText2'], leftIndent=30, fontSize=9
                        )))
            story.append(Spacer(1, 8))

    if sales_letter_md:
        story.append(PageBreak())
        story.extend(_chapter_header("Marketplace Sales Letter", styles, BRAND_AMBER, chapter_num))
        chapter_num += 1
        sales_elements = _markdown_to_reportlab(sales_letter_md, styles, 'BodyTextSales')
        story.extend(sales_elements)

    if include_biz_docs and business_docs:
        story.append(PageBreak())
        story.extend(_chapter_header("Force Multiplier Business Documents", styles, BRAND_EMERALD, chapter_num))
        chapter_num += 1

        story.append(Paragraph(
            f"This package includes <b>{len(business_docs)}</b> professionally generated business documents "
            f"covering legal, operational, marketing, and strategic needs.",
            styles['BodyText2']
        ))
        story.append(Spacer(1, 12))

        tiers_found = {}
        try:
            from app.services.business_docs import DOC_REGISTRY, TIERS
        except ImportError:
            DOC_REGISTRY = {}
            TIERS = {}

        for doc_key, doc_data in business_docs.items():
            if isinstance(doc_data, dict):
                tier = doc_data.get("tier", "")
            elif doc_key in DOC_REGISTRY:
                tier = DOC_REGISTRY[doc_key].get("tier", "general")
            else:
                tier = "general"
            if tier not in tiers_found:
                tiers_found[tier] = []
            tiers_found[tier].append((doc_key, doc_data))

        doc_index_items = []
        for tier_key in ["business_docs", "legal", "contracts", "marketing", "operations", "calculators", "general"]:
            if tier_key not in tiers_found:
                continue
            tier_label = DOC_TIER_LABELS.get(tier_key, tier_key.replace("_", " ").title())
            tier_color = DOC_TIER_COLORS.get(tier_key, BRAND_PURPLE)
            doc_index_items.append(Paragraph(
                f"<b>{tier_label}</b> ({len(tiers_found[tier_key])} documents)",
                ParagraphStyle('TierIdx', fontName='Helvetica-Bold', fontSize=10,
                               textColor=tier_color, spaceBefore=6, spaceAfter=2)
            ))
            for doc_key, doc_data in tiers_found[tier_key]:
                if isinstance(doc_data, dict):
                    doc_label = doc_data.get("label", doc_key.replace("_", " ").title())
                elif doc_key in DOC_REGISTRY:
                    doc_label = DOC_REGISTRY[doc_key].get("label", doc_key.replace("_", " ").title())
                else:
                    doc_label = doc_key.replace("_", " ").title()
                doc_index_items.append(Paragraph(f"&bull; {_safe_text(doc_label)}", styles['TOCItem']))

        story.extend(doc_index_items)
        story.append(Spacer(1, 8))

        for tier_key in ["business_docs", "legal", "contracts", "marketing", "operations", "calculators", "general"]:
            if tier_key not in tiers_found:
                continue

            tier_label = DOC_TIER_LABELS.get(tier_key, tier_key.replace("_", " ").title())
            tier_color = DOC_TIER_COLORS.get(tier_key, BRAND_PURPLE)

            for doc_key, doc_data in tiers_found[tier_key]:
                story.append(PageBreak())

                if isinstance(doc_data, dict):
                    doc_label = doc_data.get("label", doc_key.replace("_", " ").title())
                    doc_content = doc_data.get("content", "")
                elif isinstance(doc_data, str):
                    doc_label = DOC_REGISTRY.get(doc_key, {}).get("label", doc_key.replace("_", " ").title()) if DOC_REGISTRY else doc_key.replace("_", " ").title()
                    doc_content = doc_data
                else:
                    continue

                story.append(GradientRect(letter[0] - 1.5 * inch, 3, tier_color, BORDER_LIGHT))
                story.append(Spacer(1, 6))

                tier_badge_text = tier_label.upper()
                story.append(Paragraph(
                    f'<font color="{tier_color.hexval()}" size="8"><b>{tier_badge_text}</b></font>',
                    ParagraphStyle('TBadge', fontName='Helvetica-Bold', fontSize=8, spaceAfter=2)
                ))

                story.append(Paragraph(_safe_text(doc_label), styles['DocTitle']))
                story.append(HRFlowable(width="100%", thickness=1, color=tier_color, spaceAfter=10))

                if doc_content and isinstance(doc_content, str) and len(doc_content.strip()) > 10:
                    doc_elements = _markdown_to_reportlab(doc_content, styles, 'BodyText2')
                    story.extend(doc_elements)
                else:
                    story.append(Paragraph("<i>Document content not yet generated.</i>", styles['BodyText2']))

    if screenshots:
        story.append(PageBreak())
        story.extend(_chapter_header("Site Preview", styles, rl_secondary, chapter_num))

        usable_width = letter[0] - 1.5 * inch
        max_height = letter[1] - 2.0 * inch

        for i, screenshot_path in enumerate(screenshots):
            if not os.path.exists(screenshot_path):
                continue
            try:
                img = Image(screenshot_path)
                aspect = img.imageHeight / img.imageWidth if img.imageWidth > 0 else 1.0
                img_width = usable_width
                img_height = img_width * aspect
                if img_height > max_height:
                    img_height = max_height
                    img_width = img_height / aspect
                img.drawWidth = img_width
                img.drawHeight = img_height

                img_block = [
                    img,
                    Paragraph(f"Page {i+1} of {len(screenshots)}", styles['ScreenshotCaption']),
                ]
                story.append(KeepTogether(img_block))
                if i < len(screenshots) - 1:
                    story.append(PageBreak())
            except Exception as e:
                story.append(Paragraph(f"[Screenshot {i+1} could not be embedded: {str(e)}]", styles['BodyText2']))

    story.append(Spacer(1, 30))
    story.append(GradientRect(letter[0] - 1.5 * inch, 2, BRAND_PURPLE, BRAND_VIOLET))
    story.append(Spacer(1, 8))
    story.append(Paragraph(f"Generated by Aura  |  {gen_date}", ParagraphStyle(
        'Footer', fontName='Helvetica', fontSize=8, textColor=TEXT_GRAY, alignment=TA_CENTER
    )))
    story.append(Paragraph(f"{_safe_text(domain)}  |  {_safe_text(niche)}", ParagraphStyle(
        'Footer2', fontName='Helvetica', fontSize=7, textColor=TEXT_GRAY, alignment=TA_CENTER
    )))

    doc.build(
        story,
        canvasmaker=lambda *args, **kwargs: PageNumCanvas(
            *args, brand_name=brand_name, domain=domain, **kwargs
        )
    )
    return buffer.getvalue()


def generate_package_markdown(package) -> str:
    brand = package.brand or {}
    site_copy = package.site_copy or {}
    domain = package.domain_name or "unknown"
    niche = package.chosen_niche or ""

    sales_letter_md = _extract_sales_letter_md(package)

    brand_options = brand.get("options", [])
    recommended_idx = brand.get("recommended", 0)
    chosen_brand = brand_options[recommended_idx] if brand_options and recommended_idx < len(brand_options) else {}
    brand_name = chosen_brand.get("name", domain)
    tagline = chosen_brand.get("tagline", "")
    color_primary = brand.get("color_primary", "#6366f1")
    color_secondary = brand.get("color_secondary", "#8b5cf6")
    color_accent = brand.get("color_accent", "#f59e0b")
    industry_context = brand.get("industry_context", "")

    gen_date = datetime.datetime.utcnow().strftime("%B %d, %Y")

    lines = []
    lines.append(f"# {brand_name}")
    lines.append("")
    if tagline:
        lines.append(f"*{tagline}*")
        lines.append("")
    lines.append(f"**Domain:** {domain}  ")
    lines.append(f"**Niche:** {niche}  ")
    lines.append(f"**Generated:** {gen_date}  ")
    lines.append("")
    lines.append("---")
    lines.append("")

    lines.append("## Brand Identity")
    lines.append("")
    if brand_options:
        for i, opt in enumerate(brand_options):
            rec = " **(Recommended)**" if i == recommended_idx else ""
            lines.append(f"### Option {i+1}: {opt.get('name', '')}{rec}")
            if opt.get('tagline'):
                lines.append(f"> {opt['tagline']}")
            lines.append("")

    lines.append("### Color Palette")
    lines.append(f"- **Primary:** `{color_primary}`")
    lines.append(f"- **Secondary:** `{color_secondary}`")
    lines.append(f"- **Accent:** `{color_accent}`")
    lines.append("")

    if industry_context:
        lines.append("## Industry Context")
        lines.append("")
        lines.append(industry_context)
        lines.append("")

    lines.append("---")
    lines.append("")
    lines.append("## Site Content")
    lines.append("")

    hero_fields = {
        "headline": "Headline",
        "subheadline": "Subheadline",
        "hero_body": "Hero Body",
        "cta_text": "CTA Text",
        "cta_secondary_text": "Secondary CTA",
    }
    hero_data = {k: site_copy.get(k) for k in hero_fields if site_copy.get(k)}
    if hero_data:
        lines.append("### Hero Section")
        lines.append("")
        for key, label in hero_fields.items():
            val = site_copy.get(key)
            if val:
                lines.append(f"**{label}:** {val}")
                lines.append("")

    simple_text_sections = {
        "about_title": "About Title",
        "about": "About / Our Story",
        "mission_statement": "Mission Statement",
        "problem_title": "Problem Title",
        "problem_body": "Problem Statement",
        "solution_title": "Solution Title",
        "solution_body": "Solution",
        "guarantee_title": "Guarantee Title",
        "guarantee_body": "Guarantee",
        "newsletter_title": "Newsletter Title",
        "newsletter_body": "Newsletter Description",
        "offer": "Offer Details",
    }
    for key, label in simple_text_sections.items():
        val = site_copy.get(key)
        if val and isinstance(val, str):
            lines.append(f"### {label}")
            lines.append("")
            lines.append(val)
            lines.append("")

    list_sections = {
        "problem_points": "Pain Points",
        "solution_points": "Key Benefits",
        "benefits": "Benefits",
        "how_it_works_steps": "How It Works Steps",
    }
    for key, label in list_sections.items():
        val = site_copy.get(key)
        if val and isinstance(val, list):
            lines.append(f"### {label}")
            lines.append("")
            for item in val:
                if isinstance(item, str):
                    lines.append(f"- {item}")
                elif isinstance(item, dict):
                    title = item.get("title") or item.get("step") or item.get("name", "")
                    desc = item.get("description") or item.get("body") or item.get("detail", "")
                    lines.append(f"- **{title}**" + (f": {desc}" if desc else ""))
            lines.append("")

    features = site_copy.get("features")
    if features and isinstance(features, list):
        lines.append("### Features")
        lines.append("")
        for feat in features:
            if isinstance(feat, dict):
                title = feat.get("title") or feat.get("name", "")
                desc = feat.get("description") or feat.get("body", "")
                lines.append(f"#### {title}")
                if desc:
                    lines.append(desc)
                lines.append("")
            elif isinstance(feat, str):
                lines.append(f"- {feat}")
        lines.append("")

    testimonials = site_copy.get("testimonials")
    if testimonials and isinstance(testimonials, list):
        lines.append("### Testimonials")
        lines.append("")
        for t in testimonials:
            if isinstance(t, dict):
                quote = t.get("quote") or t.get("text", "")
                author = t.get("author") or t.get("name", "")
                role = t.get("role") or t.get("title", "")
                lines.append(f'> "{quote}"')
                attr = f"> — {author}"
                if role:
                    attr += f", {role}"
                lines.append(attr)
                lines.append("")

    faq_items = site_copy.get("faq_items")
    if faq_items and isinstance(faq_items, list):
        lines.append("### FAQ")
        lines.append("")
        for faq in faq_items:
            if isinstance(faq, dict):
                q = faq.get("question", "")
                a = faq.get("answer", "")
                lines.append(f"**Q: {q}**")
                lines.append(f"A: {a}")
                lines.append("")

    pricing = site_copy.get("pricing") or site_copy.get("pricing_plans")
    if pricing and isinstance(pricing, list):
        lines.append("### Pricing")
        lines.append("")
        for plan in pricing:
            if isinstance(plan, dict):
                name = plan.get("name") or plan.get("tier", "")
                price = plan.get("price", "")
                desc = plan.get("description", "")
                lines.append(f"#### {name} - {price}")
                if desc:
                    lines.append(desc)
                plan_features = plan.get("features", [])
                for pf in plan_features:
                    lines.append(f"  - {pf}")
                lines.append("")

    stats = site_copy.get("stats") or site_copy.get("statistics")
    if stats and isinstance(stats, list):
        lines.append("### Statistics")
        lines.append("")
        for stat in stats:
            if isinstance(stat, dict):
                val = stat.get("value") or stat.get("number", "")
                label = stat.get("label") or stat.get("description", "")
                lines.append(f"- **{val}** — {label}")
        lines.append("")

    handled = set(hero_fields.keys()) | set(simple_text_sections.keys()) | set(list_sections.keys()) | {
        "features", "testimonials", "faq_items", "pricing", "pricing_plans", "stats", "statistics"
    }
    remaining = set(site_copy.keys()) - handled
    for key in sorted(remaining):
        val = site_copy[key]
        if val is None:
            continue
        label = SECTION_LABELS.get(key, key.replace("_", " ").title())
        if isinstance(val, str) and len(val) > 5:
            lines.append(f"### {label}")
            lines.append("")
            lines.append(val)
            lines.append("")
        elif isinstance(val, list) and len(val) > 0:
            lines.append(f"### {label}")
            lines.append("")
            for item in val:
                if isinstance(item, str):
                    lines.append(f"- {item}")
                elif isinstance(item, dict):
                    lines.append(f"```json")
                    lines.append(json.dumps(item, indent=2))
                    lines.append("```")
            lines.append("")

    if sales_letter_md:
        lines.append("---")
        lines.append("")
        lines.append("## Marketplace Sales Letter")
        lines.append("")
        lines.append(sales_letter_md)
        lines.append("")

    lines.append("---")
    lines.append(f"*Generated by Aura | {gen_date}*")

    return "\n".join(lines)


async def capture_site_screenshots(domain: str, base_url: str, token: str, viewport_height: int = 900, max_pages: int = 8) -> list:
    preview_url = f"{base_url}/_dev_preview/{token}/{domain}"
    screenshots_dir = tempfile.mkdtemp(prefix="aura_screenshots_")

    chromium_path = None
    for candidate in ["/nix/store/qa9cnw4v5xkxyip6mb9kxqfq1z4x2dx1-chromium-138.0.7204.100/bin/chromium"]:
        if os.path.exists(candidate):
            chromium_path = candidate
            break
    if not chromium_path:
        result = subprocess.run(["which", "chromium"], capture_output=True, text=True)
        if result.returncode == 0:
            chromium_path = result.stdout.strip()

    try:
        from playwright.async_api import async_playwright
        async with async_playwright() as p:
            launch_args = ["--no-sandbox", "--disable-gpu", "--disable-dev-shm-usage"]
            browser = await p.chromium.launch(
                executable_path=chromium_path,
                headless=True,
                args=launch_args
            )
            page = await browser.new_page(
                viewport={"width": 1280, "height": viewport_height},
                device_scale_factor=2
            )
            await page.goto(preview_url, wait_until="networkidle", timeout=30000)

            total_height = await page.evaluate("() => document.body.scrollHeight")
            num_pages = min(max_pages, max(1, (total_height + viewport_height - 1) // viewport_height))

            paths = []
            for i in range(num_pages):
                scroll_y = i * viewport_height
                await page.evaluate(f"window.scrollTo(0, {scroll_y})")
                await page.wait_for_timeout(500)
                path = os.path.join(screenshots_dir, f"page_{i+1:02d}.png")
                await page.screenshot(path=path, full_page=False)
                paths.append(path)

            await browser.close()
            return paths
    except Exception as e:
        print(f"[export] Screenshot capture failed: {e}")
        return []


def _fmt_money_single(n):
    if n < 0:
        return "-" + _fmt_money_single(-n)
    if n >= 1000000:
        return f"${n / 1000000:.1f}M"
    if n >= 1000:
        return f"${n / 1000:.1f}K"
    return f"${int(round(n))}"


def _fmt_money(low, high):
    return f"{_fmt_money_single(low)}-{_fmt_money_single(high)}"


def _fmt_pct(val):
    return f"{int(round(val))}%"


def _margin_color(pct):
    if pct >= 60:
        return colors.HexColor("#10b981")
    if pct >= 40:
        return colors.HexColor("#eab308")
    return colors.HexColor("#f97316")


def _fulfillment_color(pct):
    if pct == 0:
        return colors.HexColor("#34d399")
    if pct <= 5:
        return colors.HexColor("#4ade80")
    if pct <= 15:
        return colors.HexColor("#facc15")
    if pct <= 40:
        return colors.HexColor("#fb923c")
    return colors.HexColor("#f87171")


class DarkPageCanvas(canvas.Canvas):
    def __init__(self, *args, **kwargs):
        self._domain = kwargs.pop('domain', '')
        canvas.Canvas.__init__(self, *args, **kwargs)
        self._saved_page_states = []

    def showPage(self):
        self._saved_page_states.append(dict(self.__dict__))
        self._startPage()

    def save(self):
        num_pages = len(self._saved_page_states)
        for state in self._saved_page_states:
            self.__dict__.update(state)
            self._draw_dark_footer(num_pages)
            canvas.Canvas.showPage(self)
        canvas.Canvas.save(self)

    def _draw_dark_footer(self, page_count):
        page_num = self._pageNumber
        pw, ph = landscape(A4)
        self.setFillColor(DARK_BG)
        self.rect(0, 0, pw, 35, fill=True, stroke=False)
        self.setFont("Helvetica", 7)
        self.setFillColor(TEXT_GRAY)
        self.drawString(0.5 * inch, 14, f"Aura Valuation — {self._domain}")
        self.drawRightString(pw - 0.5 * inch, 14, f"Page {page_num} of {page_count}")
        self.setStrokeColor(colors.HexColor("#334155"))
        self.setLineWidth(0.5)
        self.line(0.5 * inch, 30, pw - 0.5 * inch, 30)


class DarkBackground(Flowable):
    def __init__(self, width, height, color=None):
        Flowable.__init__(self)
        self.width = width
        self.height = height
        self.bg_color = color or DARK_BG

    def draw(self):
        self.canv.setFillColor(self.bg_color)
        self.canv.rect(0, 0, self.width, self.height, fill=True, stroke=False)


def generate_valuation_pdf(domain: str, valuation_data: dict) -> bytes:
    buffer = io.BytesIO()
    page_w, page_h = landscape(A4)
    doc = SimpleDocTemplate(
        buffer,
        pagesize=landscape(A4),
        rightMargin=0.4 * inch,
        leftMargin=0.4 * inch,
        topMargin=0.4 * inch,
        bottomMargin=0.5 * inch,
    )

    content_width = page_w - 0.8 * inch

    story = []

    gen_date = datetime.datetime.utcnow().strftime("%B %d, %Y")
    di = valuation_data.get("domain_intrinsic", {})

    header_style = ParagraphStyle(
        'ValHeader', fontName='Helvetica-Bold', fontSize=24,
        textColor=TEXT_WHITE, alignment=TA_LEFT, leading=28,
    )
    sub_style = ParagraphStyle(
        'ValSub', fontName='Helvetica', fontSize=9,
        textColor=TEXT_GRAY, alignment=TA_LEFT, leading=12,
    )
    value_label_style = ParagraphStyle(
        'ValLabel', fontName='Helvetica', fontSize=8,
        textColor=TEXT_GRAY, alignment=TA_CENTER, leading=10,
    )
    value_big_style = ParagraphStyle(
        'ValBig', fontName='Helvetica-Bold', fontSize=18,
        textColor=BRAND_EMERALD, alignment=TA_CENTER, leading=22,
    )
    value_big_purple = ParagraphStyle(
        'ValBigPurple', fontName='Helvetica-Bold', fontSize=18,
        textColor=BRAND_PURPLE_LIGHT, alignment=TA_CENTER, leading=22,
    )
    value_detail_style = ParagraphStyle(
        'ValDetail', fontName='Helvetica', fontSize=7,
        textColor=TEXT_GRAY, alignment=TA_CENTER, leading=9,
    )
    section_title_style = ParagraphStyle(
        'ValSecTitle', fontName='Helvetica-Bold', fontSize=13,
        textColor=TEXT_WHITE, alignment=TA_LEFT, leading=16,
    )
    niche_title_style = ParagraphStyle(
        'NicheTitle', fontName='Helvetica-Bold', fontSize=11,
        textColor=TEXT_WHITE, alignment=TA_LEFT, leading=14,
    )
    badge_style = ParagraphStyle(
        'Badge', fontName='Helvetica-Bold', fontSize=7,
        textColor=TEXT_WHITE, alignment=TA_CENTER, leading=9,
    )
    cell_style = ParagraphStyle(
        'CellText', fontName='Helvetica', fontSize=8,
        textColor=TEXT_WHITE, alignment=TA_LEFT, leading=10,
    )
    cell_right = ParagraphStyle(
        'CellRight', fontName='Helvetica', fontSize=8,
        textColor=TEXT_WHITE, alignment=TA_RIGHT, leading=10,
    )
    cell_center = ParagraphStyle(
        'CellCenter', fontName='Helvetica', fontSize=8,
        textColor=TEXT_WHITE, alignment=TA_CENTER, leading=10,
    )
    th_style = ParagraphStyle(
        'THStyle', fontName='Helvetica-Bold', fontSize=7,
        textColor=colors.HexColor("#cbd5e1"), alignment=TA_CENTER, leading=9,
    )
    th_left = ParagraphStyle(
        'THLeft', fontName='Helvetica-Bold', fontSize=7,
        textColor=colors.HexColor("#cbd5e1"), alignment=TA_LEFT, leading=9,
    )
    fulfill_label = ParagraphStyle(
        'FulfillLabel', fontName='Helvetica-Bold', fontSize=8,
        textColor=TEXT_WHITE, alignment=TA_CENTER, leading=10,
    )
    fulfill_sub = ParagraphStyle(
        'FulfillSub', fontName='Helvetica', fontSize=6,
        textColor=TEXT_GRAY, alignment=TA_CENTER, leading=8,
    )

    domain_only = valuation_data.get("domain_only_value", 0)
    best_dev = valuation_data.get("best_developed_value", 0)
    best_net = valuation_data.get("best_monthly_net", 0)

    domain_details = f"{di.get('name_part', domain)} \u00b7 {di.get('tld', '.com')} \u00b7 {di.get('length', 0)} chars"
    if di.get("has_hyphens"):
        domain_details += " \u00b7 hyphenated"
    if di.get("has_numbers"):
        domain_details += " \u00b7 has numbers"

    header_data = [[
        [Paragraph(_safe_text(domain), header_style),
         Paragraph(f"Domain Valuation Report \u00b7 {gen_date}", sub_style)],
        [Paragraph("DOMAIN-ONLY VALUE", value_label_style),
         Paragraph(_fmt_money_single(domain_only), value_big_style),
         Paragraph(domain_details, value_detail_style)],
        [Paragraph("BEST DEVELOPED VALUE", value_label_style),
         Paragraph(_fmt_money_single(best_dev), value_big_purple),
         Paragraph(f"Best monthly net: {_fmt_money_single(best_net)}/mo", value_detail_style)],
    ]]

    header_table = Table(header_data, colWidths=[content_width * 0.40, content_width * 0.30, content_width * 0.30])
    header_table.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), colors.HexColor("#0c1222")),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('TOPPADDING', (0, 0), (-1, -1), 12),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 12),
        ('LEFTPADDING', (0, 0), (0, 0), 16),
        ('RIGHTPADDING', (-1, -1), (-1, -1), 16),
        ('LINEBELOW', (0, 0), (-1, 0), 2, BRAND_PURPLE),
        ('ROUNDEDCORNERS', [6, 6, 6, 6]),
    ]))
    story.append(header_table)
    story.append(Spacer(1, 12))

    story.append(GradientRect(content_width, 2, BRAND_PURPLE, BRAND_EMERALD))
    story.append(Spacer(1, 10))

    fulfillment_data = [
        ("0%", "Affiliate", "#34d399", "Zero fulfillment"),
        ("~3%", "Digital/Info", "#4ade80", "Near-zero"),
        ("~10%", "SaaS", "#facc15", "Server costs"),
        ("~35%", "Dropship", "#fb923c", "Supplier ships"),
        ("~50%", "Own Inventory", "#f87171", "Full burden"),
    ]

    fulfill_cells = []
    for cost, label, hex_c, desc in fulfillment_data:
        fulfill_cells.append([
            Paragraph(f'<font color="{hex_c}">{cost}</font>', fulfill_label),
            Paragraph(label, fulfill_sub),
        ])

    fulfill_title_row = [[Paragraph("\u26a0 FULFILLMENT REALITY CHECK", ParagraphStyle(
        'FulfillTitle', fontName='Helvetica-Bold', fontSize=9,
        textColor=colors.HexColor("#facc15"), alignment=TA_LEFT, leading=11,
    ))] + [Paragraph("", cell_style)] * 4]

    fw = content_width / 5
    fulfill_table = Table([fulfill_cells], colWidths=[fw] * 5)
    fulfill_table.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), colors.HexColor("#1a1a2e")),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('TOPPADDING', (0, 0), (-1, -1), 8),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 8),
        ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
        ('GRID', (0, 0), (-1, -1), 0.5, colors.HexColor("#334155")),
        ('ROUNDEDCORNERS', [4, 4, 4, 4]),
    ]))

    fulfill_title_table = Table(
        [[Paragraph("\u26a0 FULFILLMENT REALITY CHECK", ParagraphStyle(
            'FulfillTitle2', fontName='Helvetica-Bold', fontSize=9,
            textColor=colors.HexColor("#facc15"), alignment=TA_LEFT, leading=11,
        ))]],
        colWidths=[content_width],
    )
    fulfill_title_table.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), colors.HexColor("#1a1a2e")),
        ('TOPPADDING', (0, 0), (-1, -1), 6),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 2),
        ('LEFTPADDING', (0, 0), (-1, -1), 10),
    ]))

    story.append(fulfill_title_table)
    story.append(fulfill_table)
    story.append(Spacer(1, 16))

    niche_valuations = valuation_data.get("niche_valuations", [])

    for nv in niche_valuations:
        traffic = nv.get("traffic_estimate", {})
        visitors_low = traffic.get("monthly_visitors_low", 0)
        visitors_high = traffic.get("monthly_visitors_high", 0)
        requires_inv = nv.get("requires_inventory", False)

        inv_color = "#ef4444" if requires_inv else "#10b981"
        inv_bg = "#7f1d1d" if requires_inv else "#064e3b"
        inv_text = "Requires Inventory" if requires_inv else "No Inventory"

        niche_header_data = [[
            Paragraph(_safe_text(nv.get("niche_name", "Unknown")), niche_title_style),
            Paragraph(f'<font color="{inv_color}" size="7"><b>{inv_text}</b></font>', ParagraphStyle(
                'InvBadge', fontName='Helvetica-Bold', fontSize=7,
                textColor=colors.HexColor(inv_color), alignment=TA_RIGHT, leading=9,
            )),
            Paragraph(f'<font color="#94a3b8" size="7">{visitors_low:,}-{visitors_high:,} visitors/mo</font>', ParagraphStyle(
                'TrafficLabel', fontName='Helvetica', fontSize=7,
                textColor=TEXT_GRAY, alignment=TA_RIGHT, leading=9,
            )),
        ]]

        niche_header_table = Table(niche_header_data, colWidths=[content_width * 0.50, content_width * 0.25, content_width * 0.25])
        niche_header_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, -1), colors.HexColor("#1e1b4b")),
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
            ('TOPPADDING', (0, 0), (-1, -1), 8),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 8),
            ('LEFTPADDING', (0, 0), (0, 0), 12),
            ('RIGHTPADDING', (-1, -1), (-1, -1), 12),
            ('ROUNDEDCORNERS', [6, 6, 0, 0]),
        ]))

        headers_row = [
            Paragraph("BUSINESS MODEL", th_left),
            Paragraph("FULFILLMENT", th_style),
            Paragraph("GROSS/MO", th_style),
            Paragraph("NET/MO", th_style),
            Paragraph("MARGIN", th_style),
            Paragraph("DEVELOPED VALUE", th_style),
            Paragraph("STARTUP", th_style),
        ]

        col_widths = [
            content_width * 0.22,
            content_width * 0.10,
            content_width * 0.15,
            content_width * 0.15,
            content_width * 0.10,
            content_width * 0.15,
            content_width * 0.13,
        ]

        table_data = [headers_row]

        revenue_models = nv.get("revenue_by_model", [])
        for rm in revenue_models:
            rev = rm.get("monthly_revenue", {})
            is_primary = rm.get("is_primary_fit", False)
            prefix = "\u2605 " if is_primary else ""

            margin_pct = rev.get("profit_margin_pct", 0)
            mc = _margin_color(margin_pct)
            fc = _fulfillment_color(rm.get("fulfillment_cost_pct", 0))

            gross_text = _fmt_money(rev.get("gross_low", 0), rev.get("gross_high", 0))
            net_low = rev.get("net_profit_low", 0)
            net_high = rev.get("net_profit_high", 0)
            net_text = _fmt_money(net_low, net_high)
            net_color = "#ef4444" if (net_low < 0 or net_high < 0) else "#f1f5f9"

            dev_val = rm.get("developed_value", {})
            dev_text = _fmt_money(dev_val.get("low", 0), dev_val.get("high", 0))
            dev_color = "#64748b" if dev_val.get("high", 0) == 0 else "#10b981"

            startup = rm.get("startup_cost", {})
            startup_text = _fmt_money(startup.get("low", 0), startup.get("high", 0))

            row = [
                Paragraph(f'<b>{prefix}{_safe_text(rm.get("label", ""))}</b>', cell_style),
                Paragraph(f'<font color="{fc.hexval()}">{_fmt_pct(rm.get("fulfillment_cost_pct", 0))}</font>', cell_center),
                Paragraph(gross_text, cell_right),
                Paragraph(f'<font color="{net_color}">{net_text}</font>', cell_right),
                Paragraph(f'<font color="{mc.hexval()}">{_fmt_pct(margin_pct)}</font>', cell_center),
                Paragraph(f'<font color="{dev_color}">{dev_text}</font>', cell_right),
                Paragraph(startup_text, cell_right),
            ]
            table_data.append(row)

        data_table = Table(table_data, colWidths=col_widths)

        table_styles = [
            ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor("#312e81")),
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.HexColor("#cbd5e1")),
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
            ('TOPPADDING', (0, 0), (-1, -1), 5),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 5),
            ('LEFTPADDING', (0, 0), (-1, -1), 6),
            ('RIGHTPADDING', (0, 0), (-1, -1), 6),
            ('LINEBELOW', (0, 0), (-1, 0), 1, colors.HexColor("#4338ca")),
            ('GRID', (0, 0), (-1, -1), 0.25, colors.HexColor("#1e293b")),
            ('ROUNDEDCORNERS', [0, 0, 6, 6]),
        ]

        for i in range(1, len(table_data)):
            bg = colors.HexColor("#0f172a") if i % 2 == 1 else colors.HexColor("#151d30")
            table_styles.append(('BACKGROUND', (0, i), (-1, i), bg))

            rm = revenue_models[i - 1] if i - 1 < len(revenue_models) else {}
            if rm.get("is_primary_fit", False):
                table_styles.append(('BACKGROUND', (0, i), (-1, i), colors.HexColor("#1a0f3a")))

        data_table.setStyle(TableStyle(table_styles))

        story.append(KeepTogether([niche_header_table, data_table]))
        story.append(Spacer(1, 14))

    footer_style = ParagraphStyle(
        'ValFooter', fontName='Helvetica-Oblique', fontSize=7,
        textColor=TEXT_GRAY, alignment=TA_CENTER, leading=9,
    )
    story.append(Spacer(1, 6))
    story.append(GradientRect(content_width, 1, BRAND_PURPLE, BRAND_EMERALD))
    story.append(Spacer(1, 6))
    story.append(Paragraph(
        f"Generated by Aura \u00b7 {gen_date} \u00b7 Estimates based on algorithmic scoring, not financial advice",
        footer_style
    ))

    def on_page(canvas_obj, doc_obj):
        canvas_obj.saveState()
        pw, ph = landscape(A4)
        canvas_obj.setFillColor(DARK_BG)
        canvas_obj.rect(0, 0, pw, ph, fill=True, stroke=False)
        canvas_obj.restoreState()

    doc.build(story, onFirstPage=on_page, onLaterPages=on_page,
              canvasmaker=lambda *a, **kw: DarkPageCanvas(*a, domain=domain, **kw))

    return buffer.getvalue()
