"""
extract_story_text.py
Extrae el texto de los PDFs dentro de los ZIPs y actualiza notes_markdown
en la base de datos via course_map.json + artisan raio:import.

Formato del PDF:
  RAIO Interactive Stories
  Story N, Chapter N
  Topic
  Normal:
  ... texto normal ...
  Interactive:
  ... texto interactivo con preguntas ...
  IMPORTANT: You may continue...
"""
import json
import re
import sys
import zipfile
import io
from pathlib import Path

sys.stdout.reconfigure(encoding="utf-8")

try:
    import fitz  # PyMuPDF
except ImportError:
    print("Instala PyMuPDF: pip install pymupdf")
    sys.exit(1)

SCRIPTS_DIR  = Path(__file__).parent
BASE_DIR     = SCRIPTS_DIR.parent
DOCS_DIR     = BASE_DIR / "storage" / "app" / "course-media" / "curso-de-ingles-raio" / "docs"
CONTENT_FILE = SCRIPTS_DIR / "course_content.json"
MAP_FILE     = SCRIPTS_DIR / "course_map.json"


def extract_pdf_text(zip_path: Path) -> str | None:
    """Extract text from the first PDF in a ZIP file."""
    try:
        with zipfile.ZipFile(zip_path) as z:
            pdfs = [
                n for n in z.namelist()
                if n.lower().endswith(".pdf") and not n.startswith("__MACOSX")
            ]
            if not pdfs:
                return None
            pdf_data = z.read(pdfs[0])

        doc = fitz.open(stream=pdf_data, filetype="pdf")
        pages = []
        for page in doc:
            pages.append(page.get_text())
        doc.close()
        return "\n".join(pages).strip()
    except Exception as e:
        print(f"  Error leyendo {zip_path.name}: {e}", flush=True)
        return None


def extract_title_from_pdf(raw: str) -> str | None:
    """Extract the topic title from the PDF header (3rd meaningful line)."""
    skip_patterns = [
        r"^RAIO Interactive Stories",
        r"^Story \d+",
        r"^Chapter \d+",
        r"^Story \d+, Chapter \d+",
    ]
    for line in raw.splitlines():
        stripped = line.strip()
        if not stripped:
            continue
        if any(re.match(p, stripped, re.I) for p in skip_patterns):
            continue
        if re.match(r"^(Normal|Interactive)\s*:", stripped, re.I):
            return None
        return stripped  # First non-header, non-blank line = topic title
    return None


def pdf_text_to_markdown(raw: str, title: str) -> str:
    """Convert raw PDF text to readable markdown."""
    # Try to get better title from PDF itself
    pdf_title = extract_title_from_pdf(raw)
    display_title = pdf_title if pdf_title else title

    lines = [l.rstrip() for l in raw.splitlines()]

    # Remove header lines (title block at top of PDF)
    clean = []
    skip_patterns = [
        r"^RAIO Interactive Stories",
        r"^Story \d+",
        r"^Chapter \d+",
        r"^Story \d+, Chapter \d+",
    ]
    title_skipped = False
    for line in lines:
        stripped = line.strip()
        if any(re.match(p, stripped, re.I) for p in skip_patterns):
            continue
        # Skip the topic title line (already used as heading)
        if not title_skipped and stripped == display_title:
            title_skipped = True
            continue
        # Remove the trailing IMPORTANT notice
        if stripped.startswith("IMPORTANT: You may continue"):
            break
        clean.append(line)

    # Split into Normal and Interactive sections
    normal_lines = []
    interactive_lines = []
    current = None

    for line in clean:
        stripped = line.strip()
        if re.match(r'^Normal\s*:', stripped, re.I):
            current = "normal"
            continue
        if re.match(r'^Interactive\s*:', stripped, re.I):
            current = "interactive"
            continue
        if current == "normal":
            normal_lines.append(line)
        elif current == "interactive":
            interactive_lines.append(line)

    # If no section markers, treat all as normal text
    if not normal_lines and not interactive_lines:
        normal_lines = clean

    def lines_to_paragraphs(ls: list[str]) -> str:
        text = "\n".join(ls).strip()
        # Collapse multiple blank lines
        text = re.sub(r"\n{3,}", "\n\n", text)
        return text

    md = f"## {display_title}\n\n"

    if normal_lines:
        md += "### Normal version\n\n"
        md += lines_to_paragraphs(normal_lines) + "\n\n"

    if interactive_lines:
        md += "### Interactive version\n\n"
        # Format YES/NO questions — highlight brackets
        formatted = []
        for line in interactive_lines:
            # Bold the [YES/NO] or [YES] or [NO] markers
            line = re.sub(r'\[(YES(?:/NO)?|NO)\]', r'**[\1]**', line)
            formatted.append(line)
        md += lines_to_paragraphs(formatted) + "\n\n"

    return md.strip()


def main():
    if not CONTENT_FILE.exists():
        print("No encontré course_content.json")
        sys.exit(1)

    content = json.loads(CONTENT_FILE.read_text(encoding="utf-8"))

    updated = 0
    skipped = 0
    errors  = 0

    for lesson in content:
        num = lesson["num"]

        # Find the local ZIP for this lesson
        doc_urls = lesson.get("doc_urls", [])
        zip_local = None
        for doc in doc_urls:
            lp = doc.get("local_path", "")
            if lp and lp.endswith(".zip"):
                zip_local = lp
                break

        if not zip_local:
            skipped += 1
            continue

        # Resolve to absolute path
        zip_path = BASE_DIR / "public" / zip_local if zip_local.startswith("media/") else BASE_DIR / zip_local
        if not zip_path.exists():
            # Try docs dir directly
            zip_path = DOCS_DIR / Path(zip_local).name
        if not zip_path.exists():
            skipped += 1
            continue

        raw_text = extract_pdf_text(zip_path)
        if not raw_text:
            errors += 1
            continue

        # Get title from existing notes or lesson
        existing_title = lesson.get("title", f"Lección {num}")
        md = pdf_text_to_markdown(raw_text, existing_title)

        lesson["notes"] = md
        updated += 1
        print(f"  [{num:2d}] Extraído: {len(md)} chars — {zip_path.name[:50]}", flush=True)

    # Save back to content file
    CONTENT_FILE.write_text(
        json.dumps(content, ensure_ascii=False, indent=2),
        encoding="utf-8"
    )

    print(f"\nActualizados: {updated} | Sin ZIP: {skipped} | Errores: {errors}")
    print("Ahora ejecuta:")
    print("  python build_course_map.py")
    print("  php artisan raio:import --force")


if __name__ == "__main__":
    main()
