"""
Execute Playwright tests and capture artifacts.
"""

import subprocess
import json
import time
from pathlib import Path
from typing import Optional
from dataclasses import dataclass, field


@dataclass
class PlaywrightResult:
    """Result of a Playwright test execution."""
    test_id: str
    name: str
    status: str  # "passed", "failed", "skipped"
    duration: float
    error_message: Optional[str] = None
    traceback: Optional[str] = None
    artifacts: list[dict] = field(default_factory=list)


class PlaywrightRunner:
    """Run Playwright tests and collect artifacts."""

    def __init__(self, tests_dir: Path, artifacts_dir: Path):
        self.tests_dir = tests_dir
        self.artifacts_dir = artifacts_dir
        self.videos_dir = artifacts_dir / "videos"
        self.screenshots_dir = artifacts_dir / "screenshots"
        self.traces_dir = artifacts_dir / "traces"

        # Ensure artifact directories exist
        self.videos_dir.mkdir(parents=True, exist_ok=True)
        self.screenshots_dir.mkdir(parents=True, exist_ok=True)
        self.traces_dir.mkdir(parents=True, exist_ok=True)

    def run_tests(
        self,
        test_files: Optional[list[str]] = None,
        run_id: Optional[str] = None
    ) -> list[PlaywrightResult]:
        """
        Run Playwright tests and collect results.

        Args:
            test_files: List of test file paths to run (relative to tests_dir).
                       If None, runs all tests.
            run_id: Optional run ID to namespace artifacts.

        Returns:
            List of PlaywrightResult objects.
        """
        if not self.tests_dir.exists():
            return []

        # Build playwright command
        cmd = ["npx", "playwright", "test"]

        # Add specific test files if provided
        if test_files:
            cmd.extend(test_files)

        # Add reporter for JSON output
        results_file = self.artifacts_dir / f"results_{run_id or 'latest'}.json"
        cmd.extend([
            "--reporter=json",
            f"--output={results_file}"
        ])

        # Configure artifact collection
        # Videos and screenshots are configured in playwright.config.ts
        # We'll assume config is set to capture on failure

        # Run tests
        start_time = time.time()

        try:
            result = subprocess.run(
                cmd,
                cwd=self.tests_dir,
                capture_output=True,
                text=True,
                timeout=600  # 10 minute timeout
            )

            # Parse results
            if results_file.exists():
                with open(results_file) as f:
                    results_data = json.load(f)
                    return self._parse_results(results_data, run_id)
            else:
                # No results file - likely error
                return self._create_error_result(result.stderr)

        except subprocess.TimeoutExpired:
            return self._create_error_result("Tests timed out after 10 minutes")
        except Exception as e:
            return self._create_error_result(str(e))

    def _parse_results(
        self,
        results_data: dict,
        run_id: Optional[str]
    ) -> list[PlaywrightResult]:
        """Parse Playwright JSON results."""
        parsed_results = []

        # Playwright JSON reporter structure:
        # {
        #   "suites": [...],
        #   "tests": [...],
        # }

        tests = results_data.get("tests", [])

        for test in tests:
            test_id = test.get("testId", "unknown")
            title = test.get("title", "Unknown test")
            status = test.get("status", "unknown")  # passed, failed, skipped
            duration = test.get("duration", 0) / 1000.0  # Convert ms to seconds

            error_message = None
            traceback = None

            # Extract error if failed
            if status == "failed":
                error = test.get("error", {})
                error_message = error.get("message", "Test failed")
                traceback = error.get("stack", "")

            # Collect artifacts
            artifacts = []
            for attachment in test.get("attachments", []):
                artifact_type = attachment.get("contentType", "")
                artifact_path = attachment.get("path", "")

                if artifact_path:
                    artifact_file = Path(artifact_path)
                    if artifact_file.exists():
                        # Determine type
                        if "video" in artifact_type:
                            type_label = "video"
                        elif "image" in artifact_type:
                            type_label = "screenshot"
                        elif "trace" in artifact_type:
                            type_label = "trace"
                        else:
                            type_label = "attachment"

                        artifacts.append({
                            "type": type_label,
                            "filename": artifact_file.name,
                            "path": str(artifact_file),
                            "size": artifact_file.stat().st_size,
                            "mimetype": artifact_type,
                        })

            parsed_results.append(PlaywrightResult(
                test_id=test_id,
                name=title,
                status=status,
                duration=duration,
                error_message=error_message,
                traceback=traceback,
                artifacts=artifacts,
            ))

        return parsed_results

    def _create_error_result(self, error_msg: str) -> list[PlaywrightResult]:
        """Create an error result when test execution fails."""
        return [
            PlaywrightResult(
                test_id="playwright_error",
                name="Playwright Execution Error",
                status="failed",
                duration=0.0,
                error_message=error_msg,
                traceback="",
                artifacts=[],
            )
        ]

    def get_artifact_url(self, run_id: str, artifact_filename: str) -> str:
        """Generate URL for streaming an artifact."""
        return f"/tools/tester/api/artifact/{run_id}/{artifact_filename}"
