"""Base classes for screen capture engines."""

from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Any, Dict, List, Optional

import numpy as np


@dataclass
class DisplayInfo:
    """Information about a display/monitor."""

    index: int
    name: str
    width: int
    height: int
    x: int
    y: int
    is_primary: bool
    refresh_rate: int


@dataclass
class ScreenCapture:
    """Captured screen image data."""

    image: np.ndarray
    width: int
    height: int
    display_index: int


class CaptureStream(ABC):
    """Abstract base class for a display capture session.

    A CaptureStream is a stateful session bound to a specific display.
    It holds all display-specific resources and provides frame capture.

    Created by CaptureEngine.create_stream().

    Lifecycle:
        stream = engine.create_stream(display_index, config)
        stream.initialize()
        frame = stream.capture_frame()
        stream.cleanup()

    Or via context manager:
        with engine.create_stream(display_index, config) as stream:
            frame = stream.capture_frame()
    """

    def __init__(self, display_index: int, config: Dict[str, Any]):
        self.display_index = display_index
        self.config = config
        self._initialized = False

    @abstractmethod
    def initialize(self) -> None:
        """Initialize capture resources for this display.

        Raises:
            RuntimeError: If initialization fails
        """
        pass

    @abstractmethod
    def cleanup(self) -> None:
        """Release all capture resources for this display."""
        pass

    @abstractmethod
    def capture_frame(self) -> Optional[ScreenCapture]:
        """Capture one frame from the bound display.

        Returns:
            ScreenCapture with image data (RGB), or None if screen unchanged.

        Raises:
            RuntimeError: If capture fails
        """
        pass

    def __enter__(self):
        """Context manager entry - initialize stream."""
        self.initialize()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """Context manager exit - cleanup stream."""
        self.cleanup()


class CaptureEngine(ABC):
    """Abstract base class for screen capture engines.

    A CaptureEngine is a stateless factory that knows about a capture
    technology. It can enumerate displays, check availability, and create
    CaptureStream instances for specific displays.

    All methods are classmethods — no instance creation needed.
    """

    ENGINE_TYPE: str = "base"
    ENGINE_PRIORITY: int = 0
    HAS_OWN_DISPLAYS: bool = False  # True for engines with non-desktop device lists

    @classmethod
    @abstractmethod
    def is_available(cls) -> bool:
        """Check if this engine is available on current system."""
        pass

    @classmethod
    @abstractmethod
    def get_default_config(cls) -> Dict[str, Any]:
        """Get default configuration for this engine."""
        pass

    @classmethod
    @abstractmethod
    def get_available_displays(cls) -> List[DisplayInfo]:
        """Get list of available displays.

        This method works without prior initialization — implementations
        create temporary resources as needed.

        Returns:
            List of DisplayInfo objects describing available displays

        Raises:
            RuntimeError: If unable to detect displays
        """
        pass

    @classmethod
    @abstractmethod
    def create_stream(cls, display_index: int, config: Dict[str, Any]) -> CaptureStream:
        """Create a capture stream for the specified display.

        Args:
            display_index: Index of display to capture (0-based)
            config: Engine-specific configuration dict

        Returns:
            Uninitialized CaptureStream. Caller must call initialize()
            or use as context manager.
        """
        pass
