#!/usr/bin/env python3
"""
Export Book chapters to a Kindle-ready EPUB file.

Usage:
    venv/bin/python export_kindle.py --book 1
    # or: source venv/bin/activate && python export_kindle.py --book 1

Requires: pip install -r requirements.txt (ebooklib, markdown)
"""

import argparse
import re
import sys
from pathlib import Path

import markdown
from ebooklib import epub

ROOT = Path(__file__).parent
KINDLE_CSS = """\
body {
    font-family: Georgia, "Times New Roman", serif;
    font-size: 1em;
    line-height: 1.6;
    margin: 1em;
}
h1 {
    font-size: 1.8em;
    text-align: center;
    margin-top: 2em;
    margin-bottom: 1.5em;
    page-break-before: always;
}
p {
    margin: 0 0 0.8em 0;
    text-indent: 1.5em;
}
p.first-para {
    text-indent: 0;
}
p.scene-break {
    text-align: center;
    text-indent: 0;
    margin: 1.5em 0;
    letter-spacing: 0.5em;
    font-size: 0.85em;
}
.title-page {
    text-align: center;
    margin-top: 4em;
    margin-bottom: 4em;
}
.title-page h1 {
    font-size: 2.2em;
    margin-bottom: 0.3em;
    page-break-before: avoid;
}
.title-page p {
    text-indent: 0;
    font-size: 1.1em;
    font-style: italic;
}
em { font-style: italic; }
strong { font-weight: bold; }
"""



# ---------------------------------------------------------------------------
# Markdown → HTML conversion
# ---------------------------------------------------------------------------

def convert_md_to_html(text: str) -> str:
    """Convert markdown text to HTML with smart quotes and scene breaks."""
    md = markdown.Markdown(extensions=["smarty"])
    html = md.convert(text)
    html = convert_scene_breaks(html)
    html = inject_first_para_class(html)
    return html


def convert_scene_breaks(html: str) -> str:
    """Replace bare '* * *' paragraphs with styled scene breaks."""
    return html.replace("<p>* * *</p>", '<p class="scene-break">* * *</p>')


def inject_first_para_class(html: str) -> str:
    """Add class='first-para' to paragraphs following h1 and scene breaks."""
    # After </h1>
    html = re.sub(
        r"(</h1>\s*)<p>",
        r'\1<p class="first-para">',
        html,
    )
    # After scene break
    html = re.sub(
        r'(<p class="scene-break">.*?</p>\s*)<p>',
        r'\1<p class="first-para">',
        html,
    )
    return html


def extract_title(text: str) -> str:
    """Extract the chapter title from the first # heading."""
    match = re.match(r"^#\s+(.+)$", text.strip(), re.MULTILINE)
    return match.group(1) if match else None


# ---------------------------------------------------------------------------
# Chapter discovery
# ---------------------------------------------------------------------------

def find_chapter_file(chapter_dir: Path, num: int) -> Path | None:
    """Find the best file for a chapter number (prefer final, fall back to draft)."""
    for suffix in ("final", "draft"):
        path = chapter_dir / f"ch{num:02d}-{suffix}.md"
        if path.exists():
            return path
    return None


def find_special_chapter(chapter_dir: Path, name: str) -> Path | None:
    """Find prologue or epilogue (prefer final, fall back to draft)."""
    for suffix in ("final", "draft"):
        path = chapter_dir / f"{name}-{suffix}.md"
        if path.exists():
            return path
    return None


def discover_chapters(chapter_dir: Path) -> list[tuple[str, Path]]:
    """Discover all chapter files in order: prologue, ch01..chNN, epilogue."""
    chapters = []

    # Prologue
    prologue = find_special_chapter(chapter_dir, "prologue")
    if prologue:
        chapters.append(("prologue", prologue))

    # Numbered chapters
    nums = set()
    for p in chapter_dir.glob("ch*-final.md"):
        m = re.match(r"ch(\d+)", p.name)
        if m:
            nums.add(int(m.group(1)))
    for p in chapter_dir.glob("ch*-draft.md"):
        m = re.match(r"ch(\d+)", p.name)
        if m:
            nums.add(int(m.group(1)))

    for num in sorted(nums):
        path = find_chapter_file(chapter_dir, num)
        if path:
            chapters.append((f"ch{num:02d}", path))

    # Epilogue
    epilogue = find_special_chapter(chapter_dir, "epilogue")
    if epilogue:
        chapters.append(("epilogue", epilogue))

    return chapters


# ---------------------------------------------------------------------------
# Template handling
# ---------------------------------------------------------------------------

