"""
Capture screenshots of EMOM and TABATA combo timers in Execution Mode,
including the TABATA rest screen — not covered by all_pages.py (which only
seeds an AMRAP combo).

The app is driven in English by default (use --lang fr for French
screenshots) with a seeded database so each screenshot shows meaningful
content rather than empty states.

Intended for visual investigations and documentation figures — not a test.

Prerequisites:
    - Playwright for Python installed (see `tests/requirements.txt`)
    - Playwright browsers installed: `python -m playwright install firefox chromium`
    - Vite dev server running: `npm run dev -- --port 5199 --strictPort`

Usage (from project root):

    python scripts/screenshots/combo_timers.py
    python scripts/screenshots/combo_timers.py --browser chromium
    python scripts/screenshots/combo_timers.py --lang fr
    python scripts/screenshots/combo_timers.py --out-dir /tmp/screenshots

Options:

    --url URL        App URL (default: http://localhost:5199)
    --browser NAME   firefox | chromium | webkit (default: firefox)
    --lang LANG      en | fr (default: en)
    --width N        Viewport width in px (default: 1920)
    --height N       Viewport height in px (default: 1080)
    --out-dir PATH   Output directory (default: tmp/screenshots/combo-timers-<lang>-<browser>-<W>x<H>)

Exit code: 0 on success, 1 on failure.
"""

from __future__ import annotations

import argparse
import os
import sys
import time
import traceback
from pathlib import Path

from playwright.sync_api import Page, sync_playwright


# ---------------------------------------------------------------------------
# Seed helpers
# ---------------------------------------------------------------------------

# TABATA work/rest kept short (6s / 5s) so the script doesn't have to wait
# long to reach the rest screen.
_SEED_SCRIPT = """
async () => {
    const uuid = await window.__repos.settings.get('user_uuid');

    const ex1 = await window.__repos.exercises.create({
        title: 'Jumping Jacks',
        description: 'Cardio warm-up movement.',
        asymmetric: false, alternate: false, image_urls: [], video_urls: [],
        default_reps: 20, default_weight: 0, created_by: uuid
    });
    const ex2 = await window.__repos.exercises.create({
        title: 'Mountain Climbers',
        description: 'Core and cardio movement.',
        asymmetric: false, alternate: false, image_urls: [], video_urls: [],
        default_reps: 20, default_weight: 0, created_by: uuid
    });

    // ── EMOM combo — work phase is always a 60s slot per exercise ─────────
    const emomComboId = await window.__repos.combos.create({
        title: 'EMOM Cardio', description: '3-minute EMOM.',
        type: 'EMOM', timer_config: {}, created_by: uuid
    });
    await window.__repos.combos.setExercises(emomComboId, [
        { exerciseId: ex1, position: 0, defaultReps: 20, defaultWeight: 0 }
    ]);
    const emomSessId = await window.__repos.sessions.create({
        title: 'EMOM Session', description: '', created_by: uuid
    });
    await window.__repos.sessions.setItems(emomSessId, [
        { item_id: emomComboId, item_type: 'combo', repetitions: 3, weight: 0.0 }
    ]);

    // ── TABATA combo ────────────────────────────────────────────────────
    const tabataComboId = await window.__repos.combos.create({
        title: 'TABATA Blast', description: 'Work/rest intervals.',
        type: 'TABATA', timer_config: { workTime: 6, restTime: 5 }, created_by: uuid
    });
    await window.__repos.combos.setExercises(tabataComboId, [
        { exerciseId: ex1, position: 0, defaultReps: 0, defaultWeight: 0 },
        { exerciseId: ex2, position: 1, defaultReps: 0, defaultWeight: 0 }
    ]);
    const tabataSessId = await window.__repos.sessions.create({
        title: 'TABATA Session', description: '', created_by: uuid
    });
    await window.__repos.sessions.setItems(tabataSessId, [
        { item_id: tabataComboId, item_type: 'combo', repetitions: 4, weight: 0.0 }
    ]);

    return { emomSessId, tabataSessId };
}
"""

_COUNT_SCRIPT = """
async () => (await window.__repos.exercises.getAll()).length
"""


def wait_for_db(page: Page, url: str) -> None:
    page.goto(url)
    page.wait_for_function(
        "document.documentElement.getAttribute('data-db-ready') === 'true'",
        timeout=15000,
    )


