"""Minimal qBittorrent Web API client (read-only: sync/maindata only).

Modeled on :class:`~media_library_viewer_api.clients.jellyfin.JellyfinClient`'s
session pattern. Authentication uses username/password login which stores an
SID cookie in the requests session. The client re-logins transparently on 403.
"""

from __future__ import annotations

import logging
from typing import Any

import requests

logger = logging.getLogger(__name__)


class QbittorrentClient:
    """Small wrapper around the qBittorrent Web API.

    Only the endpoints needed by the dashboard widgets are implemented
    (currently just ``/sync/maindata``). All calls share a single
    :class:`requests.Session` that carries the login cookie.
    """

    def __init__(self, base_url: str, username: str, password: str, timeout: int = 10) -> None:
        if not base_url:
            raise ValueError("qBittorrent base_url is required")
        if not username:
            raise ValueError("qBittorrent username is required")

        self.base_url = base_url.rstrip("/")
        if not self.base_url.endswith("/api/v2"):
            self.base_url += "/api/v2"
        self._username = username
        self._password = password
        self.timeout = timeout
        self._session = requests.Session()
        self._logged_in = False

    def _login(self) -> None:
        """POST username/password to ``/auth/login``; store the SID cookie.

        qBittorrent returns the plain text ``"Ok."`` on success. The
        ``Referer`` header is required by some qBittorrent CSRF protections.
        """
        resp = self._session.post(
            f"{self.base_url}/auth/login",
            data={"username": self._username, "password": self._password},
            timeout=self.timeout,
            headers={"Referer": self.base_url},
        )
        resp.raise_for_status()
        if resp.text.strip() != "Ok.":
            raise RuntimeError(f"qBittorrent login failed: {resp.text.strip()}")
        self._logged_in = True
        logger.info("qBittorrent login successful for %s", self.base_url)

    def _get(self, path: str, **params: Any) -> dict[str, Any]:
        """GET an endpoint with auto-login on first call and re-login on 403."""
        if not self._logged_in:
            self._login()
        url = f"{self.base_url}{path}"
        resp = self._session.get(url, params=params, timeout=self.timeout)
        if resp.status_code == 403:
            logger.debug("qBittorrent 403 on %s, re-logging in", path)
            self._logged_in = False
            self._login()
            resp = self._session.get(url, params=params, timeout=self.timeout)
        resp.raise_for_status()
        return resp.json()

    def maindata(self) -> dict[str, Any]:
        """Fetch ``/sync/maindata``.

        Returns a dict with ``server_state`` (containing ``dl_info_speed``,
        ``up_info_speed``, etc.) and ``torrents`` (a dict of
        ``{hash: {name, state, progress, size, dlspeed, upspeed, ...}}``).
        """
        return self._get("/sync/maindata")
