from __future__ import annotations

from datetime import datetime, timezone
from unittest.mock import MagicMock

import pytest
import requests

from cirtusai import CirtusClient
from cirtusai.exceptions import AuthenticationError, APIError


def test_init_requires_base_url():
    with pytest.raises(ValueError):
        CirtusClient(base_url="", api_key="x")


def test_init_requires_api_key():
    with pytest.raises(ValueError):
        CirtusClient(base_url="http://x", api_key="")


def test_auto_authenticate_false_skips_auth(mock_session):
    client = CirtusClient(base_url="http://x", api_key="key", session=mock_session, auto_authenticate=False)
    assert client._token is None


def test_register_raises_api_error_on_failure(monkeypatch, mock_response_factory):
    monkeypatch.setattr(requests, "post", lambda *_, **__: mock_response_factory(status_code=400, json_data={"detail": "bad"}))
    with pytest.raises(APIError):
        CirtusClient.register("http://x", "agent", "pass")


def test_login_raises_authentication_error(monkeypatch, mock_response_factory):
    monkeypatch.setattr(requests, "post", lambda *_, **__: mock_response_factory(status_code=401, json_data={"detail": "bad"}))
    with pytest.raises(AuthenticationError):
        CirtusClient.login("http://x", "agent", "pass")


def test_authenticate_uses_cached_token(mock_session, mock_response_factory, future_expiry):
    mock_session.post.return_value = mock_response_factory(json_data={
        "access_token": "token",
        "expires_at": "2099-01-01T00:00:00+00:00",
        "user": {"id": "1", "agent_name": "a", "display_name": "a", "email_verified": True, "is_active": True,
                 "created_at": "2024-01-01T00:00:00+00:00", "updated_at": "2024-01-01T00:00:00+00:00"},
    })
    client = CirtusClient(base_url="http://x", api_key="key", session=mock_session)
    mock_session.post.reset_mock()
    client._token = "token"
    client._token_expiry = future_expiry
    token = client.authenticate()
    assert token == "token"
    mock_session.post.assert_not_called()


def test_normalize_site_strips_www():
    client = CirtusClient(base_url="http://x", api_key="key", auto_authenticate=False)
    assert client.normalize_site("https://www.example.com") == "example.com"


def test_prepare_access_builds_prompt(mock_session, future_expiry):
    client = CirtusClient(base_url="http://x", api_key="key", auto_authenticate=False)
    client._token = "t"
    client._token_expiry = future_expiry
    client._session = mock_session
    client._request = MagicMock(return_value={"action": "LOGIN", "password": "secret"})
    result = client.prepare_access(site="example.com", normalize=False)
    assert result["action"] == "LOGIN"
    assert "secret" in result["prompt"]


def test_create_api_key_defaults_permissions(future_expiry):
    client = CirtusClient(base_url="http://x", api_key="key", auto_authenticate=False)
    client._token = "t"
    client._token_expiry = future_expiry
    client._request = MagicMock(return_value={"secret": "k"})
    client.create_api_key("label")
    args, kwargs = client._request.call_args
    payload = kwargs.get("json")
    assert payload["permissions"][0]["asset_type"] == "email"


def test_create_stake_requires_tier(future_expiry):
    client = CirtusClient(base_url="http://x", api_key="key", auto_authenticate=False)
    client._token = "t"
    client._token_expiry = future_expiry
    with pytest.raises(ValueError):
        client.create_stake("", 10)