def ensure_language(page: Page, lang: str) -> None:
    current = page.evaluate("async () => window.__repos.settings.get('language')")
    if current != lang:
        page.evaluate(f"async () => window.__repos.settings.set('language', '{lang}')")
        page.reload()
        page.wait_for_function(
            "document.documentElement.getAttribute('data-db-ready') === 'true'",
            timeout=15000,
        )


def has_data(page: Page) -> bool:
    return page.evaluate(_COUNT_SCRIPT) > 0


# ---------------------------------------------------------------------------
# Screenshot helpers
# ---------------------------------------------------------------------------

def shot(page: Page, out_dir: Path, name: str, full_page: bool = True) -> None:
    time.sleep(0.3)
    path = out_dir / f"{name}.png"
    page.screenshot(path=str(path), full_page=full_page)
    print(f"  ✓  {path.name}")


def goto(page: Page, url: str, route: str, wait_selector: str | None = None) -> None:
    page.goto(f"{url}/#/{route}", wait_until="domcontentloaded")
    if wait_selector:
        page.wait_for_selector(wait_selector, timeout=8000)
    else:
        time.sleep(0.3)


# ---------------------------------------------------------------------------
# Main capture flow
# ---------------------------------------------------------------------------

def capture(page: Page, url: str, out_dir: Path, lang: str) -> None:
    wait_for_db(page, url)
    ensure_language(page, lang)

    if not has_data(page):
        print("  Seeding database…")
        ids = page.evaluate(_SEED_SCRIPT)
        print("  Seed complete.")
    else:
        raise RuntimeError("DB already has data — start with a fresh browser context")

    # ── EMOM — work phase starts immediately ───────────────────────────────
    goto(page, url, f"sessions/{ids['emomSessId']}/execute", '[data-testid="execute-timer"]')
    shot(page, out_dir, "combo-emom")

    # ── TABATA — work phase ─────────────────────────────────────────────
    # Navigate away first so Vue Router remounts SessionExecuteView (it reuses
    # the component when only params change, see all_pages.py for the same
    # workaround).
    goto(page, url, "sessions", '[data-testid="session-new-btn"]')
    goto(page, url, f"sessions/{ids['tabataSessId']}/execute", '[data-testid="execute-timer"]')
    shot(page, out_dir, "combo-tabata-work")

    # ── TABATA — rest phase (work duration is 6s in the seed above) ────────
    page.wait_for_selector('[data-testid="execute-tabata-rest"]', timeout=12000)
    shot(page, out_dir, "combo-tabata-rest")


# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------

def parse_args(argv: list[str]) -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument("--url", default=os.environ.get("APP_URL", "http://localhost:5199"))
    parser.add_argument("--browser", default="firefox", choices=["firefox", "chromium", "webkit"])
    parser.add_argument("--lang", default="en", choices=["en", "fr"])
    parser.add_argument("--width", type=int, default=1920)
    parser.add_argument("--height", type=int, default=1080)
    parser.add_argument("--out-dir", default=None)
    return parser.parse_args(argv)


def default_out_dir(browser: str, lang: str, width: int, height: int) -> Path:
    project_root = Path(__file__).resolve().parents[2]
    prefix = f"combo-timers-{browser}" if lang == "en" else f"combo-timers-{lang}-{browser}"
    return project_root / "tmp" / "screenshots" / f"{prefix}-{width}x{height}"


def main(argv: list[str] | None = None) -> int:
    args = parse_args(argv or sys.argv[1:])
    out_dir = (
        Path(args.out_dir)
        if args.out_dir
        else default_out_dir(args.browser, args.lang, args.width, args.height)
    )
    out_dir.mkdir(parents=True, exist_ok=True)

    print(f"\n── {args.browser}  {args.width}×{args.height}  →  {out_dir}")

    with sync_playwright() as p:
        browser_type = getattr(p, args.browser)
        browser = browser_type.launch(headless=True)
        try:
            context = browser.new_context(viewport={"width": args.width, "height": args.height})
            page = context.new_page()
            page.on("dialog", lambda dialog: dialog.accept())
            capture(page, args.url, out_dir, args.lang)
            count = len(list(out_dir.glob("*.png")))
            print(f"\n  Done — {count} screenshots saved")
        except Exception as exc:
            print(f"\n  ERROR: {exc}", file=sys.stderr)
            traceback.print_exc()
            return 1
        finally:
            browser.close()

    return 0


if __name__ == "__main__":
    sys.exit(main())
