from __future__ import annotations

from typing import Any

import pytest

from blackout_notifier.clients import EitaaClient, ExternalServiceError, SaapaClient


class FakeResponse:
    def __init__(self, body: Any, *, status_code: int = 200) -> None:
        self._body = body
        self.status_code = status_code
        self.ok = 200 <= status_code < 400

    def json(self) -> Any:
        return self._body


class FakeSession:
    def __init__(self, response: FakeResponse) -> None:
        self.response = response
        self.calls: list[tuple[str, str, dict[str, Any]]] = []

    def post(self, url: str, **kwargs: Any) -> FakeResponse:
        self.calls.append(("POST", url, kwargs))
        return self.response

    def get(self, url: str, **kwargs: Any) -> FakeResponse:
        self.calls.append(("GET", url, kwargs))
        return self.response


def _payload(number: int = 1) -> dict[str, Any]:
    return {
        "outage_number": number,
        "outage_date": "1405/04/27",
        "outage_start_time": "09:00",
        "outage_stop_time": "11:00",
        "outage_address": "آدرس",
        "reason_outage": "مدیریت بار",
        "is_planned": True,
    }


def test_saapa_client_sends_expected_request() -> None:
    session = FakeSession(FakeResponse({"data": [_payload()]}))
    client = SaapaClient("secret", timeout=7, max_events_per_bill=25, session=session)  # type: ignore[arg-type]

    events = client.fetch("123", "1405/04/26", "1405/04/31")

    assert len(events) == 1
    _, _, kwargs = session.calls[0]
    assert kwargs["headers"]["Authorization"] == "Bearer secret"
    assert kwargs["json"]["bill_id"] == "123"
    assert kwargs["timeout"] == 7


def test_saapa_rejects_oversized_or_duplicate_snapshot() -> None:
    oversized = FakeSession(FakeResponse({"data": [_payload(1), _payload(2)]}))
    client = SaapaClient("token", timeout=1, max_events_per_bill=1, session=oversized)  # type: ignore[arg-type]
    with pytest.raises(ExternalServiceError, match="limit is 1"):
        client.fetch("123", "from", "to")

    duplicate = FakeSession(FakeResponse({"data": [_payload(1), _payload(1)]}))
    client = SaapaClient("token", timeout=1, max_events_per_bill=5, session=duplicate)  # type: ignore[arg-type]
    with pytest.raises(ExternalServiceError, match="duplicate outage_number"):
        client.fetch("123", "from", "to")


def test_eitaa_requires_ok_response() -> None:
    session = FakeSession(FakeResponse({"ok": False, "description": "denied"}))
    client = EitaaClient("token", timeout=2, session=session)  # type: ignore[arg-type]

    with pytest.raises(ExternalServiceError, match="denied"):
        client.send("chat", "message")

    _, url, kwargs = session.calls[0]
    assert url.endswith("/token/sendMessage")
    assert kwargs["params"] == {"chat_id": "chat", "text": "message"}