def is_stub(text: str) -> bool:
    """Check if a template file is a stub (placeholder with no real content)."""
    # Strip headings, HTML comments, and whitespace
    content = re.sub(r"^#+\s+.*$", "", text, flags=re.MULTILINE)
    content = re.sub(r"<!--.*?-->", "", content, flags=re.DOTALL)
    content = content.strip()
    return len(content.split()) < 10


def load_template(path: Path) -> str | None:
    """Load a template file, returning None if it doesn't exist or is a stub."""
    if not path.exists():
        return None
    text = path.read_text(encoding="utf-8")
    if is_stub(text):
        print(f"  Skipping stub template: {path.name}", file=sys.stderr)
        return None
    return text


# ---------------------------------------------------------------------------
# EPUB construction
# ---------------------------------------------------------------------------

def make_epub_chapter(filename: str, title: str, body_html: str) -> epub.EpubHtml:
    """Create an EPUB chapter item from HTML body content."""
    chapter = epub.EpubHtml(
        title=title,
        file_name=filename,
        lang="en",
    )
    chapter.set_content(body_html)
    chapter.add_link(href="style/kindle.css", rel="stylesheet", type="text/css")
    return chapter


def build_title_page(title: str, subtitle: str, author: str) -> epub.EpubHtml:
    """Generate a title page chapter."""
    body = f"""\
<div class="title-page">
<h1>{title}</h1>
<p>{subtitle}</p>
<p>by {author}</p>
</div>"""
    return make_epub_chapter("title.xhtml", "Title Page", body)


def build_epub(args) -> Path:
    """Build the EPUB file and return its path."""
    book_num = args.book
    title = args.title or "The Floundry Affair"
    author = args.author or "Phillip Tarrant"
    subtitle = f"A Phelan Varrant Novel — Book {book_num}"

    chapter_dir = ROOT / "chapters" / f"book{book_num}"
    if not chapter_dir.exists():
        print(f"Error: Chapter directory not found: {chapter_dir}", file=sys.stderr)
        sys.exit(1)

    template_dir = ROOT / "kindle" / "templates"
    export_dir = ROOT / "kindle" / "exports"
    export_dir.mkdir(parents=True, exist_ok=True)

    # --- Create the EPUB book ---
    book = epub.EpubBook()
    book.set_identifier(f"phelan-varrant-book{book_num}")
    book.set_title(f"{title}: {subtitle}")
    book.set_language("en")
    book.add_author(author)

    # Cover image
    if args.cover:
        cover_path = Path(args.cover)
        if cover_path.exists():
            cover_data = cover_path.read_bytes()
            ext = cover_path.suffix.lower()
            media_type = {
                ".jpg": "image/jpeg", ".jpeg": "image/jpeg",
                ".png": "image/png",
            }.get(ext, "image/jpeg")
            book.set_cover("cover" + ext, cover_data)
            print(f"  Cover: {cover_path.name}")
        else:
            print(f"  Warning: Cover image not found: {args.cover}", file=sys.stderr)

    # CSS
    css = epub.EpubItem(
        uid="kindle_css",
        file_name="style/kindle.css",
        media_type="text/css",
        content=KINDLE_CSS,
    )
    book.add_item(css)

    spine = ["nav"]
    toc = []

    # --- Title page ---
    title_page = build_title_page(title, subtitle, author)
    book.add_item(title_page)
    spine.append(title_page)

    # --- Copyright page ---
    copyright_md = load_template(template_dir / "copyright-page.md")
    if copyright_md:
        html = convert_md_to_html(copyright_md)
        ch = make_epub_chapter("copyright.xhtml", "Copyright", html)
        book.add_item(ch)
        spine.append(ch)

    # --- Front matter ---
    front_md = load_template(template_dir / "front-matter.md")
    if front_md:
        html = convert_md_to_html(front_md)
        front_title = extract_title(front_md) or "Front Matter"
        ch = make_epub_chapter("front-matter.xhtml", front_title, html)
        book.add_item(ch)
        spine.append(ch)
        toc.append(ch)

    # --- Chapters ---
    chapters = discover_chapters(chapter_dir)
    if not chapters:
        print("Error: No chapters found.", file=sys.stderr)
        sys.exit(1)

    print(f"  Found {len(chapters)} chapter(s)")

    for slug, path in chapters:
        text = path.read_text(encoding="utf-8")
        ch_title = extract_title(text) or slug.title()
        html = convert_md_to_html(text)

        filename = f"{slug}.xhtml"
        ch = make_epub_chapter(filename, ch_title, html)
        book.add_item(ch)
        spine.append(ch)
        toc.append(ch)
        print(f"  Added: {path.name} → {ch_title}")

    # --- Back matter templates ---
    for template_name, epub_title in [
        ("back-matter.md", "Back Matter"),
        ("also-by.md", "Also by the Author"),
    ]:
        back_md = load_template(template_dir / template_name)
        if back_md:
            html = convert_md_to_html(back_md)
            fname = template_name.replace(".md", ".xhtml")
            ch = make_epub_chapter(fname, epub_title, html)
            book.add_item(ch)
            spine.append(ch)

    # --- Finalize ---
    book.toc = toc
    book.spine = spine
    book.add_item(epub.EpubNcx())
    book.add_item(epub.EpubNav())

    # Output
    if args.output:
        out_path = Path(args.output)
    else:
        out_path = export_dir / f"book{book_num}-kindle.epub"

    epub.write_epub(str(out_path), book, {})
    return out_path


