"""Tests for MRP SDK error hierarchy."""

from __future__ import annotations

import pytest

from mrp.errors import (
    AuthError,
    ConflictError,
    ForbiddenError,
    MRPError,
    NotFoundError,
    PayloadTooLargeError,
    RateLimitError,
    RequestError,
    StorageError,
    ValidationError,
)


class TestMRPError:
    def test_mrp_error_basic(self):
        err = MRPError("auth_failed", "Invalid token", "req-123")
        assert err.code == "auth_failed"
        assert err.message == "Invalid token"
        assert err.request_id == "req-123"

    def test_mrp_error_no_request_id(self):
        err = MRPError("some_code", "some message")
        assert err.request_id is None

    def test_error_str(self):
        err = MRPError("err_code", "Something went wrong")
        assert "Something went wrong" in str(err)


class TestErrorSubclasses:
    def test_auth_error_inherits(self):
        err = AuthError("unauthorized", "Bad credentials")
        assert isinstance(err, MRPError)
        assert isinstance(err, Exception)

    @pytest.mark.parametrize(
        "cls,code,message",
        [
            (AuthError, "unauthorized", "Bad credentials"),
            (ForbiddenError, "forbidden", "Access denied"),
            (NotFoundError, "not_found", "Resource missing"),
            (ConflictError, "conflict", "Duplicate detected"),
            (ValidationError, "validation", "Invalid input"),
            (StorageError, "storage", "Quota exceeded"),
            (PayloadTooLargeError, "too_large", "Body too big"),
        ],
    )
    def test_all_error_subclasses(self, cls, code, message):
        err = cls(code, message, "req-456")
        assert isinstance(err, MRPError)
        assert err.code == code
        assert err.message == message
        assert err.request_id == "req-456"

    def test_forbidden_error(self):
        err = ForbiddenError("forbidden", "No access", "req-789")
        assert err.code == "forbidden"
        assert err.message == "No access"
        assert err.request_id == "req-789"

    def test_storage_error(self):
        err = StorageError("storage_full", "Disk full", "req-000")
        assert err.code == "storage_full"
        assert err.message == "Disk full"
        assert err.request_id == "req-000"


class TestRateLimitError:
    def test_rate_limit_error_fields(self):
        err = RateLimitError(
            code="rate_limited",
            message="Too many requests",
            request_id="req-rl",
            retry_after=30.0,
            limit=100,
            remaining=0,
            reset=1700000000.0,
        )
        assert err.code == "rate_limited"
        assert err.message == "Too many requests"
        assert err.request_id == "req-rl"
        assert err.retry_after == 30.0
        assert err.limit == 100
        assert err.remaining == 0
        assert err.reset == 1700000000.0
        assert isinstance(err, MRPError)


class TestRequestError:
    def test_request_error_basic(self):
        err = RequestError("bad_input", "Missing field")
        assert err.code == "bad_input"
        assert err.message == "Missing field"

    def test_request_error_not_mrp(self):
        err = RequestError("code", "msg")
        assert not isinstance(err, MRPError)
        assert isinstance(err, Exception)


class TestErrorBehavior:
    def test_errors_can_be_raised(self):
        with pytest.raises(AuthError):
            raise AuthError("unauthorized", "token expired")

        with pytest.raises(RateLimitError):
            raise RateLimitError("rate_limited", "slow down")

        with pytest.raises(RequestError):
            raise RequestError("bad_input", "missing field")

    def test_catch_as_parent(self):
        with pytest.raises(MRPError):
            raise AuthError("unauthorized", "token expired")

        with pytest.raises(MRPError):
            raise ForbiddenError("forbidden", "denied")

        with pytest.raises(MRPError):
            raise RateLimitError("rate_limited", "slow down")
