from __future__ import annotations
{% if module.uses_records() %}

from dataclasses import dataclass
{% endif %}
{% if module.uses_c_style_enums() %}

from enum import IntEnum
{% endif %}
{% if module.has_native_callables() %}

import sys
from pathlib import Path
{% endif %}
{% if module.uses_records() || module.uses_c_style_enums() || module.has_native_callables() %}

from . import _native
{% endif %}
{% if module.has_native_callables() %}

def _shared_library_filename() -> str:
    if sys.platform == "win32":
        return "{{ module.library_name }}.dll"
    if sys.platform == "darwin":
        return "lib{{ module.library_name }}.dylib"
    return "lib{{ module.library_name }}.so"

_native._initialize_loader(str(Path(__file__).resolve().with_name(_shared_library_filename())))
{% endif %}
{% if module.uses_records() %}

{% for record in module.records %}
@dataclass(frozen=True, slots=True)
class {{ record.class_name() }}:
{% for field in record.fields.iter() %}
    {{ field.python_name }}: {{ field.annotation() }}
{% endfor %}
{% for constructor in record.constructors %}

    @classmethod
    def {{ constructor.python_name }}(cls{% if !constructor.callable.parameters.is_empty() %}, {% for parameter in constructor.callable.parameters %}{{ parameter.name }}: {{ parameter.type_ref.parameter_annotation() }}{% if !loop.last %}, {% endif %}{% endfor %}{% endif %}) -> {{ constructor.callable.return_type.return_annotation() }}:
        return _native.{{ constructor.callable.native_name }}({% for parameter in constructor.callable.parameters %}{{ parameter.name }}{% if !loop.last %}, {% endif %}{% endfor %})
{% endfor %}
{% for method in record.methods %}

{% if method.is_static %}
    @staticmethod
    def {{ method.python_name }}({% for parameter in method.public_parameters() %}{{ parameter.name }}: {{ parameter.type_ref.parameter_annotation() }}{% if !loop.last %}, {% endif %}{% endfor %}) -> {{ method.callable.return_type.return_annotation() }}:
        return _native.{{ method.callable.native_name }}({% for parameter in method.public_parameters() %}{{ parameter.name }}{% if !loop.last %}, {% endif %}{% endfor %})
{% else %}
    def {{ method.python_name }}(self{% if !method.public_parameters().is_empty() %}, {% for parameter in method.public_parameters() %}{{ parameter.name }}: {{ parameter.type_ref.parameter_annotation() }}{% if !loop.last %}, {% endif %}{% endfor %}{% endif %}) -> {{ method.callable.return_type.return_annotation() }}:
        return _native.{{ method.callable.native_name }}(self{% if !method.public_parameters().is_empty() %}, {% for parameter in method.public_parameters() %}{{ parameter.name }}{% if !loop.last %}, {% endif %}{% endfor %}{% endif %})
{% endif %}
{% endfor %}

_native.{{ record.type_ref.registration_function_name() }}({{ record.class_name() }})
{% endfor %}
{% endif %}
{% if module.uses_c_style_enums() %}

{% for enumeration in module.enums %}
class {{ enumeration.class_name() }}(IntEnum):
{% for variant in enumeration.variants %}
    {{ variant.member_name }} = {{ variant.native_value }}
{% endfor %}
{% if enumeration.constructors.is_empty() && enumeration.methods.is_empty() %}
    pass
{% endif %}
{% for constructor in enumeration.constructors %}

    @classmethod
    def {{ constructor.python_name }}(cls{% if !constructor.callable.parameters.is_empty() %}, {% for parameter in constructor.callable.parameters %}{{ parameter.name }}: {{ parameter.type_ref.parameter_annotation() }}{% if !loop.last %}, {% endif %}{% endfor %}{% endif %}) -> {{ constructor.callable.return_type.return_annotation() }}:
        return _native.{{ constructor.callable.native_name }}({% for parameter in constructor.callable.parameters %}{{ parameter.name }}{% if !loop.last %}, {% endif %}{% endfor %})
{% endfor %}
{% for method in enumeration.methods %}

{% if method.is_static %}
    @staticmethod
    def {{ method.python_name }}({% for parameter in method.public_parameters() %}{{ parameter.name }}: {{ parameter.type_ref.parameter_annotation() }}{% if !loop.last %}, {% endif %}{% endfor %}) -> {{ method.callable.return_type.return_annotation() }}:
        return _native.{{ method.callable.native_name }}({% for parameter in method.public_parameters() %}{{ parameter.name }}{% if !loop.last %}, {% endif %}{% endfor %})
{% else %}
    def {{ method.python_name }}(self{% if !method.public_parameters().is_empty() %}, {% for parameter in method.public_parameters() %}{{ parameter.name }}: {{ parameter.type_ref.parameter_annotation() }}{% if !loop.last %}, {% endif %}{% endfor %}{% endif %}) -> {{ method.callable.return_type.return_annotation() }}:
        return _native.{{ method.callable.native_name }}(self{% if !method.public_parameters().is_empty() %}, {% for parameter in method.public_parameters() %}{{ parameter.name }}{% if !loop.last %}, {% endif %}{% endfor %}{% endif %})
{% endif %}
{% endfor %}

_native.{{ enumeration.type_ref.registration_function_name() }}({{ enumeration.class_name() }})
{% endfor %}
{% endif %}
{% if !module.functions.is_empty() %}

{% for function in module.functions %}
{{ function.python_name }} = _native.{{ function.python_name }}
{% endfor %}
{% endif %}

MODULE_NAME = {{ module.module_name_literal() }}
PACKAGE_NAME = {{ module.package_name_literal() }}
PACKAGE_VERSION = {{ module.package_version_literal() }}

__all__ = [
    "MODULE_NAME",
    "PACKAGE_NAME",
    "PACKAGE_VERSION",
{% for record in module.records %}
    "{{ record.class_name() }}",
{% endfor %}
{% for enumeration in module.enums %}
    "{{ enumeration.class_name() }}",
{% endfor %}
{% for function in module.functions %}
    "{{ function.python_name }}",
{% endfor %}
]
