from dynamix_sdk import types as sdk_types
from dynamix_sdk.base import (
    get_alias,
    name_mapping_dict,
)


def test_missing_mappings_in_name_mapping_file(dx_models):
    attrs_without_mapping = []
    for model_cls in dx_models:
        for field_name in model_cls.model_fields.keys():
            try:
                get_alias(
                    field_name=field_name,
                    model_cls=model_cls,
                    name_mapping_dict=name_mapping_dict
                )
            except KeyError:
                attrs_without_mapping.append(
                    f'{model_cls.__qualname__}.{field_name}'
                )

    attrs_without_mapping.sort()

    assert not attrs_without_mapping, (
        f'{len(attrs_without_mapping)} attributes without mapping:'
        f' {attrs_without_mapping}'
    )


def test_unused_mappings_in_name_mapping_file(dx_models):
    mapping_dict_keys = set(name_mapping_dict.keys())

    def exclude_used_keys(
        model_cls: type[sdk_types.BaseModel],
        mapping_dict_keys: set[str],
    ):
        for field_name in model_cls.__annotations__.keys():
            used_key = None

            individual_alias_key = f'{field_name}__{model_cls.__qualname__}'
            if individual_alias_key in mapping_dict_keys:
                used_key = individual_alias_key
            elif field_name in mapping_dict_keys:
                used_key = field_name

            if used_key and used_key in mapping_dict_keys:
                mapping_dict_keys.remove(used_key)

        for base_cls in model_cls.__bases__:
            if issubclass(base_cls, sdk_types.BaseModel):
                exclude_used_keys(
                    model_cls=base_cls,
                    mapping_dict_keys=mapping_dict_keys,
                )

    for model_cls in dx_models:
        exclude_used_keys(
            model_cls=model_cls,
            mapping_dict_keys=mapping_dict_keys,
        )

    unused_mapping_dict_keys = sorted(mapping_dict_keys)

    assert not unused_mapping_dict_keys, (
        f'{len(unused_mapping_dict_keys)} unused keys in mapping file:'
        f' {unused_mapping_dict_keys}.'
    )
