"""
Generated by Stinger-IPC code generator.
"""

from time import sleep
import signal
import os
from typing import Optional, Union, List
from datetime import datetime, timedelta, UTC
from pyqttier import Mqtt5Connection, MqttTransportType, MqttTransport
from {{stinger.python.package_name}}.server import {{stinger.python.server_class_name}}
{% if stinger.properties|length > 0 -%}
from {{stinger.python.package_name}}.property import {%if config.properties.stinger_owned_values %}{{stinger.name|UpperCamelCase}}InitialPropertyValues{%else%}{{stinger.name|UpperCamelCase}}PropertyAccess{%endif%}
{%endif%} {#- end has properties -#}
from {{stinger.python.package_name}}.interface_types import *

{%if (stinger.properties|length > 0) and (not config.properties.stinger_owned_values) %}
class {{stinger.name|UpperCamelCase}}PropertyOwnership:
    def __init__(self):
        {%-for prop_name, prop in stinger.properties.items()%}
        self._{{prop_name|snake_case}} = {##}
            {%-if prop.arg_list|length > 1 -%}
            {{prop_name|UpperCamelCase}}Property(
                {%-for arg in prop.arg_list%}
                {{arg.name|snake_case}}={{arg.get_random_example_value()}},
                {%-endfor%}
            )
            {%-else -%} {# else single value property #}
            {{-prop.arg_list[0].get_random_example_value()}}
            {%-endif %} {# end property value cases #}
        {%-endfor%} {# end property foreach #}

    {%-for prop_name, prop in stinger.properties.items()%}
    def get_property_{{prop_name|snake_case}}(self):
        """Return the value for the '{{prop_name|snake_case}}' property."""
        return self._{{prop_name|snake_case}}

    {%-if not prop.read_only%}
    def set_property_{{prop_name|snake_case}}(self, value: {{prop.python_annotation}}):
        """Set the value for the '{{prop_name|snake_case}}' property."""
        self._{{prop_name|snake_case}} = value
    {%-endif%} {# end read only #}
    {%endfor%} {# end property foreach #}
{%endif%}{# end has some app-owned values #}

if __name__ == '__main__':
    """
    This shows an example on how to run the code.  Ideally, your app should do something similar, but use the methods in
    a more meaningful way.
    """
    {%if stinger.properties | length > 0 %}
    {% if config.properties.stinger_owned_values %}
    initial_property_values = {{stinger.name|UpperCamelCase}}InitialPropertyValues(
        {%- for prop_name, prop in stinger.properties.items() %}
        {{prop_name | snake_case}}=
            {%-if prop.arg_list | length > 1%}
            {{prop.python_class}}(
                {%for arg in prop.arg_list%}
                {{arg.name|snake_case}}={{arg.get_random_example_value()}},
                {%endfor%}
            ),
            {%-else-%}
            {{prop.arg_list[0].get_random_example_value()}},
            {%endif%}
        {{prop_name | snake_case}}_version={{loop.index}},
        {%endfor%}{# end foreach property#}
    )
    {%else%} {# app-owned properties #}
    property_owner = {{stinger.name|UpperCamelCase}}PropertyOwnership()
    property_access = {{stinger.name|UpperCamelCase}}PropertyAccess(
        {%for prop_name, prop in stinger.properties.items()%}
        {{prop_name | snake_case}}_getter=property_owner.get_property_{{prop_name | snake_case}},
        {%-if not prop.read_only%}
        {{prop_name | snake_case}}_setter=property_owner.set_property_{{prop_name | snake_case}},
        {%-endif%}
        {%endfor%}{# end foreach property#}
    )
    {%endif%} {# end stinger/app owned properties#}
    {%endif%} {# end has properties #}
    
    transport = MqttTransport(MqttTransportType.TCP, "localhost", 1883)
    conn = Mqtt5Connection(transport, client_id=os.environ.get("CLIENT_ID", "py-server-demo"))
    server = {{stinger.python.server_class_name}}(conn, os.environ.get("SERVICE_ID", "py-server-demo:1"){%if stinger.properties | length > 0 %}, {% if config.properties.stinger_owned_values %}initial_property_values{%else%}property_access{%endif%}{%endif%})

    {%for method_name, method in stinger.methods.items()%}
    @server.handle_{{method_name | snake_case}} 
    def {{method_name | snake_case}}({%for arg in method.arg_list%}{{arg.name}}: {{arg.python_annotation}}{%if not loop.last%}, {%endif%}{%endfor%}) -> {{method.return_value_python_annotation}}:
        """ This is an example handler for the '{{method_name}}' method.  """
        print(f"--> Running {{method_name | snake_case}}({%for arg in method.arg_list %}{ {{-arg.name-}}{% if 'bytes' in arg.python_annotation %}!r{%endif-%} }{%if not loop.last%}, {%endif%}{%endfor%})'")
        return {{method.get_return_value_random_example_value('python')}}
    {%endfor%}

    {%for prop_name, prop in stinger.properties.items()%}
    @server.on_{{prop_name | snake_case}}_updated
    def on_{{prop_name | snake_case}}_update({%for arg in prop.arg_list %}{{arg.name}}: {{arg.python_annotation}}{%if not loop.last%}, {%endif%}{%endfor%}):
        """ Example callback for when the '{{prop_name}}' property is updated. """
        print(f"~~> Received update for '{{prop_name}}' property: {%for arg in prop.arg_list %}{ {{arg.name}}= }{%if not loop.last%}, {%endif%}{%endfor%}")
    {%endfor%}

    print("Ctrl-C will stop the program.")

    while True:
        try:
            {%for sig_name, sig in stinger.signals.items()-%}
            server.emit_{{sig_name|snake_case}}({%for arg in sig.arg_list%}{{arg.get_random_example_value()}}{%if not loop.last%}, {%endif%}{%endfor%})
            {%endfor%}
            sleep(4)
            {%for sig_name, sig in stinger.signals.items()-%}
            server.emit_{{sig_name|snake_case}}({%for arg in sig.arg_list%}{{arg.name|snake_case}}={{arg.get_random_example_value()}}{%if not loop.last%}, {%endif%}{%endfor%})
            {%endfor%}
            sleep(42)
        except KeyboardInterrupt:
            break

    signal.pause()
