"""Unit tests for the QrmClient implementation."""

from __future__ import annotations

import json

import pytest
import requests

import qrm.client as client_module
from qrm.client import QrmClient, QrmClientError


class FakeResponse:
    def __init__(
        self,
        *,
        json_data: object | None = None,
        text_data: str | None = None,
        status_code: int = 200,
        json_error: bool = False,
        headers: dict | None = None,
    ) -> None:
        self._json_data = json_data
        self._json_error = json_error
        if text_data is None and json_data is not None:
            text_data = json.dumps(json_data)
        self._text_data = text_data or ""
        self.status_code = status_code
        self.headers = headers or {}

    def json(self) -> object:
        if self._json_error:
            raise ValueError("invalid json")
        return self._json_data

    @property
    def text(self) -> str:
        return self._text_data

    def raise_for_status(self) -> None:
        if self.status_code >= 400:
            raise requests.HTTPError("boom")


class FakeSession:
    def __init__(self, response: FakeResponse) -> None:
        self._response = response
        self.verify = True
        self.post_kwargs: dict | None = None
        self.get_kwargs: dict | None = None

    def post(
        self,
        url: str,
        json: dict | None = None,
        timeout: float | None = None,
        headers: dict | None = None,
    ):
        self.post_kwargs = {
            "url": url,
            "json": json,
            "timeout": timeout,
            "headers": headers,
        }
        return self._response

    def get(self, url: str, headers: dict | None = None, timeout: float | None = None):
        self.get_kwargs = {"url": url, "headers": headers, "timeout": timeout}
        return self._response


def test_login_extracts_token_from_json_dict() -> None:
    response = FakeResponse(json_data={"token": "abc123"})
    session = FakeSession(response)
    client = QrmClient(base_url="https://qrm.example.com/api", session=session)

    token = client.login("jonas", "secret")

    assert token == "abc123"
    assert session.post_kwargs == {
        "url": "https://qrm.example.com/api/User/Login",
        "json": {"username": "jonas", "password": "secret"},
        "timeout": 10.0,
        "headers": None,
    }


def test_login_extracts_token_from_plain_text() -> None:
    response = FakeResponse(text_data="plain-token", json_error=True)
    session = FakeSession(response)
    client = QrmClient(base_url="https://qrm.example.com/api", session=session)

    token = client.login("jonas", "secret")

    assert token == "plain-token"


def test_login_extracts_token_from_json_string() -> None:
    payload = {
        "Token": "ABC.DEF.GHI",
        "RequireCaptcha": False,
    }
    response = FakeResponse(json_data=json.dumps(payload))
    session = FakeSession(response)
    client = QrmClient(base_url="https://qrm.example.com/api", session=session)

    token = client.login("jonas", "secret")

    assert token == "ABC.DEF.GHI"


def test_login_raises_when_token_missing() -> None:
    response = FakeResponse(json_data={"status": "ok"}, text_data="")
    session = FakeSession(response)
    client = QrmClient(base_url="https://qrm.example.com/api", session=session)

    with pytest.raises(QrmClientError):
        client.login("jonas", "secret")


def test_status_returns_json_and_sets_authorization_header() -> None:
    response = FakeResponse(json_data={"healthy": True})
    session = FakeSession(response)
    client = QrmClient(base_url="https://qrm.example.com/api", session=session)

    payload = client.status(token="TOKEN123")

    assert payload == {"healthy": True}
    assert session.get_kwargs == {
        "url": "https://qrm.example.com/api/Result/Status",
        "headers": {"Authorization": "Bearer TOKEN123"},
        "timeout": 10.0,
    }


def test_status_returns_plain_text_when_json_invalid() -> None:
    response = FakeResponse(text_data="OK", json_error=True)
    session = FakeSession(response)
    client = QrmClient(base_url="https://qrm.example.com/api", session=session)

    payload = client.status(token=None)

    assert payload == "OK"
    assert session.get_kwargs["headers"] is None