# ---------------------------------------------------------------------------
# Checklist generation
# ---------------------------------------------------------------------------

def generate_checklist(book_num: int, epub_path: Path) -> Path:
    """Write a publishing checklist to notes/book{N}-kindle-publish-checklist.md."""
    notes_dir = ROOT / "notes"
    notes_dir.mkdir(parents=True, exist_ok=True)
    checklist_path = notes_dir / f"book{book_num}-kindle-publish-checklist.md"

    if checklist_path.exists():
        return checklist_path

    checklist = f"""\
# Kindle Publishing Checklist — Book {book_num}

Generated from `export_kindle.py`. Review and complete before uploading.

EPUB: `{epub_path.relative_to(ROOT)}`

---

## Front & Back Matter

- [ ] Copyright page — fill in year, pen name, legal text (`kindle/templates/copyright-page.md`)
- [ ] Dedication (optional) — add to front matter if desired
- [ ] Author\u2019s Note (optional) — add to back matter if desired
- [ ] \u201cAlso by the Author\u201d page — create `kindle/templates/also-by.md` when applicable
- [ ] Next book preview — append preview chapter to back matter when available

## Metadata

- [ ] Confirm pen name / author name
- [ ] Confirm book title and subtitle
- [ ] Write book description / blurb (for KDP listing)
- [ ] Choose KDP categories (2 allowed)
- [ ] Select 7 keywords for KDP search
- [ ] Set price (consider KU 70% royalty tier: $2.99\u2013$9.99)

## Cover Image

- [ ] Cover image ready (2560\u00d71600px recommended for Kindle)
- [ ] Cover passes KDP image quality checks
- [ ] Run `export_kindle.py --cover path/to/cover.jpg` to embed cover in EPUB

## Quality Checks

- [ ] Open EPUB in Kindle Previewer \u2014 check rendering on multiple devices
- [ ] Verify Table of Contents links work
- [ ] Verify chapter breaks (each chapter starts on new page)
- [ ] Verify scene breaks (`* * *`) are centered and styled
- [ ] Check smart quotes, em dashes, ellipses throughout
- [ ] Check first paragraphs are not indented after headings/scene breaks
- [ ] Proofread front and back matter
- [ ] Confirm no `[CONTINUITY FLAG]` markers remain in text

## Upload

- [ ] Log in to KDP (kdp.amazon.com)
- [ ] Create new Kindle eBook
- [ ] Upload EPUB manuscript
- [ ] Upload cover image
- [ ] Fill in metadata (title, description, categories, keywords)
- [ ] Set pricing and royalty
- [ ] Enroll in Kindle Unlimited (KDP Select)
- [ ] Preview and publish
"""

    checklist_path.write_text(checklist, encoding="utf-8")
    return checklist_path


# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------

def main():
    parser = argparse.ArgumentParser(
        description="Export chapter markdown to a Kindle-ready EPUB file.",
    )
    parser.add_argument(
        "--book", type=int, default=1,
        help="Book number (default: 1)",
    )
    parser.add_argument(
        "--output", "-o",
        help="Output EPUB path (default: kindle/exports/bookN-kindle.epub)",
    )
    parser.add_argument(
        "--title",
        help="Book title (default: The Floundry Affair)",
    )
    parser.add_argument(
        "--author",
        help="Author name (default: [Author Name])",
    )
    parser.add_argument(
        "--cover",
        help="Path to cover image (JPG or PNG)",
    )
    args = parser.parse_args()

    print(f"Building EPUB for Book {args.book}...")

    epub_path = build_epub(args)
    print(f"\nEPUB written: {epub_path}")

    checklist_path = generate_checklist(args.book, epub_path)
    print(f"Checklist written: {checklist_path}")


if __name__ == "__main__":
    main()
