from __future__ import annotations

from unittest.mock import Mock

import pytest

from appraisal_forge_sdk.client import ApiError, AppraisalForgeClient


def _mock_response(status_code: int, payload: dict | list | None = None, text: str = "") -> Mock:
    response = Mock()
    response.status_code = status_code
    response.content = b"x" if payload is not None else b""
    response.text = text
    if payload is None:
        response.json.side_effect = ValueError("no json")
    else:
        response.json.return_value = payload
    return response


def test_write_fields_calls_expected_endpoint() -> None:
    client = AppraisalForgeClient(api_url="http://localhost:8090", token="abc")
    response = _mock_response(200, {"ok": True})
    client.session.request = Mock(return_value=response)

    result = client.write_fields(42, {"0100.0009": "Raleigh"})

    assert result == {"ok": True}
    client.session.request.assert_called_once()
    args, kwargs = client.session.request.call_args
    assert args[0] == "PUT"
    assert args[1] == "http://localhost:8090/api/appraisals/42/fields/"
    assert kwargs["json"] == {"0100.0009": "Raleigh"}


def test_read_fields_uses_params() -> None:
    client = AppraisalForgeClient(api_url="http://localhost:8090", token="abc")
    response = _mock_response(200, {"fields": {}})
    client.session.request = Mock(return_value=response)

    client.read_fields(99, prefix="0100", include_empty=False)

    args, kwargs = client.session.request.call_args
    assert args[0] == "GET"
    assert args[1].endswith("/api/appraisals/99/fields/")
    assert kwargs["params"] == {"prefix": "0100", "include_empty": "false"}


def test_list_tokens_calls_expected_endpoint() -> None:
    client = AppraisalForgeClient(api_url="http://localhost:8090", token="abc")
    response = _mock_response(200, {"tokens": []})
    client.session.request = Mock(return_value=response)

    result = client.list_tokens()

    assert result == {"tokens": []}
    args, kwargs = client.session.request.call_args
    assert args[0] == "GET"
    assert args[1] == "http://localhost:8090/api/tokens/"


def test_create_token_posts_payload() -> None:
    client = AppraisalForgeClient(api_url="http://localhost:8090", token="abc")
    response = _mock_response(201, {"id": 7, "token": "abc"})
    client.session.request = Mock(return_value=response)

    result = client.create_token(label="Claude", scope="full")

    assert result == {"id": 7, "token": "abc"}
    args, kwargs = client.session.request.call_args
    assert args[0] == "POST"
    assert args[1] == "http://localhost:8090/api/tokens/"
    assert kwargs["json"] == {"label": "Claude", "scope": "full"}


def test_verify_token_uses_endpoint() -> None:
    client = AppraisalForgeClient(api_url="http://localhost:8090", token="abc")
    response = _mock_response(200, {"valid": True})
    client.session.request = Mock(return_value=response)

    result = client.verify_token()

    assert result == {"valid": True}
    args, kwargs = client.session.request.call_args
    assert args[0] == "GET"
    assert args[1] == "http://localhost:8090/api/tokens/verify/"


def test_raises_api_error_on_http_failure() -> None:
    client = AppraisalForgeClient(api_url="http://localhost:8090", token="abc")
    response = _mock_response(403, {"detail": "forbidden"})
    client.session.request = Mock(return_value=response)

    with pytest.raises(ApiError) as exc:
        client.validate(7)

    assert exc.value.status_code == 403
    assert exc.value.payload == {"detail": "forbidden"}
