import pytest

from vcti.config.errors import (
    ConfigError,
    ConfigErrors,
    DecodeError,
    MissingFieldError,
    ValidationError,
)


class TestDecodeError:
    """Tests for DecodeError."""

    def test_message(self):
        err = DecodeError("bad value", field_name="port", raw_value="abc")
        assert str(err) == "bad value"
        assert err.field_name == "port"
        assert err.raw_value == "abc"

    def test_is_config_error(self):
        assert issubclass(DecodeError, ConfigError)

    def test_defaults(self):
        err = DecodeError("msg")
        assert err.field_name == ""
        assert err.raw_value == ""


class TestMissingFieldError:
    """Tests for MissingFieldError."""

    def test_message(self):
        err = MissingFieldError("missing", field_name="host", env_name="APP_HOST")
        assert str(err) == "missing"
        assert err.field_name == "host"
        assert err.env_name == "APP_HOST"

    def test_is_config_error(self):
        assert issubclass(MissingFieldError, ConfigError)


class TestValidationError:
    """Tests for ValidationError."""

    def test_message(self):
        err = ValidationError("invalid", field_name="port", value=-1)
        assert str(err) == "invalid"
        assert err.field_name == "port"
        assert err.value == -1

    def test_is_config_error(self):
        assert issubclass(ValidationError, ConfigError)


class TestConfigErrors:
    """Tests for ConfigErrors collection."""

    def test_collects_multiple_errors(self):
        errs = [
            DecodeError("bad port", field_name="port", raw_value="abc"),
            MissingFieldError("no host", field_name="host", env_name="APP_HOST"),
        ]
        exc = ConfigErrors(errs)
        assert len(exc.errors) == 2
        assert "2 configuration error(s):" in str(exc)
        assert "[DecodeError]" in str(exc)
        assert "[MissingFieldError]" in str(exc)

    def test_is_config_error(self):
        assert issubclass(ConfigErrors, ConfigError)

    def test_single_error(self):
        exc = ConfigErrors([DecodeError("bad")])
        assert "1 configuration error(s):" in str(exc)

    def test_can_be_raised_and_caught(self):
        with pytest.raises(ConfigErrors, match="2 configuration"):
            raise ConfigErrors(
                [
                    DecodeError("a"),
                    ValidationError("b"),
                ]
            )