def test_status_prompts_relogin_on_401() -> None:
    response = FakeResponse(status_code=401)
    session = FakeSession(response)
    client = QrmClient(base_url="https://qrm.example.com/api", session=session)

    with pytest.raises(QrmClientError) as excinfo:
        client.status(token="TOKEN123")

    assert "qrm login" in str(excinfo.value)


def test_client_requires_base_url() -> None:
    with pytest.raises(ValueError):
        QrmClient(base_url="")


def test_token_extraction_handles_empty_response() -> None:
    response = FakeResponse(text_data="", json_error=True)
    assert QrmClient._extract_token(response) is None


def test_token_from_payload_returns_trimmed_on_invalid_json_string() -> None:
    assert (
        QrmClient._token_from_payload("{bad json}") == "{bad json}"
    )


def test_uut_status_posts_payload_and_returns_json() -> None:
    response = FakeResponse(json_data=[{"Id": 1}])
    session = FakeSession(response)
    client = QrmClient(base_url="https://qrm.example.com/api", session=session)

    payload = client.uut_status(
        token="TOKEN123",
        serial_number="3261",
        start_datetime="2026-02-01 00:00:00",
        stop_datetime="2026-02-06 23:59:00",
        max_results=500,
    )

    assert payload == [{"Id": 1}]
    assert session.post_kwargs == {
        "url": "https://qrm.example.com/api/Uut/Status",
        "json": {
            "serialNumber": "3261",
            "startDateTime": "2026-02-01 00:00:00",
            "stopDateTime": "2026-02-06 23:59:00",
            "maxNumberOfResults": 500,
        },
        "timeout": 10.0,
        "headers": {"Authorization": "Bearer TOKEN123"},
    }


def test_uut_status_requires_serial_number() -> None:
    client = QrmClient(
        base_url="https://qrm.example.com/api",
        session=FakeSession(FakeResponse(json_data=[])),
    )

    with pytest.raises(ValueError):
        client.uut_status(token="TOKEN", serial_number="")


def test_client_disables_warnings_when_insecure(monkeypatch) -> None:
    captured = {}

    def fake_disable(warning):  # noqa: ANN001
        captured["warning"] = warning

    monkeypatch.setattr(client_module.urllib3, "disable_warnings", fake_disable)

    session = FakeSession(FakeResponse(json_data={}))
    client = QrmClient(
        base_url="https://qrm.example.com/api",
        verify_tls=False,
        session=session,
    )

    assert client.session.verify is False
    assert captured["warning"] is client_module.urllib3.exceptions.InsecureRequestWarning


def test_box_list_posts_filters() -> None:
    response = FakeResponse(json_data=[{"BoxId": 1}])
    session = FakeSession(response)
    client = QrmClient(base_url="https://qrm.example.com/api", session=session)

    payload = client.box_list(
        token="TOKEN123",
        start_datetime="1970-01-01 00:00:00",
        stop_datetime="2026-02-06 00:00:00",
    )

    assert payload == [{"BoxId": 1}]
    assert session.post_kwargs == {
        "url": "https://qrm.example.com/api/Box/List",
        "json": {
            "startDateTime": "1970-01-01 00:00:00",
            "stopDateTime": "2026-02-06 00:00:00",
        },
        "timeout": 10.0,
        "headers": {"Authorization": "Bearer TOKEN123"},
    }


def test_box_list_requires_token() -> None:
    client = QrmClient(
        base_url="https://qrm.example.com/api",
        session=FakeSession(FakeResponse(json_data=[])),
    )

    with pytest.raises(ValueError):
        client.box_list(token="")


def test_debug_logging_captures_request_and_response(monkeypatch, capsys) -> None:  # type: ignore[no-untyped-def]
    monkeypatch.setenv("QRM_DEBUG", "1")
    response = FakeResponse(json_data={"healthy": True}, headers={"X-Test": "1"})
    session = FakeSession(response)
    client = QrmClient(base_url="https://qrm.example.com/api", session=session)

    client.status(token="TOKEN123")

    stderr = capsys.readouterr().err
    assert "[QRM DEBUG] REQUEST" in stderr
    assert "[QRM DEBUG] RESPONSE" in stderr
    assert "/Result/Status" in stderr
    assert "\"healthy\"" in stderr
