"""Test runner — upload APK/URL, poll for completion, download report."""
from __future__ import annotations

import json
import sys
import time
from pathlib import Path

import httpx


async def run_test(
    target: str,
    api_key: str,
    persona: str = "curious",
    max_steps: int = 200,
    strategy: str = "ai",
    report_format: str = "html",
    output_path: str | None = None,
    server_url: str = "https://www.susatest.com",
    username: str | None = None,
    password: str | None = None,
    no_wait: bool = False,
):
    """Upload target, wait for completion, download report."""
    base_url = server_url.rstrip("/")
    headers = {"X-API-Key": api_key}

    is_web = target.startswith("http://") or target.startswith("https://")

    async with httpx.AsyncClient(
        base_url=base_url,
        headers=headers,
        timeout=httpx.Timeout(120, connect=10),
    ) as client:

        # ── Upload ──
        if is_web:
            print(f"[susatest] Testing web URL: {target}")
            print(f"[susatest] Persona: {persona} | Steps: {max_steps} | Strategy: {strategy}")

            data = {
                "test_url": target,
                "persona": persona,
                "max_steps": str(max_steps),
                "exploration_strategy": strategy,
            }
            if username and password:
                creds = json.dumps({"username": username, "password": password, "custom_fields": []})
                data["credentials"] = creds

            resp = await client.post("/api/upload-web", data=data)
        else:
            apk_path = Path(target)
            if not apk_path.exists():
                print(f"[susatest] File not found: {target}")
                sys.exit(1)
            if not apk_path.suffix == ".apk":
                print(f"[susatest] Not an APK file: {target}")
                sys.exit(1)

            size_mb = apk_path.stat().st_size / 1024 / 1024
            print(f"[susatest] Uploading: {apk_path.name} ({size_mb:.1f} MB)")
            print(f"[susatest] Persona: {persona} | Steps: {max_steps} | Strategy: {strategy}")

            data = {
                "persona": persona,
                "max_steps": str(max_steps),
                "exploration_strategy": strategy,
            }
            if username and password:
                creds = json.dumps({"username": username, "password": password, "custom_fields": []})
                data["credentials"] = creds

            files = {"file": (apk_path.name, apk_path.open("rb"), "application/vnd.android.package-archive")}
            resp = await client.post("/api/upload", data=data, files=files)

        if resp.status_code == 401:
            print("[susatest] Authentication failed. Check your API key.")
            sys.exit(1)
        if resp.status_code != 200:
            detail = resp.json().get("detail", resp.text) if resp.headers.get("content-type", "").startswith("application/json") else resp.text
            print(f"[susatest] Upload failed ({resp.status_code}): {detail}")
            sys.exit(1)

        session = resp.json()
        session_id = session["id"]
        print(f"[susatest] Session created: #{session_id}")
        print(f"[susatest] Dashboard: {base_url}/app/session/{session_id}")

        if no_wait:
            print(f"[susatest] Report will be at: {base_url}/api/sessions/{session_id}/report")
            return

        # ── Poll for completion ──
        print(f"[susatest] Exploring...", end="", flush=True)
        last_steps = 0
        start_time = time.monotonic()

        while True:
            await _sleep(5)
            resp = await client.get(f"/api/sessions/{session_id}")
            if resp.status_code != 200:
                print(f"\n[susatest] Failed to check status: {resp.status_code}")
                sys.exit(1)

            data = resp.json()
            status = data.get("status", "unknown")
            steps = data.get("total_steps", 0)
            screens = data.get("unique_screens", 0)
            issues = data.get("issues_found", 0)

            if steps > last_steps:
                elapsed = int(time.monotonic() - start_time)
                print(f"\r[susatest] Step {steps}/{max_steps} | {screens} screens | {issues} issues | {elapsed}s", end="", flush=True)
                last_steps = steps

            if status in ("completed", "stopped", "error", "failed"):
                print()
                break

        elapsed_total = int(time.monotonic() - start_time)
        print(f"[susatest] {status.upper()} in {elapsed_total}s — {steps} steps, {screens} screens, {issues} issues")

        # ── Download report ──
        if report_format == "html":
            endpoint = f"/api/sessions/{session_id}/report/html"
        elif report_format == "junit":
            endpoint = f"/api/sessions/{session_id}/report/junit"
        else:
            endpoint = f"/api/sessions/{session_id}/report"

        resp = await client.get(endpoint)
        if resp.status_code != 200:
            print(f"[susatest] Failed to download report: {resp.status_code}")
            sys.exit(1)

        # Determine output filename
        if output_path:
            out = Path(output_path)
        else:
            app_name = data.get("apk_filename", "app").replace(".apk", "")
            ext = {"html": ".html", "json": ".json", "junit": ".xml"}[report_format]
            out = Path(f"{app_name}_report{ext}")

        if report_format == "json":
            out.write_text(json.dumps(resp.json(), indent=2), encoding="utf-8")
        else:
            out.write_bytes(resp.content)

        print(f"[susatest] Report saved: {out}")
        print(f"[susatest] View online: {base_url}/app/session/{session_id}/report")


async def _sleep(seconds: float):
    """Async sleep wrapper."""
    import asyncio
    await asyncio.sleep(seconds)
