"""qBittorrent service definition.

Declares the config model (base URL + timeout), secret fields (username +
password), and three widget kinds (totals, active, speed). Models on
:mod:`media_library_viewer_api.integrations.prometheus`.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, Literal

from pydantic import Field

from media_library_viewer_api.clients.qbittorrent import QbittorrentClient
from media_library_viewer_api.integrations.base import (
    SecretField,
    ServiceBaseUrl,
    ServiceConfigBase,
    ServiceDefinition,
    TestResult,
    WidgetConfigBase,
    translate_connection_error,
    widget_kind,
)

if TYPE_CHECKING:
    from media_library_viewer_api.services.settings_store import SettingsStore


def test_connection(
    config: dict[str, Any],
    secrets: dict[str, str],
    store: SettingsStore,
) -> TestResult:
    """Login + probe maindata; surface auth failures specifically."""
    try:
        base_url = str(config.get("base_url") or "")
        username = str(secrets.get("username") or "")
        password = str(secrets.get("password") or "")
        timeout = int(config.get("timeout_seconds") or 60)
        client = QbittorrentClient(base_url, username, password, timeout=timeout)
        data = client.maindata()
        version = str(data.get("server_state", {}).get("qbittorrent_version", "") or "connected")
        return TestResult(ok=True, detail="Connected to qBittorrent.", evidence=version)
    except RuntimeError as exc:
        lowered = str(exc).lower()
        if "invalid username or password" in lowered:
            return TestResult(ok=False, detail="Authentication failed — qBittorrent rejected the credentials.")
        # Gateway timeout, wrong URL/path, empty body, etc. — surface the real
        # reason instead of masking every login error as an auth failure.
        return translate_connection_error(exc, context="qBittorrent")
    except Exception as exc:
        return translate_connection_error(exc, context="qBittorrent")


class QbittorrentConfig(ServiceConfigBase):
    """Non-secret qBittorrent connection and sampling config."""

    base_url: ServiceBaseUrl
    timeout_seconds: int = Field(default=60, ge=1, le=300)
    polling_enabled: bool = Field(default=True, description="Collect speed samples without an open dashboard")
    poll_interval_seconds: int = Field(default=15, ge=5, le=300, description="Seconds between speed samples")
    sample_retention_seconds: int = Field(
        default=1_800,
        ge=60,
        le=86_400,
        description="How long speed samples remain available",
    )
    sample_max_rows: int = Field(
        default=1_200,
        ge=60,
        le=1_200,
        description="Maximum speed samples retained per service",
    )


class QbittorrentWidgetConfig(WidgetConfigBase):
    """Per-widget config for totals/active (empty — derived from the service connection)."""

    pass


class QbittorrentSpeedWidgetConfig(WidgetConfigBase):
    """Speed chart config. The source returns raw bytes/sec; the frontend scales."""

    window_seconds: int = Field(default=1_800, ge=60, le=86_400)
    unit: Literal[
        "none",
        "bytes",
        "bytes_per_sec",
        "bits_per_sec",
        "bits",
        "percent",
        "seconds",
    ] = "bytes_per_sec"
    scale: Literal["auto", "k", "m", "g", "t"] = "auto"


DEFINITION = ServiceDefinition(
    service_type="qbittorrent",
    name="qBittorrent",
    description="Torrent client activity, speeds, and item counts.",
    config_model=QbittorrentConfig,
    secret_fields=[
        SecretField(key="username", label="Username", required=True),
        SecretField(key="password", label="Password", required=True, helper="Stored encrypted"),
    ],
    widget_kinds=[
        widget_kind(
            kind="totals",
            name="Totals",
            description="Count of all listed torrents, broken down by state.",
            model_cls=QbittorrentWidgetConfig,
            default_config={},
            refresh_interval_ms=30_000,
        ),
        widget_kind(
            kind="active",
            name="Active torrents",
            description="All active download/upload work, including queued and stalled transfers.",
            model_cls=QbittorrentWidgetConfig,
            default_config={},
            refresh_interval_ms=15_000,
        ),
        widget_kind(
            kind="speed",
            name="Speed chart",
            description="Live download/upload speed over a short window.",
            model_cls=QbittorrentSpeedWidgetConfig,
            default_config={"window_seconds": 1_800, "unit": "bytes_per_sec", "scale": "auto"},
            refresh_interval_ms=15_000,
        ),
    ],
    test_callable=test_connection,
)
