import importlib
import builtins as py_builtins
import sys
from renzmc.core.error import (
    RenzmcImportError,
    RenzmcTypeError,
    RenzmcAttributeError,
)


class SmartPythonWrapper:

    def __init__(self, obj, integration_manager):
        self._obj = obj
        self._integration = integration_manager
        self._obj_type = type(obj).__name__

    def __getattr__(self, name):
        try:
            attr = getattr(self._obj, name)
            return self._integration.convert_python_to_renzmc(attr)
        except AttributeError:
            raise RenzmcAttributeError(
                f"Objek Python '{self._obj_type}' tidak memiliki atribut '{name}'"
            )

    def __setattr__(self, name, value):
        if name.startswith("_"):
            super().__setattr__(name, value)
        else:
            try:
                setattr(
                    self._obj, name, self._integration.convert_renzmc_to_python(value)
                )
            except AttributeError:
                raise RenzmcAttributeError(
                    f"Tidak dapat mengatur atribut '{name}' pada objek Python '{self._obj_type}'"
                )

    def __call__(self, *args, **kwargs):
        if callable(self._obj):
            py_args = [self._integration.convert_renzmc_to_python(arg) for arg in args]
            py_kwargs = {
                k: self._integration.convert_renzmc_to_python(v)
                for k, v in kwargs.items()
            }
            result = self._obj(*py_args, **py_kwargs)
            return self._integration.convert_python_to_renzmc(result)
        else:
            raise RenzmcTypeError(
                f"Objek Python '{self._obj_type}' tidak dapat dipanggil"
            )

    def __getitem__(self, key):
        try:
            result = self._obj[self._integration.convert_renzmc_to_python(key)]
            return self._integration.convert_python_to_renzmc(result)
        except (KeyError, IndexError, TypeError) as e:
            raise RenzmcAttributeError(
                f"Error mengakses indeks pada objek Python: {str(e)}"
            )

    def __setitem__(self, key, value):
        try:
            self._obj[self._integration.convert_renzmc_to_python(key)] = (
                self._integration.convert_renzmc_to_python(value)
            )
        except (KeyError, IndexError, TypeError) as e:
            raise RenzmcAttributeError(
                f"Error mengatur indeks pada objek Python: {str(e)}"
            )

    def __delitem__(self, key):
        try:
            del self._obj[self._integration.convert_renzmc_to_python(key)]
        except (KeyError, IndexError, TypeError) as e:
            raise RenzmcAttributeError(
                f"Error menghapus indeks pada objek Python: {str(e)}"
            )

    def __iter__(self):
        try:
            for item in self._obj:
                yield self._integration.convert_python_to_renzmc(item)
        except TypeError:
            raise RenzmcTypeError(
                f"Objek Python '{self._obj_type}' tidak dapat diiterasi"
            )

    def __next__(self):
        try:
            result = next(self._obj)
            return self._integration.convert_python_to_renzmc(result)
        except StopIteration:
            raise StopIteration
        except TypeError:
            raise RenzmcTypeError(f"Objek Python '{self._obj_type}' bukan iterator")

    def __len__(self):
        try:
            return len(self._obj)
        except TypeError:
            raise RenzmcTypeError(
                f"Objek Python '{self._obj_type}' tidak memiliki panjang"
            )

    def __contains__(self, item):
        try:
            return self._integration.convert_renzmc_to_python(item) in self._obj
        except TypeError:
            return False

    def __enter__(self):
        try:
            result = self._obj.__enter__()
            return self._integration.convert_python_to_renzmc(result)
        except AttributeError:
            raise RenzmcTypeError(
                f"Objek Python '{self._obj_type}' tidak mendukung context manager"
            )

    def __exit__(self, exc_type, exc_val, exc_tb):
        try:
            return self._obj.__exit__(exc_type, exc_val, exc_tb)
        except AttributeError:
            raise RenzmcTypeError(
                f"Objek Python '{self._obj_type}' tidak mendukung context manager"
            )

    def __eq__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            return self._obj == other_py
        except (TypeError, ValueError, AttributeError):
            return False

    def __ne__(self, other):
        return not self.__eq__(other)

    def __lt__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            return self._obj < other_py
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat membandingkan objek Python '{self._obj_type}'"
            )

    def __le__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            return self._obj <= other_py
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat membandingkan objek Python '{self._obj_type}'"
            )

    def __gt__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            return self._obj > other_py
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat membandingkan objek Python '{self._obj_type}'"
            )

    def __ge__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            return self._obj >= other_py
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat membandingkan objek Python '{self._obj_type}'"
            )

    def __add__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = self._obj + other_py
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat menambahkan pada objek Python '{self._obj_type}'"
            )

    def __sub__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = self._obj - other_py
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat mengurangi pada objek Python '{self._obj_type}'"
            )

    def __mul__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = self._obj * other_py
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat mengalikan pada objek Python '{self._obj_type}'"
            )

    def __truediv__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = self._obj / other_py
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat membagi pada objek Python '{self._obj_type}'"
            )

    def __mod__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = self._obj % other_py
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat modulo pada objek Python '{self._obj_type}'"
            )

    def __pow__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = self._obj**other_py
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat pangkat pada objek Python '{self._obj_type}'"
            )

    def __bool__(self):
        try:
            return bool(self._obj)
        except (TypeError, ValueError):
            return True

    def __hash__(self):
        try:
            return hash(self._obj)
        except TypeError:
            raise RenzmcTypeError(
                f"Objek Python '{self._obj_type}' tidak dapat di-hash"
            )

    def __str__(self):
        try:
            return str(self._obj)
        except (TypeError, ValueError):
            return f"SmartWrapper({self._obj_type})"

    def __repr__(self):
        try:
            return repr(self._obj)
        except (TypeError, ValueError):
            return f"<SmartPythonWrapper for {self._obj_type}>"

    def __dir__(self):
        try:
            return dir(self._obj)
        except (TypeError, AttributeError):
            return []

    def __format__(self, format_spec):
        try:
            return format(self._obj, format_spec)
        except (TypeError, ValueError):
            return str(self._obj)

    def __sizeof__(self):
        try:
            return self._obj.__sizeof__()
        except (TypeError, AttributeError):
            return object.__sizeof__(self)

    def __reduce__(self):
        try:
            return self._obj.__reduce__()
        except (TypeError, AttributeError):
            raise RenzmcTypeError(
                f"Objek Python '{self._obj_type}' tidak dapat di-pickle"
            )

    def __reduce_ex__(self, protocol):
        try:
            return self._obj.__reduce_ex__(protocol)
        except (TypeError, AttributeError):
            raise RenzmcTypeError(
                f"Objek Python '{self._obj_type}' tidak dapat di-pickle dengan protocol {protocol}"
            )

    def __copy__(self):
        try:
            import copy

            result = copy.copy(self._obj)
            return self._integration.convert_python_to_renzmc(result)
        except (TypeError, AttributeError) as e:
            raise RenzmcTypeError(
                f"Objek Python '{self._obj_type}' tidak dapat di-copy: {e}"
            )

    def __deepcopy__(self, memo):
        try:
            import copy

            result = copy.deepcopy(self._obj, memo)
            return self._integration.convert_python_to_renzmc(result)
        except (TypeError, AttributeError) as e:
            raise RenzmcTypeError(
                f"Objek Python '{self._obj_type}' tidak dapat di-deepcopy: {e}"
            )

    def __await__(self):
        try:
            if hasattr(self._obj, "__await__"):
                return self._obj.__await__()
            else:
                raise RenzmcTypeError(
                    f"Objek Python '{self._obj_type}' tidak mendukung await"
                )
        except Exception as e:
            raise RenzmcTypeError(f"Error dalam await: {str(e)}")

    def __aiter__(self):
        try:
            if hasattr(self._obj, "__aiter__"):
                result = self._obj.__aiter__()
                return self._integration.convert_python_to_renzmc(result)
            else:
                raise RenzmcTypeError(
                    f"Objek Python '{self._obj_type}' tidak mendukung async iteration"
                )
        except Exception as e:
            raise RenzmcTypeError(f"Error dalam async iteration: {str(e)}")

    def __anext__(self):
        try:
            if hasattr(self._obj, "__anext__"):
                result = self._obj.__anext__()
                return self._integration.convert_python_to_renzmc(result)
            else:
                raise RenzmcTypeError(
                    f"Objek Python '{self._obj_type}' tidak mendukung async next"
                )
        except Exception as e:
            raise RenzmcTypeError(f"Error dalam async next: {str(e)}")

    def __aenter__(self):
        try:
            if hasattr(self._obj, "__aenter__"):
                result = self._obj.__aenter__()
                return self._integration.convert_python_to_renzmc(result)
            else:
                raise RenzmcTypeError(
                    f"Objek Python '{self._obj_type}' tidak mendukung async context manager"
                )
        except Exception as e:
            raise RenzmcTypeError(f"Error dalam async context manager entry: {str(e)}")

    def __aexit__(self, exc_type, exc_val, exc_tb):
        try:
            if hasattr(self._obj, "__aexit__"):
                return self._obj.__aexit__(exc_type, exc_val, exc_tb)
            else:
                raise RenzmcTypeError(
                    f"Objek Python '{self._obj_type}' tidak mendukung async context manager"
                )
        except Exception as e:
            raise RenzmcTypeError(f"Error dalam async context manager exit: {str(e)}")

    def __and__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = self._obj & other_py
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat melakukan operasi AND pada objek Python '{self._obj_type}'"
            )

    def __or__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = self._obj | other_py
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat melakukan operasi OR pada objek Python '{self._obj_type}'"
            )

    def __xor__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = self._obj ^ other_py
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat melakukan operasi XOR pada objek Python '{self._obj_type}'"
            )

    def __lshift__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = self._obj << other_py
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat melakukan left shift pada objek Python '{self._obj_type}'"
            )

    def __rshift__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = self._obj >> other_py
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat melakukan right shift pada objek Python '{self._obj_type}'"
            )

    def __floordiv__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = self._obj // other_py
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat melakukan floor division pada objek Python '{self._obj_type}'"
            )

    def __divmod__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = divmod(self._obj, other_py)
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat melakukan divmod pada objek Python '{self._obj_type}'"
            )

    def __matmul__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = self._obj @ other_py
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat melakukan matrix multiplication pada objek Python '{self._obj_type}'"
            )

    def __radd__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = other_py + self._obj
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat menambahkan objek Python '{self._obj_type}' dari kanan"
            )

    def __rsub__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = other_py - self._obj
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat mengurangi objek Python '{self._obj_type}' dari kanan"
            )

    def __rmul__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = other_py * self._obj
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat mengalikan objek Python '{self._obj_type}' dari kanan"
            )

    def __rtruediv__(self, other):
        try:
            other_py = self._integration.convert_renzmc_to_python(other)
            result = other_py / self._obj
            return self._integration.convert_python_to_renzmc(result)
        except TypeError:
            raise RenzmcTypeError(
                f"Tidak dapat membagi objek Python '{self._obj_type}' dari kanan"
            )


