#!/usr/bin/env python3
"""
Integration test: slide-creator HTML → kai-html-export → PPTX

Tests the full export chain:
  1. Take a demo HTML generated by slide-creator
  2. Call kai-html-export/scripts/export-pptx.py (image mode)
  3. Call kai-html-export/scripts/export-pptx.py (native mode)
  4. Validate output PPTX: exists, non-empty, correct slide count

Run:
    python -m pytest tests/test_export_integration.py -v
    python -m pytest tests/test_export_integration.py -v -s   # show subprocess output

Environment:
    KAI_HTML_EXPORT_DIR  path to kai-html-export skill (default: ~/.claude/skills/kai-html-export)

Requirements:
    pip install python-pptx playwright beautifulsoup4 lxml
    playwright install chromium
"""

import os
import subprocess
import sys
import tempfile
from pathlib import Path

import pytest

# ─── Locate kai-html-export ──────────────────────────────────────────────────

KAI_EXPORT_DIR = Path(
    os.environ.get("KAI_HTML_EXPORT_DIR", Path.home() / ".claude/skills/kai-html-export")
)
EXPORT_SCRIPT = KAI_EXPORT_DIR / "scripts" / "export-pptx.py"

DEMOS_DIR = Path(__file__).parent.parent / "demos"

# Pick a small demo to keep the test fast
DEMO_CANDIDATES = sorted(DEMOS_DIR.glob("*.html"))


# ─── Fixtures ────────────────────────────────────────────────────────────────

@pytest.fixture(scope="session")
def export_script():
    if not EXPORT_SCRIPT.exists():
        pytest.skip(
            f"kai-html-export script not found at {EXPORT_SCRIPT}\n"
            f"Set KAI_HTML_EXPORT_DIR env var to the skill directory."
        )
    return EXPORT_SCRIPT


@pytest.fixture(scope="session")
def demo_html():
    if not DEMO_CANDIDATES:
        pytest.skip("No demo HTML files found in demos/")
    # Prefer a small demo for speed; fall back to the first available
    preferred = ["aurora-mesh.html", "enterprise-dark.html", "data-story.html"]
    for name in preferred:
        p = DEMOS_DIR / name
        if p.exists():
            return p
    return DEMO_CANDIDATES[0]


# ─── Helpers ─────────────────────────────────────────────────────────────────

def run_export(script: Path, html: Path, output: Path, mode: str) -> subprocess.CompletedProcess:
    """Run export-pptx.py and return the CompletedProcess."""
    cmd = [sys.executable, str(script), str(html), str(output), "--mode", mode]
    return subprocess.run(cmd, capture_output=True, text=True, timeout=120)


def slide_count_from_pptx(pptx_path: Path) -> int:
    """Return number of slides in a PPTX file."""
    try:
        from pptx import Presentation
        prs = Presentation(str(pptx_path))
        return len(prs.slides)
    except ImportError:
        pytest.skip("python-pptx not installed; cannot verify slide count")


def html_slide_count(html_path: Path) -> int:
    """Count .slide elements in source HTML."""
    try:
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(html_path.read_text(encoding="utf-8"), "html.parser")
        return len(soup.find_all(class_="slide"))
    except ImportError:
        return 0


# ─── Prerequisite check ──────────────────────────────────────────────────────

def test_export_script_exists(export_script):
    """kai-html-export script must exist at the expected path."""
    assert export_script.exists(), f"Script not found: {export_script}"


def test_export_script_importable(export_script):
    """export-pptx.py must be importable (syntax check)."""
    result = subprocess.run(
        [sys.executable, "-c", f"import ast; ast.parse(open('{export_script}').read())"],
        capture_output=True, text=True
    )
    assert result.returncode == 0, f"Syntax error in export-pptx.py:\n{result.stderr}"


def test_native_module_loadable(export_script):
    """export-native-pptx.py must load via importlib (the fixed import path)."""
    native_script = export_script.parent / "export-native-pptx.py"
    assert native_script.exists(), f"export-native-pptx.py not found at {native_script}"

    result = subprocess.run(
        [sys.executable, "-c",
         f"import importlib.util; "
         f"spec = importlib.util.spec_from_file_location('m', '{native_script}'); "
         f"mod = importlib.util.module_from_spec(spec); "
         f"spec.loader.exec_module(mod); "
         f"assert hasattr(mod, 'export_native'), 'export_native function missing'"],
        capture_output=True, text=True
    )
    assert result.returncode == 0, (
        f"Failed to load export-native-pptx.py via importlib:\n{result.stderr}"
    )


# ─── Export chain tests ───────────────────────────────────────────────────────

@pytest.mark.slow
def test_export_image_mode(export_script, demo_html, tmp_path):
    """slide-creator HTML → PPTX (image mode): file created, non-empty, correct slide count."""
    output = tmp_path / "out_image.pptx"
    result = run_export(export_script, demo_html, output, mode="image")

    assert result.returncode == 0, (
        f"export-pptx.py --mode image failed (exit {result.returncode})\n"
        f"stdout: {result.stdout}\nstderr: {result.stderr}"
    )
    assert output.exists(), "PPTX file was not created (image mode)"
    assert output.stat().st_size > 5_000, f"PPTX suspiciously small: {output.stat().st_size} bytes"

    expected = html_slide_count(demo_html)
    if expected > 0:
        actual = slide_count_from_pptx(output)
        assert actual == expected, (
            f"Slide count mismatch (image mode): HTML has {expected}, PPTX has {actual}"
        )


@pytest.mark.slow
def test_export_native_mode(export_script, demo_html, tmp_path):
    """slide-creator HTML → PPTX (native mode): file created, non-empty, correct slide count."""
    output = tmp_path / "out_native.pptx"
    result = run_export(export_script, demo_html, output, mode="native")

    assert result.returncode == 0, (
        f"export-pptx.py --mode native failed (exit {result.returncode})\n"
        f"stdout: {result.stdout}\nstderr: {result.stderr}"
    )
    assert output.exists(), "PPTX file was not created (native mode)"
    assert output.stat().st_size > 5_000, f"PPTX suspiciously small: {output.stat().st_size} bytes"

    expected = html_slide_count(demo_html)
    if expected > 0:
        actual = slide_count_from_pptx(output)
        assert actual == expected, (
            f"Slide count mismatch (native mode): HTML has {expected}, PPTX has {actual}"
        )


@pytest.mark.slow
def test_export_both_modes_independent(export_script, demo_html, tmp_path):
    """Both modes must succeed independently without interfering with each other."""
    out_image = tmp_path / "image.pptx"
    out_native = tmp_path / "native.pptx"

    r1 = run_export(export_script, demo_html, out_image, mode="image")
    r2 = run_export(export_script, demo_html, out_native, mode="native")

    assert r1.returncode == 0, f"image mode failed:\n{r1.stdout}\n{r1.stderr}"
    assert r2.returncode == 0, f"native mode failed:\n{r2.stdout}\n{r2.stderr}"
    assert out_image.exists() and out_native.exists()
    assert out_image.stat().st_size > 0
    assert out_native.stat().st_size > 0


# ─── Entry point ─────────────────────────────────────────────────────────────

if __name__ == "__main__":
    sys.exit(pytest.main([__file__, "-v", "-s"]))
