#!/usr/bin/env python3
"""Generate printable PDFs from guide.md files for 2nd Grade curriculum."""

import os
import re
import glob
from fpdf import FPDF

BASE = os.path.expanduser("~/Home_School/2nd Grade")
FONT_DIR = "/usr/share/fonts/truetype/dejavu"

class PDF(FPDF):
    def __init__(self):
        super().__init__()
        self.add_font('DejaVu', '', f'{FONT_DIR}/DejaVuSans.ttf', uni=True)
        self.add_font('DejaVu', 'B', f'{FONT_DIR}/DejaVuSans-Bold.ttf', uni=True)
        self.add_font('DejaVuMono', '', f'{FONT_DIR}/DejaVuSansMono.ttf', uni=True)
        self.add_font('DejaVuMono', 'B', f'{FONT_DIR}/DejaVuSansMono-Bold.ttf', uni=True)
        self.subject = ''
        self.week = ''

    def header(self):
        self.set_font('DejaVu', 'B', 9)
        self.set_text_color(100, 100, 100)
        self.cell(0, 6, f'{self.subject}  •  {self.week}', 0, 1, 'L')
        self.set_draw_color(200, 200, 200)
        self.line(10, 12, 200, 12)
        self.ln(4)

    def footer(self):
        self.set_y(-15)
        self.set_font('DejaVu', '', 8)
        self.set_text_color(150, 150, 150)
        self.cell(0, 10, f'Page {self.page_no()}', 0, 0, 'C')

    def add_section_title(self, text):
        self.set_font('DejaVu', 'B', 14)
        self.set_text_color(30, 30, 30)
        self.cell(0, 10, text, 0, 1, 'L')
        self.set_draw_color(60, 120, 200)
        self.set_line_width(0.4)
        self.line(10, self.get_y(), 200, self.get_y())
        self.ln(4)

    def add_sub_title(self, text):
        self.set_font('DejaVu', 'B', 11)
        self.set_text_color(50, 50, 50)
        self.cell(0, 8, text, 0, 1, 'L')
        self.ln(1)

    def add_sub_sub_title(self, text):
        self.set_font('DejaVu', 'B', 10)
        self.set_text_color(60, 60, 60)
        self.cell(0, 7, text, 0, 1, 'L')
        self.ln(1)

    def add_body(self, text, indent=0):
        self.set_font('DejaVu', '', 10)
        self.set_text_color(30, 30, 30)
        x = 10 + indent
        w = 190 - indent
        self.set_x(x)
        self.multi_cell(w, 5, text)
        self.ln(2)

    def add_bold_body(self, text):
        self.set_font('DejaVu', 'B', 10)
        self.set_text_color(30, 30, 30)
        self.set_x(10)
        self.multi_cell(190, 5, text)
        self.ln(1)

    def add_column_math(self, lines):
        """Render a column math block (stacked addition/subtraction)."""
        self.set_font('DejaVuMono', '', 12)
        self.set_text_color(30, 30, 30)
        y_start = self.get_y()
        max_len = max(len(l) for l in lines) if lines else 10
        # Calculate width needed
        char_w = self.get_string_width('0')
        block_w = (max_len + 2) * char_w
        x = (210 - block_w) / 2  # center the block

        self.set_draw_color(180, 180, 180)
        self.set_fill_color(248, 248, 248)
        # Draw background
        block_h = (len(lines) + 1) * (char_w * 1.3)
        self.rect(x - 5, y_start - 2, block_w + 10, block_h, 'F')

        self.set_x(x)
        for i, line in enumerate(lines):
            self.set_y(y_start + i * (char_w * 1.3))
            if '---' in line:
                # Draw a line instead
                self.set_draw_color(80, 80, 80)
                self.set_line_width(0.6)
                ly = self.get_y() + char_w * 0.8
                self.line(x - 3, ly, x + block_w, ly)
            else:
                self.cell(block_w, char_w * 1.3, f'  {line}  ')
        self.set_line_width(0.2)
        self.ln(block_h + 4)

    def add_problem_list(self, items):
        """Add numbered problem list, 2 per row when possible."""
        self.set_font('DejaVu', '', 10)
        self.set_text_color(30, 30, 30)
        x_start = 10
        col_w = 90
        line_h = 6
        for i, item in enumerate(items):
            if i % 2 == 0:
                self.set_x(x_start)
                self.set_y(self.get_y())
            else:
                self.set_x(x_start + col_w + 10)
                self.set_y(self.get_y() - line_h)
            # Check if we need a new page
            if self.get_y() > 255:
                self.add_page()
                self.set_x(x_start)
            self.cell(col_w, line_h, item)
        self.ln(3)


def parse_guide(content, subject, week_num):
    """Parse guide.md and return a list of day sections."""
    sections = []

    # Match ## headers, skip overview
    for m in re.finditer(r'^## (.+?)$\n(.*?)(?=^## )', content, re.MULTILINE | re.DOTALL):
        title = m.group(1).strip()
        body = m.group(2).strip()

        if any(skip in title.lower() for skip in ["overview", "daily breakdown"]):
            continue

        if body.strip():
            sections.append((title, body))

    if not sections:
        # Fallback
        parts = re.split(r'^## ', content, flags=re.MULTILINE)
        for part in parts:
            lines = part.strip().split('\n')
            if not lines:
                continue
            title = lines[0].strip()
            if any(skip in title.lower() for skip in ["overview", "daily breakdown"]):
                continue
            body = '\n'.join(lines[1:]).strip()
            if body:
                sections.append((title, body))

    return sections


