"""Utility functions for screenshot coordinator.

These utilities are copied from screenshot package internals to avoid
coupling to private APIs. They should be kept in sync with upstream
or replaced when public APIs become available.
"""

import hashlib
from typing import Any
from urllib.parse import urlparse

from screenshot import ScreenshotOptions


def ensure_capture_enabled(options: ScreenshotOptions) -> ScreenshotOptions:
    """Ensure capture is enabled in screenshot options.

    Args:
        options: Screenshot options to check.

    Returns:
        Modified options with capture enabled, or original if already enabled.

    Example:
        >>> opts = ScreenshotOptions()
        >>> opts = ensure_capture_enabled(opts)
        >>> assert opts.capture.enabled is True
    """
    if options.capture.enabled:
        return options

    # Create new options with capture enabled
    import dataclasses

    new_capture = dataclasses.replace(options.capture, enabled=True)
    return dataclasses.replace(options, capture=new_capture)


def derive_job_id(url: str, fallback: str = "job") -> str:
    """Derive a job identifier from a URL.

    Uses the URL's netloc (domain) as the base, with a hash suffix for uniqueness.

    Args:
        url: URL to derive job ID from.
        fallback: Fallback prefix if URL parsing fails.

    Returns:
        Job identifier string (e.g., "example-com-abc123").

    Example:
        >>> job_id = derive_job_id("https://example.com/page")
        >>> assert job_id.startswith("example-com-")
    """
    try:
        parsed = urlparse(url)
        netloc = parsed.netloc or fallback
        # Sanitize netloc for use in job IDs
        sanitized = netloc.replace(":", "-").replace(".", "-")

        # Add hash for uniqueness
        url_hash = hashlib.md5(url.encode()).hexdigest()[:8]
        return f"{sanitized}-{url_hash}"
    except Exception:
        # Fallback to hash-only ID
        url_hash = hashlib.md5(url.encode()).hexdigest()[:12]
        return f"{fallback}-{url_hash}"


def normalize_options_payload(payload: dict[str, Any]) -> dict[str, Any]:
    """Normalize screenshot options payload from various formats.

    Ensures the payload has the proper nested structure expected by
    ScreenshotOptions.from_dict().

    Args:
        payload: Raw options dictionary from user input.

    Returns:
        Normalized dictionary with proper nesting.

    Example:
        >>> payload = {"capture": {"enabled": True}}
        >>> normalized = normalize_options_payload(payload)
        >>> assert "capture" in normalized
    """
    # If already properly structured, return as-is
    if any(key in payload for key in ("capture", "browser", "runner")):
        return payload

    # Otherwise, wrap flat options in appropriate sections
    # This is a simplified version - expand based on actual needs
    return {"capture": {"enabled": True}, **payload}


def serialize_options(options: ScreenshotOptions) -> dict[str, Any]:
    """Serialize screenshot options to JSON-compatible dict.

    Args:
        options: Screenshot options to serialize.

    Returns:
        Dictionary representation suitable for JSON serialization.

    Example:
        >>> opts = ScreenshotOptions()
        >>> payload = serialize_options(opts)
        >>> assert isinstance(payload, dict)
    """
    import dataclasses
    from pathlib import Path

    def serialize_value(value: Any) -> Any:
        """Recursively serialize values to JSON-compatible types."""
        if value is None:
            return None
        if isinstance(value, (str, int, float, bool)):
            return value
        if isinstance(value, Path):
            return str(value)
        if isinstance(value, (list, tuple)):
            return [serialize_value(item) for item in value]
        if isinstance(value, dict):
            return {k: serialize_value(v) for k, v in value.items()}
        if dataclasses.is_dataclass(value):
            return {field.name: serialize_value(getattr(value, field.name)) for field in dataclasses.fields(value)}
        # Fallback: convert to string
        return str(value)

    result: dict[str, Any] = serialize_value(options)
    return result
