import json
from unittest.mock import patch, MagicMock
from urllib.error import HTTPError
from io import BytesIO

from payfence.client import authorize


class TestAuthorize:
    @patch("payfence.client.urlopen")
    def test_allow_response(self, mock_urlopen):
        decision = {"decision": "allow", "units": 1, "remainingUnits": 99}
        resp = MagicMock()
        resp.read.return_value = json.dumps(decision).encode()
        resp.__enter__ = MagicMock(return_value=resp)
        resp.__exit__ = MagicMock(return_value=False)
        mock_urlopen.return_value = resp

        result = authorize(api_key="sk_test", token="tok_123", method="GET", path="/v1/data")
        assert result["decision"] == "allow"
        assert result["units"] == 1

    @patch("payfence.client.urlopen")
    def test_deny_response_via_http_error(self, mock_urlopen):
        decision = {"decision": "deny", "reason": "payment_required"}
        error = HTTPError(
            url="https://api.payfence.io/v1/authorize",
            code=402,
            msg="Payment Required",
            hdrs={},
            fp=BytesIO(json.dumps(decision).encode()),
        )
        mock_urlopen.side_effect = error

        result = authorize(api_key="sk_test", token="tok_123", method="POST", path="/v1/weather")
        assert result["decision"] == "deny"
        assert result["reason"] == "payment_required"

    @patch("payfence.client.urlopen")
    def test_custom_base_url(self, mock_urlopen):
        resp = MagicMock()
        resp.read.return_value = json.dumps({"decision": "allow"}).encode()
        resp.__enter__ = MagicMock(return_value=resp)
        resp.__exit__ = MagicMock(return_value=False)
        mock_urlopen.return_value = resp

        authorize(api_key="sk_test", token="tok_123", method="GET", path="/", base_url="https://custom.example.com/")

        # Verify the Request object URL
        req_arg = mock_urlopen.call_args[0][0]
        assert req_arg.full_url == "https://custom.example.com/v1/authorize"

    @patch("payfence.client.urlopen")
    def test_request_id_forwarded(self, mock_urlopen):
        resp = MagicMock()
        resp.read.return_value = json.dumps({"decision": "allow"}).encode()
        resp.__enter__ = MagicMock(return_value=resp)
        resp.__exit__ = MagicMock(return_value=False)
        mock_urlopen.return_value = resp

        authorize(api_key="sk_test", token="tok_123", method="GET", path="/", request_id="my-req-id")

        req_arg = mock_urlopen.call_args[0][0]
        body = json.loads(req_arg.data)
        assert body["requestId"] == "my-req-id"