class PythonModule:

    def __init__(self, module):
        self._module = module
        self._module_name = module.__name__
        self._cached_attributes = {}
        self._submodule_cache = {}

    def __getattr__(self, name):
        try:
            attr = getattr(self._module, name)
            if hasattr(attr, "__name__") and hasattr(attr, "__file__"):
                return PythonModule(attr)
            return attr
        except AttributeError:
            raise RenzmcAttributeError(
                f"Modul Python '{self._module_name}' tidak memiliki atribut '{name}'"
            )

    def __getitem__(self, key):
        try:
            if hasattr(self._module, "__getitem__"):
                return self._module[key]
            else:
                raise RenzmcAttributeError(
                    f"Modul Python '{self._module_name}' tidak mendukung indexing"
                )
        except (KeyError, IndexError, TypeError) as e:
            raise RenzmcAttributeError(
                f"Error mengakses indeks '{key}' pada modul '{self._module_name}': {str(e)}"
            )

    def __setitem__(self, key, value):
        try:
            if hasattr(self._module, "__setitem__"):
                self._module[key] = value
            else:
                raise RenzmcAttributeError(
                    f"Modul Python '{self._module_name}' tidak mendukung assignment"
                )
        except (KeyError, IndexError, TypeError) as e:
            raise RenzmcAttributeError(
                f"Error mengatur indeks '{key}' pada modul '{self._module_name}': {str(e)}"
            )

    def __iter__(self):
        if hasattr(self._module, "__iter__"):
            return iter(self._module)
        else:
            raise RenzmcTypeError(
                f"Modul Python '{self._module_name}' tidak dapat diiterasi"
            )

    def __len__(self):
        if hasattr(self._module, "__len__"):
            return len(self._module)
        else:
            raise RenzmcTypeError(
                f"Modul Python '{self._module_name}' tidak memiliki panjang"
            )

    def __call__(self, *args, **kwargs):
        if callable(self._module):
            return self._module(*args, **kwargs)
        raise RenzmcTypeError(
            f"Modul Python '{self._module_name}' tidak dapat dipanggil"
        )

    def __repr__(self):
        return f"<PythonModule '{self._module_name}'>"

    def __str__(self):
        return f"PythonModule({self._module_name})"

    def __dir__(self):
        return dir(self._module)


