# fmt: off
# Auto-generated by https://github.com/mos9527/UnityPyTypetreeCodegen
from typing import List, Union, Optional, TypeVar, Type
from UnityPy.files.ObjectReader import ObjectReader
from UnityPy.classes import *
from UnityPy.classes.math import (ColorRGBA, Matrix3x4f, Matrix4x4f, Quaternionf, Vector2f, Vector3f, Vector4f, float3, float4,)

UTTCG_Classes = dict()
def UTTCGen(fullname: str, typetree: dict):
    """dataclass-like decorator for typetree classess with nested type support
    
    limitations:
    - the behavior is similar to slotted dataclasses where shared attributes are inherited
      but allows ommiting init of the parent if kwargs are not sufficient
    - generally supports nested types, however untested and could be slow	
    - and ofc, zero type checking and safeguards :/	
    """    
    REFERENCED_ARGS = {'object_reader'}
    def __inner(clazz: T) -> T:
        # Allow these to be propogated to the props
        def __init__(self, **d):        
            def reduce_init(clazz, **d):
                types : dict = clazz.__annotations__
                for k, sub in types.items():
                    if type(sub) == str:
                        sub = eval(sub) # attrs turns these into strings...why?
                    while sub.__name__ == "Optional":
                        sub = sub.__args__[0]  # Reduce Optional[T] -> T
                    reduce_arg = getattr(sub, "__args__", [None])[0]
                    if k in REFERENCED_ARGS: # Directly refcounted
                        reduce_arg = sub = lambda x: x                         
                    if isinstance(d[k], list):
                        if hasattr(reduce_arg, "__annotations__"):
                            setattr(self, k, [reduce_arg(**x) for x in d[k]])
                        else:
                            setattr(self, k, [reduce_arg(x) for x in d[k]])
                    elif isinstance(d[k], dict) and hasattr(sub, "__annotations__"):
                        setattr(self, k, sub(**d[k]))
                    else:
                        if isinstance(d[k], dict):
                            setattr(self, k, sub(**d[k]))
                        else:
                            setattr(self, k, sub(d[k]))
            def reduce_base(clazz, **d):	
                for __base__ in clazz.__bases__:
                    if hasattr(__base__, "__annotations__"):
                        types : dict = __base__.__annotations__
                        args = {k:d[k] for k in types if k in d}
                        if len(args) == len(types):
                            super(clazz, self).__init__(**args)
                            reduce_init(__base__, **d)                       
                    reduce_base(__base__, **d)
            reduce_base(clazz, **d)               
            reduce_init(clazz, **d)            
        def __repr__(self) -> str:
            return f"{clazz.__name__}({', '.join([f'{k}={getattr(self, k)!r}' for k in self.__annotations__])})"
        def __save(self):
            self.object_reader.save_typetree(self, self.__typetree__)
        clazz.__init__ = __init__
        clazz.__repr__ = __repr__
        clazz.__typetree__ = typetree
        clazz.__fullname__ = fullname
        clazz.save = __save
        UTTCG_Classes[fullname] = clazz
        return clazz
    return __inner

# Helper functions
def UTTCGen_GetClasss(src: MonoBehaviour | str) -> Type:
    """Get the class definition from MonoBehaviour or a full type name."""
    if isinstance(src, MonoBehaviour):
        script = src.m_Script.read()
        src = script.m_ClassName
        if script.m_Namespace:
            src = f"{script.m_Namespace}.{src}"    
    return UTTCG_Classes.get(src, None)

T = TypeVar("T")
def UTTCGen_AsInstance(cls : Type[T], src: MonoBehaviour | ObjectReader) -> T:
    """Instantiate a class from the typetree definition and the raw data.

    In most cases, this is the function you want to use.
    It will read the typetree data from the MonoBehaviour instance and instantiate the class with the data.

    Args:
        cls: The class to instantiate. This should be a class that has been decorated with the UTTCGen decorator.
        src (MonoBehaviour | ObjectReader): The MonoBehaviour instance or ObjectReader to read from.        

    Returns:
        An instance of the class defined by the typetree.
    """
    if isinstance(src, MonoBehaviour):
        src = src.object_reader
    raw_def = src.read_typetree(cls.__typetree__, check_read=False)
    instance = cls(object_reader=src, **raw_def)
    return instance