def render_section(pdf, body):
    """Render a day section body into the PDF."""
    # Remove emoji prefixes
    body = re.sub(r'### ', '### ', body)
    body = re.sub(r'^\*+(.*?)\*+', r'\1', body, flags=re.MULTILINE)

    # Split into blocks
    lines = body.split('\n')
    i = 0
    in_code = False
    code_lines = []
    in_problem_set = False
    problem_items = []

    while i < len(lines):
        line = lines[i]
        stripped = line.strip()

        # Handle code blocks (column math)
        if stripped.startswith('```'):
            if in_code:
                # End of code block - render as column math
                clean_lines = [l.strip() for l in code_lines if l.strip()]
                if clean_lines:
                    # Check if it looks like column math (has numbers and dashes)
                    has_math = any(re.search(r'[\d\s+\-]', l) for l in clean_lines)
                    if has_math and len(clean_lines) >= 2:
                        pdf.add_column_math(clean_lines)
                    else:
                        pdf.add_body(f'```\n{"\n".join(clean_lines)}\n```')
                code_lines = []
                in_code = False
            else:
                in_code = True
                code_lines = []
            i += 1
            continue

        if in_code:
            code_lines.append(line)
            i += 1
            continue

        # Headers
        if stripped.startswith('### '):
            pdf.add_sub_sub_title(stripped.replace('### ', ''))
            i += 1
            continue
        elif stripped.startswith('## '):
            pdf.add_sub_title(stripped.replace('## ', ''))
            i += 1
            continue

        # Bold lines
        if stripped.startswith('**') and stripped.endswith('**'):
            pdf.add_bold_body(stripped.strip('*'))
            i += 1
            continue

        # Numbered problems (collect for 2-column layout)
        if re.match(r'^\d+[\.\)]\s', stripped) or re.match(r'^\d+\.\s+.*=.*___', stripped):
            # Check if it's a simple problem line
            if '=' in stripped or re.match(r'^\d+\.\s+.*___', stripped):
                if not in_problem_set:
                    in_problem_set = True
                problem_items.append(stripped)
                i += 1
                continue
            else:
                if in_problem_set:
                    pdf.add_problem_list(problem_items)
                    problem_items = []
                    in_problem_set = False
                pdf.add_body(stripped)
                i += 1
                continue

        # Set headers like "Set 1:", "Set 2:"
        if re.match(r'^\*?\*Set \d+:', stripped):
            if in_problem_set:
                pdf.add_problem_list(problem_items)
                problem_items = []
                in_problem_set = False
            pdf.add_sub_sub_title(stripped.strip('*'))
            i += 1
            continue

        # Word problem headers
        if re.match(r'^\*?\*(Word Problems|Guided Practice|Independent Practice|Main Lesson|Warm-Up|Strategy)', stripped):
            if in_problem_set:
                pdf.add_problem_list(problem_items)
                problem_items = []
                in_problem_set = False
            pdf.add_sub_sub_title(stripped.strip('*'))
            i += 1
            continue

        # Blank line
        if not stripped:
            if in_problem_set:
                pdf.add_problem_list(problem_items)
                problem_items = []
                in_problem_set = False
            i += 1
            continue

        # Dash list items
        if stripped.startswith('- '):
            text = stripped[2:].strip()
            text = text.strip('*').strip()
            pdf.set_x(15)
            pdf.cell(5, 5, '•')
            pdf.set_font('DejaVu', '', 10)
            pdf.set_text_color(30, 30, 30)
            pdf.multi_cell(180, 5, text)
            pdf.ln(1)
            i += 1
            continue

        # Regular text
        if stripped:
            text = stripped.strip('*').strip()
            if text:
                pdf.add_body(text)
        i += 1

    # Flush remaining problems
    if in_problem_set and problem_items:
        pdf.add_problem_list(problem_items)


def generate_pdfs():
    subjects = ["Mathematics", "Phonics & Reading", "Spelling & Grammar"]
    total = 0

    for subject in subjects:
        for week_dir in sorted(glob.glob(os.path.join(BASE, subject, "Week *"))):
            week_num = os.path.basename(week_dir).replace("Week ", "")
            guide_path = os.path.join(week_dir, "guide.md")
            if not os.path.exists(guide_path):
                continue

            with open(guide_path, 'r', encoding='utf-8') as f:
                content = f.read()

            sections = parse_guide(content, subject, week_num)
            if not sections:
                # For Spelling & Grammar, split by ## sections
                sections = [(m.group(1), m.group(2)) for m in
                          re.finditer(r'^## (.+?)\n(.*?)(?=^## )', content, re.MULTILINE | re.DOTALL)]
                if not sections:
                    continue

            print(f"\n{subject} - Week {week_num}: {len(sections)} sections")

            for title, body in sections:
                pdf = PDF()
                pdf.subject = subject
                pdf.week = f"Week {week_num}"

                pdf.add_page()
                pdf.add_section_title(title)
                render_section(pdf, body)

                # Create printables directory
                printable_dir = os.path.join(week_dir, "printables")
                os.makedirs(printable_dir, exist_ok=True)

                # Clean filename - keep it short
                safe_name = re.sub(r'[^a-zA-Z0-9_ ]', '', title)
                safe_name = re.sub(r'\s+', '_', safe_name)
                # Truncate if too long
                if len(safe_name) > 60:
                    safe_name = safe_name[:60].rsplit('_', 1)[0]
                filename = f"Week {week_num}_{safe_name}.pdf"
                filepath = os.path.join(printable_dir, filename)

                pdf.output(filepath)
                total += 1
                print(f"  ✓ {filename} ({os.path.getsize(filepath)} bytes)")

    print(f"\nDone! Generated {total} PDFs total.")


if __name__ == "__main__":
    generate_pdfs()