class PythonIntegration:

    def __init__(self):
        self.imported_modules = {}
        self.module_aliases = {}
        self.from_imports = {}

    def setup_python_builtins(self, global_scope):
        for name in dir(py_builtins):
            if not name.startswith("_"):
                global_scope[f"py_{name}"] = getattr(py_builtins, name)

    def import_python_module(self, module_name, alias=None, from_items=None):
        try:
            if module_name in self.imported_modules:
                module = self.imported_modules[module_name]
            else:
                module = importlib.import_module(module_name)
                self.imported_modules[module_name] = module
            if from_items:
                imported_items = {}
                for item in from_items:
                    if hasattr(module, item):
                        imported_items[item] = getattr(module, item)
                    else:
                        raise RenzmcImportError(
                            f"Tidak dapat mengimpor '{item}' dari modul Python '{module_name}'"
                        )
                self.from_imports[module_name] = imported_items
                return imported_items
            wrapped_module = PythonModule(module)
            if alias:
                self.module_aliases[alias] = wrapped_module
            return wrapped_module
        except ImportError as e:
            raise RenzmcImportError(
                f"Tidak dapat mengimpor modul Python '{module_name}': {str(e)}"
            )
        except Exception as e:
            raise RenzmcImportError(
                f"Error saat mengimpor modul Python '{module_name}': {str(e)}"
            )

    def get_module_attribute(self, module_name, attribute_name):
        if module_name in self.module_aliases:
            module = self.module_aliases[module_name]._module
        elif module_name in self.imported_modules:
            module = self.imported_modules[module_name]
        else:
            raise RenzmcImportError(f"Modul Python '{module_name}' belum diimpor")
        try:
            return getattr(module, attribute_name)
        except AttributeError:
            raise RenzmcAttributeError(
                f"Modul Python '{module_name}' tidak memiliki atribut '{attribute_name}'"
            )

    def call_python_function(self, func, *args, **kwargs):
        try:
            if callable(func):
                return func(*args, **kwargs)
            else:
                raise RenzmcTypeError(f"Objek '{func}' tidak dapat dipanggil")
        except Exception as e:
            raise RenzmcTypeError(f"Error dalam pemanggilan fungsi Python: {str(e)}")

    def create_python_object(self, class_obj, *args, **kwargs):
        try:
            if isinstance(class_obj, type):
                return class_obj(*args, **kwargs)
            else:
                raise RenzmcTypeError(f"'{class_obj}' bukan kelas Python yang valid")
        except Exception as e:
            raise RenzmcTypeError(f"Error saat membuat objek Python: {str(e)}")

    def list_module_attributes(self, module_name):
        if module_name in self.module_aliases:
            module = self.module_aliases[module_name]._module
        elif module_name in self.imported_modules:
            module = self.imported_modules[module_name]
        else:
            raise RenzmcImportError(f"Modul Python '{module_name}' belum diimpor")
        return [attr for attr in dir(module) if not attr.startswith("_")]

    def get_python_help(self, obj):
        try:
            import pydoc

            return pydoc.render_doc(obj)
        except Exception:
            return f"Tidak dapat mendapatkan bantuan untuk objek: {obj}"

    def install_package(self, package_name):
        try:
            import subprocess

            result = subprocess.run(
                [sys.executable, "-m", "pip", "install", package_name],
                capture_output=True,
                text=True,
            )
            return result.returncode == 0
        except Exception:
            return False

    def get_all_python_modules(self):
        try:
            import pkgutil

            return [name for _, name, _ in pkgutil.iter_modules()]
        except Exception:
            return []

    def auto_import_on_demand(self, module_name):
        try:
            if module_name not in self.imported_modules:
                module = importlib.import_module(module_name)
                self.imported_modules[module_name] = module
                return PythonModule(module)
            else:
                return PythonModule(self.imported_modules[module_name])
        except ImportError:
            return None

    def import_all_from_module(self, module_name):
        try:
            if module_name in self.imported_modules:
                module = self.imported_modules[module_name]
            else:
                module = importlib.import_module(module_name)
                self.imported_modules[module_name] = module
            all_attrs = {}
            if hasattr(module, "__all__"):
                for name in module.__all__:
                    if hasattr(module, name):
                        all_attrs[name] = self.convert_python_to_renzmc(
                            getattr(module, name)
                        )
            else:
                for name in dir(module):
                    if not name.startswith("_"):
                        all_attrs[name] = self.convert_python_to_renzmc(
                            getattr(module, name)
                        )
            return all_attrs
        except ImportError as e:
            raise RenzmcImportError(
                f"Tidak dapat mengimpor semua dari modul Python '{module_name}': {str(e)}"
            )
        except Exception as e:
            raise RenzmcImportError(
                f"Error saat mengimpor semua dari modul Python '{module_name}': {str(e)}"
            )

    def reload_module(self, module_name):
        try:
            if module_name in self.imported_modules:
                module = importlib.reload(self.imported_modules[module_name])
                self.imported_modules[module_name] = module
                return PythonModule(module)
            else:
                raise RenzmcImportError(f"Modul Python '{module_name}' belum diimpor")
        except Exception as e:
            raise RenzmcImportError(
                f"Error saat reload modul Python '{module_name}': {str(e)}"
            )

    def get_module_path(self, module_name):
        if module_name in self.imported_modules:
            module = self.imported_modules[module_name]
            if hasattr(module, "__file__"):
                return module.__file__
            else:
                return f"<built-in module '{module_name}'>"
        else:
            raise RenzmcImportError(f"Modul Python '{module_name}' belum diimpor")

    def list_available_modules(self):
        try:
            import pkgutil

            modules = []
            for importer, modname, ispkg in pkgutil.iter_modules():
                modules.append(modname)
            return sorted(modules)
        except Exception:
            return []

    def check_module_available(self, module_name):
        try:
            importlib.util.find_spec(module_name)
            return True
        except (ImportError, ModuleNotFoundError, ValueError):
            return False

    def get_module_version(self, module_name):
        if module_name in self.imported_modules:
            module = self.imported_modules[module_name]
            for attr in ["__version__", "VERSION", "version"]:
                if hasattr(module, attr):
                    return str(getattr(module, attr))
            return "Unknown"
        else:
            raise RenzmcImportError(f"Modul Python '{module_name}' belum diimpor")

    def import_submodule(self, parent_module, submodule_name):
        try:
            full_name = f"{parent_module}.{submodule_name}"
            if full_name in self.imported_modules:
                module = self.imported_modules[full_name]
            else:
                module = importlib.import_module(full_name)
                self.imported_modules[full_name] = module
            return PythonModule(module)
        except ImportError as e:
            raise RenzmcImportError(
                f"Tidak dapat mengimpor submodul '{submodule_name}' dari '{parent_module}': {str(e)}"
            )

    def execute_python_code(self, code_string, local_vars=None):
        try:
            if local_vars is None:
                local_vars = {}
            exec(code_string, globals(), local_vars)
            converted_vars = {}
            for key, value in local_vars.items():
                if not key.startswith("_"):
                    converted_vars[key] = self.convert_python_to_renzmc(value)
            return converted_vars
        except Exception as e:
            raise Exception(f"Error saat menjalankan kode Python: {str(e)}")

    def evaluate_python_expression(self, expression):
        try:
            result = eval(expression)
            return self.convert_python_to_renzmc(result)
        except Exception as e:
            raise Exception(f"Error saat evaluasi ekspresi Python: {str(e)}")

    def convert_python_to_renzmc(self, obj):
        if obj is None:
            return None
        if isinstance(obj, (int, float, str, bool, bytes)):
            return obj
        if self._is_module_object(obj):
            return PythonModule(obj)
        if isinstance(obj, type):
            return self.create_smart_wrapper(obj)
        if hasattr(obj, "__iter__") and hasattr(obj, "__next__"):
            return self.create_smart_wrapper(obj)
        if hasattr(obj, "__iter__") and (not isinstance(obj, (str, bytes))):
            try:
                if isinstance(obj, dict):
                    return {
                        self.convert_python_to_renzmc(k): self.convert_python_to_renzmc(
                            v
                        )
                        for k, v in obj.items()
                    }
                elif isinstance(obj, list):
                    return [self.convert_python_to_renzmc(item) for item in obj]
                elif isinstance(obj, tuple):
                    return tuple((self.convert_python_to_renzmc(item) for item in obj))
                elif isinstance(obj, set):
                    return {self.convert_python_to_renzmc(item) for item in obj}
                else:
                    return self.create_smart_wrapper(obj)
            except (TypeError, RecursionError):
                return self.create_smart_wrapper(obj)
        if callable(obj) and (not isinstance(obj, type)):

            def enhanced_wrapper(*args, **kwargs):
                try:
                    py_args = [self.convert_renzmc_to_python(arg) for arg in args]
                    py_kwargs = {
                        k: self.convert_renzmc_to_python(v) for k, v in kwargs.items()
                    }
                    result = obj(*py_args, **py_kwargs)
                    return self.convert_python_to_renzmc(result)
                except Exception as e:
                    raise RenzmcTypeError(
                        f"Error dalam pemanggilan fungsi Python: {str(e)}"
                    )

            try:
                enhanced_wrapper.__name__ = getattr(obj, "__name__", "python_function")
                enhanced_wrapper.__doc__ = getattr(obj, "__doc__", None)
            except (TypeError, AttributeError):
                pass
            return enhanced_wrapper
        if hasattr(obj, "__dict__") or hasattr(obj, "__getattr__"):
            return self.create_smart_wrapper(obj)
        special_methods = [
            "__getitem__",
            "__setitem__",
            "__len__",
            "__contains__",
            "__enter__",
            "__exit__",
            "__add__",
            "__sub__",
            "__mul__",
            "__call__",
            "__getattribute__",
            "__delattr__",
            "__hash__",
            "__repr__",
            "__str__",
            "__bool__",
            "__format__",
            "__sizeof__",
        ]
        if any((hasattr(obj, method) for method in special_methods)):
            return self.create_smart_wrapper(obj)
        if self._is_coroutine_or_async(obj):
            return self.create_smart_wrapper(obj)
        if self._is_file_like(obj):
            return self.create_smart_wrapper(obj)
        if isinstance(obj, BaseException):
            return self.create_smart_wrapper(obj)
        try:
            import json

            json.dumps(obj)
            return obj
        except (TypeError, ValueError):
            return self.create_smart_wrapper(obj)

    def convert_renzmc_to_python(self, obj):
        if obj is None:
            return None
        if isinstance(obj, (int, float, str, bool, bytes)):
            return obj
        if isinstance(obj, SmartPythonWrapper):
            return obj._obj
        if isinstance(obj, PythonModule):
            return obj._module
        if hasattr(obj, "__iter__") and (not isinstance(obj, (str, bytes))):
            try:
                if isinstance(obj, dict):
                    return {
                        self.convert_renzmc_to_python(k): self.convert_renzmc_to_python(
                            v
                        )
                        for k, v in obj.items()
                    }
                elif isinstance(obj, list):
                    return [self.convert_renzmc_to_python(item) for item in obj]
                elif isinstance(obj, tuple):
                    return tuple((self.convert_renzmc_to_python(item) for item in obj))
                elif isinstance(obj, set):
                    return {self.convert_renzmc_to_python(item) for item in obj}
                else:
                    try:
                        return [self.convert_renzmc_to_python(item) for item in obj]
                    except (TypeError, AttributeError):
                        return obj
            except (TypeError, RecursionError):
                return obj
        if callable(obj):
            if hasattr(obj, "__name__") and obj.__name__ == "enhanced_wrapper":
                return obj
            return obj
        return obj

    def create_smart_wrapper(self, obj):
        return SmartPythonWrapper(obj, self)

    def enable_star_imports(self, module_name, global_scope):
        try:
            module_wrapper = self.import_python_module(module_name)
            imported_count = 0
            if isinstance(module_wrapper, PythonModule):
                actual_module = module_wrapper._module
            elif isinstance(module_wrapper, dict):
                for key, value in module_wrapper.items():
                    if isinstance(value, PythonModule):
                        actual_module = value._module
                        break
                else:
                    return 0
            else:
                actual_module = module_wrapper
            if hasattr(actual_module, "__all__"):
                items = actual_module.__all__
            else:
                items = [
                    name for name in dir(actual_module) if not name.startswith("_")
                ]
            for item_name in items:
                if hasattr(actual_module, item_name):
                    global_scope[item_name] = self.convert_python_to_renzmc(
                        getattr(actual_module, item_name)
                    )
                    imported_count += 1
            return imported_count
        except Exception:
            return 0

    def _is_module_object(self, obj):
        if hasattr(obj, "__name__") and hasattr(obj, "__file__"):
            return True
        if hasattr(obj, "__name__") and hasattr(obj, "__package__"):
            return True
        import types as module_types

        return isinstance(obj, module_types.ModuleType)

    def _is_coroutine_or_async(self, obj):
        import inspect as inspect_module

        return (
            inspect_module.iscoroutine(obj)
            or inspect_module.iscoroutinefunction(obj)
            or inspect_module.isasyncgenfunction(obj)
            or inspect_module.isasyncgen(obj)
            or hasattr(obj, "__await__")
            or hasattr(obj, "__aenter__")
            or hasattr(obj, "__aexit__")
        )

    def _is_file_like(self, obj):
        file_methods = ["read", "write", "close", "flush", "seek", "tell"]
        return any((hasattr(obj, method) for method in file_methods))

    def enhance_smart_wrapper_compatibility(self, wrapper_obj):
        if not isinstance(wrapper_obj, SmartPythonWrapper):
            return wrapper_obj
        original_obj = wrapper_obj._obj
        special_methods = [
            "__format__",
            "__sizeof__",
            "__reduce__",
            "__reduce_ex__",
            "__getstate__",
            "__setstate__",
            "__copy__",
            "__deepcopy__",
            "__enter__",
            "__exit__",
            "__aenter__",
            "__aexit__",
            "__await__",
            "__aiter__",
            "__anext__",
        ]
        for method_name in special_methods:
            if hasattr(original_obj, method_name) and (
                not hasattr(wrapper_obj, method_name)
            ):

                def create_method_wrapper(method):

                    def wrapper_method(*args, **kwargs):
                        try:
                            result = method(*args, **kwargs)
                            return self.convert_python_to_renzmc(result)
                        except Exception as e:
                            raise RenzmcTypeError(
                                f"Error dalam method {method.__name__}: {str(e)}"
                            )

                    return wrapper_method

                setattr(
                    wrapper_obj,
                    method_name,
                    create_method_wrapper(getattr(original_obj, method_name)),
                )
        return wrapper_obj
