import pytest
from dataclasses import dataclass

from frisk_sdk.type_utils.normalize_object_to_dictionary import (
    normalize_object_to_dictionary,
)


@dataclass
class Person:
    name: str
    age: int


@dataclass
class Company:
    name: str
    ceo: Person


class PlainObject:
    def __init__(self, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)


@pytest.mark.unit
def test_normalize_dataclass_flat() -> None:
    person = Person(name="Ada", age=36)
    assert normalize_object_to_dictionary(person) == {"name": "Ada", "age": 36}


@pytest.mark.unit
def test_normalize_dataclass_nested() -> None:
    company = Company(name="Acme", ceo=Person(name="Ada", age=36))
    assert normalize_object_to_dictionary(company) == {
        "name": "Acme",
        "ceo": {"name": "Ada", "age": 36},
    }


@pytest.mark.unit
def test_normalize_mapping() -> None:
    assert normalize_object_to_dictionary({"a": 1, "b": 2}) == {"a": 1, "b": 2}


@pytest.mark.unit
def test_normalize_mapping_subclass() -> None:
    class MyMap(dict):
        pass

    m = MyMap(a=1)
    assert normalize_object_to_dictionary(m) == {"a": 1}


@pytest.mark.unit
def test_normalize_plain_object_via___dict__() -> None:
    obj = PlainObject(a=1, b="x")
    assert normalize_object_to_dictionary(obj) == {"a": 1, "b": "x"}


@pytest.mark.unit
def test_unsupported_type_raises_type_error() -> None:
    with pytest.raises(TypeError, match=r"Cannot normalize object of type"):
        normalize_object_to_dictionary(42)
