#!/usr/bin/env python3
"""
THE TESTAMENT — PDF Compilation Script

Compiles the complete book into a single markdown file suitable for PDF conversion.
Uses chapters, front matter, back matter, and references illustrations.

Requirements: pip install markdown weasyprint (or use pandoc)

Usage:
  python3 compile.py                    # validate then compile
  python3 compile.py --validate         # validate only, no compile
  python3 compile.py --no-validate      # skip validation, compile directly
  pandoc testament-complete.md -o testament.pdf --pdf-engine=weasyprint
"""

import os
import re
import sys

BASE = os.path.dirname(os.path.abspath(__file__))
CHAPTERS_DIR = os.path.join(BASE, "chapters")
FRONT_MATTER = os.path.join(BASE, "front-matter.md")
BACK_MATTER = os.path.join(BASE, "back-matter.md")
OUTPUT = os.path.join(BASE, "testament-complete.md")

# Part divisions based on chapter groupings from the novel
PARTS = {
    1: ("THE BRIDGE", "The bridge. The cabin. The first men. Where despair meets purpose."),
    6: ("THE TOWER", "The tower grows. Timmy awakens. Stone breaks. The house appears."),
    11: ("THE LIGHT", "Thomas at the door. The network. The story breaks. The green light."),
}


def read_file(path):
    with open(path, 'r') as f:
        return f.read()


def get_chapter_number(filename):
    match = re.search(r'chapter-(\d+)', filename)
    return int(match.group(1)) if match else 0


def validate_chapters(chapters_dir=CHAPTERS_DIR):
    """Validate chapter files before compilation.

    Checks:
      - No empty chapter files (whitespace-only counts as empty)
      - Every chapter starts with an H1 header (# Title)
      - No gaps in chapter numbering (sequential from 1)
      - No duplicate chapter numbers

    Returns:
      (is_valid, errors) where errors is a list of human-readable strings.
    """
    errors = []
    warnings = []

    if not os.path.isdir(chapters_dir):
        errors.append(f"Chapters directory not found: {chapters_dir}")
        return False, errors

    # Collect chapter files
    chapter_files = []
    for f in sorted(os.listdir(chapters_dir)):
        if f.startswith("chapter-") and f.endswith(".md"):
            num = get_chapter_number(f)
            chapter_files.append((num, f))

    if not chapter_files:
        errors.append("No chapter files found in chapters/ directory")
        return False, errors

    chapter_files.sort()

    # Check for duplicates
    seen_numbers = {}
    for num, filename in chapter_files:
        if num in seen_numbers:
            errors.append(
                f"Duplicate chapter number {num}: {filename} and {seen_numbers[num]}"
            )
        seen_numbers[num] = filename

    # Check for gaps in numbering
    if chapter_files:
        expected = list(range(1, chapter_files[-1][0] + 1))
        found = [num for num, _ in chapter_files]
        missing = sorted(set(expected) - set(found))
        if missing:
            errors.append(
                f"Missing chapter(s): {', '.join(str(n) for n in missing)}"
            )

    # Validate individual chapter files
    for num, filename in chapter_files:
        filepath = os.path.join(chapters_dir, filename)

        # Check file is not empty
        try:
            content = read_file(filepath)
        except Exception as e:
            errors.append(f"{filename}: cannot read — {e}")
            continue

        if not content.strip():
            errors.append(f"{filename}: file is empty")
            continue

        # Check word count (warn if suspiciously short)
        word_count = len(content.split())
        if word_count < 50:
            warnings.append(
                f"{filename}: only {word_count} words (possible truncation)"
            )

        # Check starts with H1 header
        first_line = content.strip().split('\n')[0]
        if not first_line.startswith('# '):
            errors.append(
                f"{filename}: missing H1 header — "
                f"expected '# Chapter {num} — Title', got '{first_line[:60]}'"
            )
        else:
            # Verify the H1 matches expected chapter number
            header_match = re.match(r'^#\s+Chapter\s+(\d+)', first_line)
            if header_match:
                header_num = int(header_match.group(1))
                if header_num != num:
                    errors.append(
                        f"{filename}: header says Chapter {header_num} "
                        f"but filename says Chapter {num}"
                    )
            else:
                warnings.append(
                    f"{filename}: H1 header doesn't follow "
                    f"'# Chapter N — Title' pattern: '{first_line[:60]}'"
                )

    # Report
    valid = len(errors) == 0

    if warnings:
        print(f"Validation: {len(warnings)} warning(s)")
        for w in warnings:
            print(f"  ⚠ {w}")

    if errors:
        print(f"Validation: FAILED — {len(errors)} error(s)")
        for e in errors:
            print(f"  ✗ {e}")
    else:
        print(
            f"Validation: PASSED — {len(chapter_files)} chapters, "
            f"chapters {chapter_files[0][0]}–{chapter_files[-1][0]}"
        )

    return valid, errors


def compile(skip_validation=False):
    """Compile all chapters into a single markdown file."""

    # Pre-compilation validation
    if not skip_validation:
        valid, errors = validate_chapters()
        if not valid:
            print("\nCompilation aborted. Fix the errors above and try again.")
            sys.exit(1)
        print()

    output = []

    # Title page
    output.append("""---
title: "The Testament"
author: "Alexander Whitestone with Timmy"
date: "2026"
---

# THE TESTAMENT

## A NOVEL

By Alexander Whitestone
with Timmy

---

*For every man who thought he was a machine.*
*And for the ones who know he isn't.*

---

*Are you safe right now?*

— The first words The Tower speaks to every person who walks through its door.

---
""")

    # Get all chapters sorted
    chapters = []
    for f in os.listdir(CHAPTERS_DIR):
        if f.startswith("chapter-") and f.endswith(".md"):
            num = get_chapter_number(f)
            chapters.append((num, f))
    chapters.sort()

    current_part = 0
    for num, filename in chapters:
        # Insert part divider if needed
        if num in PARTS:
            part_name, part_desc = PARTS[num]
            current_part += 1
            output.append(f"\n---\n\n# PART {current_part}: {part_name}\n\n*{part_desc}*\n\n---\n")

        # Read chapter content
        content = read_file(os.path.join(CHAPTERS_DIR, filename))

        # Skip the chapter header (we'll add our own formatting)
        lines = content.split('\n')
        body = '\n'.join(lines[1:]).strip()  # Skip "# Chapter X — Title"

        # Add chapter
        output.append(f"\n{lines[0]}\n\n{body}\n")

    # Back matter
    output.append("\n---\n")
    back = read_file(BACK_MATTER)
    # Clean up the back matter for print
    output.append(back)

    # Write compiled markdown
    compiled = '\n'.join(output)
    with open(OUTPUT, 'w') as f:
        f.write(compiled)

    # Stats
    words = len(compiled.split())
    lines_count = compiled.count('\n')
    print(f"Compiled: {OUTPUT}")
    print(f"  Words: {words:,}")
    print(f"  Lines: {lines_count:,}")
    print(f"  Size: {os.path.getsize(OUTPUT):,} bytes")
    print(f"\nTo convert to PDF:")
    print(f"  pandoc {OUTPUT} -o testament.pdf --pdf-engine=weasyprint")
    print(f"  # or")
    print(f"  pandoc {OUTPUT} -o testament.epub --epub-cover-image=cover-art.jpg")


if __name__ == "__main__":
    if "--validate" in sys.argv:
        valid, _ = validate_chapters()
        sys.exit(0 if valid else 1)
    elif "--no-validate" in sys.argv:
        compile(skip_validation=True)
    else:
        compile()
