"""Stash client module."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from ..logging import client_logger
from .base import StashClientBase
from .mixins.config import ConfigClientMixin
from .mixins.file import FileClientMixin
from .mixins.filter import FilterClientMixin
from .mixins.gallery import GalleryClientMixin
from .mixins.group import GroupClientMixin
from .mixins.image import ImageClientMixin
from .mixins.jobs import JobsClientMixin
from .mixins.marker import MarkerClientMixin
from .mixins.metadata import MetadataClientMixin
from .mixins.not_implemented import NotImplementedClientMixin
from .mixins.package import PackageClientMixin
from .mixins.performer import PerformerClientMixin
from .mixins.plugin import PluginClientMixin
from .mixins.scene import SceneClientMixin
from .mixins.scraper import ScraperClientMixin
from .mixins.studio import StudioClientMixin
from .mixins.subscription import SubscriptionClientMixin
from .mixins.system_query import SystemQueryClientMixin
from .mixins.tag import TagClientMixin
from .mixins.version import VersionClientMixin
from .utils import sanitize_model_data


if TYPE_CHECKING:
    from ..capabilities import ServerCapabilities


class StashClient(
    StashClientBase,  # Base class first to provide execute()
    ConfigClientMixin,
    FileClientMixin,
    FilterClientMixin,
    GalleryClientMixin,
    GroupClientMixin,
    ImageClientMixin,
    JobsClientMixin,
    MarkerClientMixin,
    MetadataClientMixin,
    PackageClientMixin,
    PerformerClientMixin,
    PluginClientMixin,
    SceneClientMixin,
    ScraperClientMixin,
    StudioClientMixin,
    SubscriptionClientMixin,
    SystemQueryClientMixin,
    TagClientMixin,
    VersionClientMixin,
    NotImplementedClientMixin,  # LAST: Fallback for unimplemented methods only
):
    """Full Stash client combining all functionality."""

    _capabilities: ServerCapabilities | None

    def __init__(
        self,
        conn: dict[str, Any] | None = None,
        verify_ssl: bool = True,
    ) -> None:
        """Initialize client.

        Args:
            conn: Connection details dictionary with:
                - Scheme: Protocol (default: "http")
                - Host: Hostname (default: "localhost")
                - Port: Port number (default: 9999)
                - ApiKey: Optional API key
                - Logger: Optional logger instance
            verify_ssl: Whether to verify SSL certificates
        """
        # Set initial state
        self._initialized = False
        self._init_args = (conn, verify_ssl)
        self._capabilities = None

        # Set up logging early
        self.log = conn.get("Logger", client_logger) if conn else client_logger

        # Set up URL components
        conn = conn or {}
        scheme = conn.get("Scheme", "http")
        host = conn.get("Host", "localhost")
        if host == "0.0.0.0":  # nosec B104  # noqa: S104  # Converting all-interfaces to localhost
            host = "127.0.0.1"
        port = conn.get("Port", 9999)

        # Validate and convert port to int
        if isinstance(port, str):
            try:
                port = int(port)
            except ValueError as e:
                raise TypeError(
                    f"Port must be an int or numeric string, got {port!r}"
                ) from e
        if not isinstance(port, int) or not 0 <= port <= 65535:
            raise ValueError(f"Port must be 0-65535, got {port}")

        self.url = f"{scheme}://{host}:{port}/graphql"

        # Set up HTTP client
        headers = {}
        if api_key := conn.get("ApiKey"):
            self.log.debug("Using API key authentication")
            headers["ApiKey"] = api_key

        # Initialize base class
        super().__init__(conn=conn, verify_ssl=verify_ssl)

        # Initialize all mixins
        NotImplementedClientMixin.__init__(self)
        ConfigClientMixin.__init__(self)
        FileClientMixin.__init__(self)
        FilterClientMixin.__init__(self)
        GalleryClientMixin.__init__(self)
        GroupClientMixin.__init__(self)
        ImageClientMixin.__init__(self)
        JobsClientMixin.__init__(self)
        MarkerClientMixin.__init__(self)
        MetadataClientMixin.__init__(self)
        PackageClientMixin.__init__(self)
        PerformerClientMixin.__init__(self)
        PluginClientMixin.__init__(self)
        SceneClientMixin.__init__(self)
        ScraperClientMixin.__init__(self)
        StudioClientMixin.__init__(self)
        SubscriptionClientMixin.__init__(self)
        SystemQueryClientMixin.__init__(self)
        TagClientMixin.__init__(self)
        VersionClientMixin.__init__(self)

    async def initialize(self) -> None:
        """Initialize the client and detect server capabilities.

        Calls base class initialize() to set up transport/session,
        then runs capability detection and rebuilds the fragment store
        with version-appropriate fields.
        """
        if self._initialized:
            return

        # Set up transport, session, etc.
        await super().initialize()

        # Detect server capabilities and rebuild fragment store
        from ..capabilities import detect_capabilities
        from ..fragments import fragment_store

        self._capabilities = await detect_capabilities(self._raw_execute, self.log)
        fragment_store.rebuild(self._capabilities)


__all__ = ["StashClient", "sanitize_model_data"]
