#!/usr/bin/env python3
"""
chunk-pdf-docs.py - Break large PDF documentation into bite-sized markdown chunks

Extracts text from large PDFs and splits them into manageable sections for easier
processing and documentation. Designed for YMCS API documentation PDFs.

Usage:
    python3 chunk-pdf-docs.py <input.pdf> [--output-dir <dir>] [--pages-per-chunk <n>]
    python3 chunk-pdf-docs.py --all  # Process all YMCS PDFs in Downloads

Options:
    --output-dir PATH       Output directory for chunks (default: ./docs/chunks/)
    --pages-per-chunk N     Pages per chunk (default: 25)
    --all                   Process all YMCS PDFs from Downloads folder
    --toc-only              Extract just the table of contents
    --help                  Show this help
"""

import sys
import os
import re
from pathlib import Path

def extract_text_with_pdftotext(pdf_path, page_start=None, page_end=None):
    """Extract text using pdftotext (poppler-utils)"""
    import subprocess

    cmd = ['pdftotext', '-layout', '-nopgbrk']

    if page_start and page_end:
        cmd.extend(['-f', str(page_start), '-l', str(page_end)])

    cmd.extend([str(pdf_path), '-'])

    try:
        result = subprocess.run(cmd, capture_output=True, text=True, check=True)
        return result.stdout
    except subprocess.CalledProcessError as e:
        print(f"[ERROR] pdftotext failed: {e}", file=sys.stderr)
        return None
    except FileNotFoundError:
        print("[ERROR] pdftotext not found. Install with: brew install poppler", file=sys.stderr)
        return None

def get_pdf_page_count(pdf_path):
    """Get total page count using pdfinfo"""
    import subprocess

    try:
        result = subprocess.run(['pdfinfo', str(pdf_path)],
                              capture_output=True, text=True, check=True)
        for line in result.stdout.split('\n'):
            if line.startswith('Pages:'):
                return int(line.split(':')[1].strip())
        return None
    except:
        return None

def sanitize_filename(name):
    """Convert section name to safe filename"""
    name = re.sub(r'[^\w\s-]', '', name.lower())
    name = re.sub(r'[-\s]+', '-', name)
    return name.strip('-')

def extract_toc(pdf_path):
    """Extract table of contents from first 20 pages"""
    text = extract_text_with_pdftotext(pdf_path, 1, 20)
    if not text:
        return []

    # Look for common TOC patterns
    toc_entries = []
    in_toc = False

    for line in text.split('\n'):
        line = line.strip()

        # Start of TOC markers
        if re.match(r'table\s+of\s+contents', line, re.I):
            in_toc = True
            continue

        # End of TOC markers
        if in_toc and (line.startswith('Chapter') or line.startswith('1 ') or line.startswith('1.')):
            in_toc = False

        # Extract TOC entries (line ending with page number)
        if in_toc:
            match = re.match(r'^(.+?)\s+\.{2,}\s*(\d+)$', line)
            if match:
                title, page = match.groups()
                toc_entries.append({'title': title.strip(), 'page': int(page)})

    return toc_entries

