"""Public runtime backends for local screenshot execution."""

from __future__ import annotations

from ._shared.errors import make_error
from ._shared.storage import LocalStorageBackend, StorageBackend
from .models import ScreenshotCaptureResult, ScreenshotJob
from .playwright_runner import capture_screenshots_async as playwright_capture_async
from .selenium_runner import capture_screenshots_async as selenium_capture_async
from .service import ScreenshotBackend, ScreenshotService

__all__ = [
    "PlaywrightScreenshotBackend",
    "SeleniumScreenshotBackend",
    "build_local_screenshot_service",
]


class PlaywrightScreenshotBackend(ScreenshotBackend[ScreenshotCaptureResult]):
    """Screenshot backend that uses the bundled Playwright runner."""

    def __init__(self, *, storage: StorageBackend | None = None) -> None:
        self._storage = storage or LocalStorageBackend()

    async def run_job_async(self, job: ScreenshotJob) -> ScreenshotCaptureResult:
        result = await playwright_capture_async(
            job.job_id,
            job.url,
            store_dir=job.output_root,
            partition_date=job.partition_date,
            options=job.options,
            job_metadata=dict(job.metadata),
            artifacts=job.artifacts,
            cancel_token=job.cancel_token,
            storage=self._storage,
        )
        if result.job_id is None:
            result.job_id = job.job_id
        return result


class SeleniumScreenshotBackend(ScreenshotBackend[ScreenshotCaptureResult]):
    """Screenshot backend powered by Selenium + Chromium."""

    def __init__(self, *, storage: StorageBackend | None = None) -> None:
        self._storage = storage or LocalStorageBackend()

    async def run_job_async(self, job: ScreenshotJob) -> ScreenshotCaptureResult:
        if job.artifacts.motion_snapshot is not None:
            return ScreenshotCaptureResult(
                requested=0,
                captured=0,
                failed=0,
                metadata_path=None,
                entries=[],
                errors=[
                    make_error(
                        "validation",
                        "Selenium backend does not support motion snapshots",
                        retryable=False,
                    )
                ],
                job_id=job.job_id,
            )
        result = await selenium_capture_async(
            job.job_id,
            job.url,
            store_dir=job.output_root,
            partition_date=job.partition_date,
            options=job.options,
            job_metadata=dict(job.metadata),
            artifacts=job.artifacts,
            cancel_token=job.cancel_token,
            storage=self._storage,
        )
        if result.job_id is None:
            result.job_id = job.job_id
        return result


def build_local_screenshot_service(
    *,
    concurrency: int = 1,
    storage: StorageBackend | None = None,
    backend: str = "playwright",
) -> ScreenshotService[ScreenshotCaptureResult]:
    """Return a ScreenshotService backed by the requested engine."""

    backend_name = (backend or "playwright").strip().lower()
    backend_impl: ScreenshotBackend[ScreenshotCaptureResult]
    if backend_name == "selenium":
        backend_impl = SeleniumScreenshotBackend(storage=storage)
    elif backend_name == "playwright":
        backend_impl = PlaywrightScreenshotBackend(storage=storage)
    else:
        raise ValueError(f"Unsupported backend '{backend}'")
    return ScreenshotService(backend_impl, concurrency=concurrency)
