import warnings
from typing import Any, Callable

from ._internal._validators import import_string

MOVED_IN_V2 = {
    'pydantic.utils.version_info': 'pydantic.version.version_info',
    'pydantic.error_wrappers.ValidationError': 'pydantic.ValidationError',
}

DEPRECATED_MOVED_IN_V2 = {
    'pydantic.tools.schema_of': 'pydantic.deprecated.tools.schema_of',
    'pydantic.tools.parse_obj_as': 'pydantic.deprecated.tools.parse_obj_as',
    'pydantic.tools.schema_json_of': 'pydantic.deprecated.tools.schema_json_of',
    'pydantic.json.pydantic_encoder': 'pydantic.deprecated.json.pydantic_encoder',
    'pydantic.validate_arguments': 'pydantic.deprecated.decorator.validate_arguments',
    'pydantic.json.custom_pydantic_encoder': 'pydantic.deprecated.json.custom_pydantic_encoder',
    'pydantic.json.timedelta_isoformat': 'pydantic.deprecated.json.timedelta_isoformat',
    'pydantic.decorator.validate_arguments': 'pydantic.deprecated.decorator.validate_arguments',
}

REMOVED_IN_V2 = {
    'pydantic.BaseSettings',
    'pydantic.ConstrainedBytes',
    'pydantic.ConstrainedDate',
    'pydantic.ConstrainedDecimal',
    'pydantic.ConstrainedFloat',
    'pydantic.ConstrainedFrozenSet',
    'pydantic.ConstrainedInt',
    'pydantic.ConstrainedList',
    'pydantic.ConstrainedSet',
    'pydantic.ConstrainedStr',
    'pydantic.JsonWrapper',
    'pydantic.NoneBytes',
    'pydantic.NoneStr',
    'pydantic.NoneStrBytes',
    'pydantic.Protocol',
    'pydantic.PyObject',
    'pydantic.Required',
    'pydantic.StrBytes',
    'pydantic.compiled',
    'pydantic.config.get_config',
    'pydantic.config.inherit_config',
    'pydantic.config.prepare_config',
    'pydantic.create_model_from_namedtuple',
    'pydantic.create_model_from_typeddict',
    'pydantic.dataclasses.create_pydantic_model_from_dataclass',
    'pydantic.dataclasses.make_dataclass_validator',
    'pydantic.dataclasses.set_validation',
    'pydantic.error_wrappers.ErrorWrapper',
    'pydantic.errors.AnyStrMaxLengthError',
    'pydantic.errors.AnyStrMinLengthError',
    'pydantic.errors.ArbitraryTypeError',
    'pydantic.errors.BoolError',
    'pydantic.errors.BytesError',
    'pydantic.errors.CallableError',
    'pydantic.errors.ClassError',
    'pydantic.errors.ColorError',
    'pydantic.errors.ConfigError',
    'pydantic.errors.DataclassTypeError',
    'pydantic.errors.DateError',
    'pydantic.errors.DateNotInTheFutureError',
    'pydantic.errors.DateNotInThePastError',
    'pydantic.errors.DateTimeError',
    'pydantic.errors.DecimalError',
    'pydantic.errors.DecimalIsNotFiniteError',
    'pydantic.errors.DecimalMaxDigitsError',
    'pydantic.errors.DecimalMaxPlacesError',
    'pydantic.errors.DecimalWholeDigitsError',
    'pydantic.errors.DictError',
    'pydantic.errors.DurationError',
    'pydantic.errors.EmailError',
    'pydantic.errors.EnumError',
    'pydantic.errors.EnumMemberError',
    'pydantic.errors.ExtraError',
    'pydantic.errors.FloatError',
    'pydantic.errors.FrozenSetError',
    'pydantic.errors.FrozenSetMaxLengthError',
    'pydantic.errors.FrozenSetMinLengthError',
    'pydantic.errors.HashableError',
    'pydantic.errors.IPv4AddressError',
    'pydantic.errors.IPv4InterfaceError',
    'pydantic.errors.IPv4NetworkError',
    'pydantic.errors.IPv6AddressError',
    'pydantic.errors.IPv6InterfaceError',
    'pydantic.errors.IPv6NetworkError',
    'pydantic.errors.IPvAnyAddressError',
    'pydantic.errors.IPvAnyInterfaceError',
    'pydantic.errors.IPvAnyNetworkError',
    'pydantic.errors.IntEnumError',
    'pydantic.errors.IntegerError',
    'pydantic.errors.InvalidByteSize',
    'pydantic.errors.InvalidByteSizeUnit',
    'pydantic.errors.InvalidDiscriminator',
    'pydantic.errors.InvalidLengthForBrand',
    'pydantic.errors.JsonError',
    'pydantic.errors.JsonTypeError',
    'pydantic.errors.ListError',
    'pydantic.errors.ListMaxLengthError',
    'pydantic.errors.ListMinLengthError',
    'pydantic.errors.ListUniqueItemsError',
    'pydantic.errors.LuhnValidationError',
    'pydantic.errors.MissingDiscriminator',
    'pydantic.errors.MissingError',
    'pydantic.errors.NoneIsAllowedError',
    'pydantic.errors.NoneIsNotAllowedError',
    'pydantic.errors.NotDigitError',
    'pydantic.errors.NotNoneError',
    'pydantic.errors.NumberNotGeError',
    'pydantic.errors.NumberNotGtError',
    'pydantic.errors.NumberNotLeError',
    'pydantic.errors.NumberNotLtError',
    'pydantic.errors.NumberNotMultipleError',
    'pydantic.errors.PathError',
    'pydantic.errors.PathNotADirectoryError',
    'pydantic.errors.PathNotAFileError',
    'pydantic.errors.PathNotExistsError',
    'pydantic.errors.PatternError',
    'pydantic.errors.PyObjectError',
    'pydantic.errors.PydanticTypeError',
    'pydantic.errors.PydanticValueError',
    'pydantic.errors.SequenceError',
    'pydantic.errors.SetError',
    'pydantic.errors.SetMaxLengthError',
    'pydantic.errors.SetMinLengthError',
    'pydantic.errors.StrError',
    'pydantic.errors.StrRegexError',
    'pydantic.errors.StrictBoolError',
    'pydantic.errors.SubclassError',
    'pydantic.errors.TimeError',
    'pydantic.errors.TupleError',
    'pydantic.errors.TupleLengthError',
    'pydantic.errors.UUIDError',
    'pydantic.errors.UUIDVersionError',
    'pydantic.errors.UrlError',
    'pydantic.errors.UrlExtraError',
    'pydantic.errors.UrlHostError',
    'pydantic.errors.UrlHostTldError',
    'pydantic.errors.UrlPortError',
    'pydantic.errors.UrlSchemeError',
    'pydantic.errors.UrlSchemePermittedError',
    'pydantic.errors.UrlUserInfoError',
    'pydantic.errors.WrongConstantError',
    'pydantic.main.validate_model',
    'pydantic.networks.stricturl',
    'pydantic.parse_file_as',
    'pydantic.parse_raw_as',
    'pydantic.stricturl',
    'pydantic.tools.parse_file_as',
    'pydantic.tools.parse_raw_as',
    'pydantic.types.ConstrainedBytes',
    'pydantic.types.ConstrainedDate',
    'pydantic.types.ConstrainedDecimal',
    'pydantic.types.ConstrainedFloat',
    'pydantic.types.ConstrainedFrozenSet',
    'pydantic.types.ConstrainedInt',
    'pydantic.types.ConstrainedList',
    'pydantic.types.ConstrainedSet',
    'pydantic.types.ConstrainedStr',
    'pydantic.types.JsonWrapper',
    'pydantic.types.NoneBytes',
    'pydantic.types.NoneStr',
    'pydantic.types.NoneStrBytes',
    'pydantic.types.PyObject',
    'pydantic.types.StrBytes',
    'pydantic.typing.AbstractSetIntStr',
    'pydantic.typing.AnyCallable',
    'pydantic.typing.AnyClassMethod',
    'pydantic.typing.CallableGenerator',
    'pydantic.typing.DictAny',
    'pydantic.typing.DictIntStrAny',
    'pydantic.typing.DictStrAny',
    'pydantic.typing.IntStr',
    'pydantic.typing.ListStr',
    'pydantic.typing.MappingIntStrAny',
    'pydantic.typing.NoArgAnyCallable',
    'pydantic.typing.NoneType',
    'pydantic.typing.ReprArgs',
    'pydantic.typing.SetStr',
    'pydantic.typing.StrPath',
    'pydantic.typing.TupleGenerator',
    'pydantic.typing.WithArgsTypes',
    'pydantic.typing.all_literal_values',
    'pydantic.typing.display_as_type',
    'pydantic.typing.get_all_type_hints',
    'pydantic.typing.get_args',
    'pydantic.typing.get_origin',
    'pydantic.typing.get_sub_types',
    'pydantic.typing.is_callable_type',
    'pydantic.typing.is_classvar',
    'pydantic.typing.is_finalvar',
    'pydantic.typing.is_literal_type',
    'pydantic.typing.is_namedtuple',
    'pydantic.typing.is_new_type',
    'pydantic.typing.is_none_type',
    'pydantic.typing.is_typeddict',
    'pydantic.typing.is_typeddict_special',
    'pydantic.typing.is_union',
    'pydantic.typing.new_type_supertype',
    'pydantic.typing.resolve_annotations',
    'pydantic.typing.typing_base',
    'pydantic.typing.update_field_forward_refs',
    'pydantic.typing.update_model_forward_refs',
    'pydantic.utils.ClassAttribute',
    'pydantic.utils.DUNDER_ATTRIBUTES',
    'pydantic.utils.GetterDict',
    'pydantic.utils.PyObjectStr',
    'pydantic.utils.ROOT_KEY',
    'pydantic.utils.Representation',
    'pydantic.utils.ValueItems',
    'pydantic.utils.almost_equal_floats',
    'pydantic.utils.deep_update',
    'pydantic.utils.get_discriminator_alias_and_values',
    'pydantic.utils.get_model',
    'pydantic.utils.get_unique_discriminator_alias',
    'pydantic.utils.import_string',
    'pydantic.utils.in_ipython',
    'pydantic.utils.is_valid_field',
    'pydantic.utils.is_valid_identifier',
    'pydantic.utils.lenient_isinstance',
    'pydantic.utils.lenient_issubclass',
    'pydantic.utils.path_type',
    'pydantic.utils.sequence_like',
    'pydantic.utils.smart_deepcopy',
    'pydantic.utils.to_camel',
    'pydantic.utils.update_not_none',
    'pydantic.utils.validate_field_name',
    'pydantic.validate_model',
}


def getattr_migration(module: str) -> Callable[[str], Any]:
    """Implement PEP 562 for objects that were either moved or removed on the migration
    to V2.

    Args:
        module: The module name.

    Returns:
        A callable that will raise an error if the object is not found.
    """
    # This avoids circular import with errors.py.
    from .errors import PydanticImportError

    def wrapper(name: str) -> object:
        """Raise an error if the object is not found, or warn if it was moved.

        In case it was moved, it still returns the object.

        Args:
            name: The object name.

        Returns:
            The object.
        """
        import_path = f'{module}.{name}'
        if import_path in MOVED_IN_V2.keys():
            new_location = MOVED_IN_V2[import_path]
            warnings.warn(f'`{import_path}` has been moved to `{new_location}`.')
            return import_string(MOVED_IN_V2[import_path])
        if import_path in DEPRECATED_MOVED_IN_V2.keys():
            # skip the warning here because a deprecation warning will be raised elsewhere
            return import_string(DEPRECATED_MOVED_IN_V2[import_path])
        if import_path in REMOVED_IN_V2:
            raise PydanticImportError(f'`{import_path}` has been removed in V2.')
        raise AttributeError(f'module {__name__!r} has no attribute {name!r}')

    return wrapper