def chunk_pdf(pdf_path, output_dir, pages_per_chunk=25):
    """Break PDF into chunks"""
    pdf_path = Path(pdf_path)
    output_dir = Path(output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)

    # Get total pages
    total_pages = get_pdf_page_count(pdf_path)
    if not total_pages:
        print(f"[ERROR] Could not determine page count for {pdf_path.name}")
        return False

    print(f"[INFO] Processing {pdf_path.name} ({total_pages} pages)")

    # Extract TOC
    print("[INFO] Extracting table of contents...")
    toc = extract_toc(pdf_path)
    if toc:
        toc_path = output_dir / f"{pdf_path.stem}-TOC.md"
        with open(toc_path, 'w') as f:
            f.write(f"# Table of Contents - {pdf_path.name}\n\n")
            for entry in toc:
                f.write(f"- Page {entry['page']}: {entry['title']}\n")
        print(f"[OK] Saved TOC to {toc_path.name} ({len(toc)} entries)")

    # Create chunks
    chunk_num = 1
    page_start = 1

    while page_start <= total_pages:
        page_end = min(page_start + pages_per_chunk - 1, total_pages)

        print(f"[INFO] Extracting chunk {chunk_num} (pages {page_start}-{page_end})...")

        text = extract_text_with_pdftotext(pdf_path, page_start, page_end)

        if text:
            chunk_path = output_dir / f"{pdf_path.stem}-chunk-{chunk_num:02d}-p{page_start}-{page_end}.md"

            with open(chunk_path, 'w') as f:
                f.write(f"# {pdf_path.name} - Pages {page_start}-{page_end}\n\n")
                f.write(f"**Source:** {pdf_path.name}\n")
                f.write(f"**Pages:** {page_start}-{page_end} of {total_pages}\n")
                f.write(f"**Chunk:** {chunk_num}\n\n")
                f.write("---\n\n")
                f.write(text)

            print(f"[OK] Saved {chunk_path.name}")
        else:
            print(f"[WARNING] Failed to extract chunk {chunk_num}")

        page_start = page_end + 1
        chunk_num += 1

    print(f"[OK] Created {chunk_num - 1} chunks in {output_dir}")
    return True

def process_all_ymcs_pdfs(output_base_dir, pages_per_chunk):
    """Process all YMCS PDFs from Downloads"""
    downloads = Path.home() / 'Downloads'

    pdfs = [
        downloads / 'Open API for Yealink Management Cloud Service V4X.pdf',
        downloads / 'YMCS 4X Enterprise Open API Webhook.pdf',
        downloads / 'Yealink Management Cloud Service(YMCS)_User Guide.pdf',
        downloads / 'Yealink Management Cloud Service(YMCS)_Channel User Guide.pdf',
    ]

    for pdf in pdfs:
        if not pdf.exists():
            print(f"[WARNING] Not found: {pdf.name}")
            continue

        # Create subdirectory for each PDF
        pdf_output_dir = Path(output_base_dir) / sanitize_filename(pdf.stem)

        print(f"\n{'='*70}")
        print(f"Processing: {pdf.name}")
        print(f"Output: {pdf_output_dir}")
        print(f"{'='*70}\n")

        chunk_pdf(pdf, pdf_output_dir, pages_per_chunk)

def main():
    import argparse

    parser = argparse.ArgumentParser(
        description='Break large PDF documentation into bite-sized chunks',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=__doc__
    )

    parser.add_argument('pdf', nargs='?', help='PDF file to process')
    parser.add_argument('--output-dir', default='./docs/chunks',
                       help='Output directory (default: ./docs/chunks)')
    parser.add_argument('--pages-per-chunk', type=int, default=25,
                       help='Pages per chunk (default: 25)')
    parser.add_argument('--all', action='store_true',
                       help='Process all YMCS PDFs from Downloads')
    parser.add_argument('--toc-only', action='store_true',
                       help='Extract just table of contents')

    args = parser.parse_args()

    if args.all:
        skill_dir = Path(__file__).parent.parent
        output_dir = skill_dir / 'docs' / 'chunks'
        process_all_ymcs_pdfs(output_dir, args.pages_per_chunk)
    elif args.pdf:
        pdf_path = Path(args.pdf)
        if not pdf_path.exists():
            print(f"[ERROR] File not found: {pdf_path}")
            sys.exit(1)

        if args.toc_only:
            toc = extract_toc(pdf_path)
            if toc:
                print(f"\nTable of Contents ({len(toc)} entries):\n")
                for entry in toc:
                    print(f"  Page {entry['page']:4d}: {entry['title']}")
            else:
                print("[WARNING] No TOC found")
        else:
            chunk_pdf(pdf_path, args.output_dir, args.pages_per_chunk)
    else:
        parser.print_help()
        sys.exit(1)

if __name__ == '__main__':
    main()
