import signal
from time import sleep
import concurrent.futures as futures
from typing import Optional, Union, List
from datetime import datetime, timedelta, UTC
from pyqttier import Mqtt5Connection, MqttTransportType, MqttTransport
from {{stinger.python.package_name}}.client import {{stinger.python.client_class_name}}, {{stinger.python.client_class_name}}Builder, {{stinger.python.client_class_name}}Discoverer
from {{stinger.python.package_name}}.interface_types import *
import threading

{% if (stinger.methods|length + stinger.properties_rw|length) > 0%}
def request_loop(client: {{stinger.python.client_class_name}}):
    """Example request loop that runs in a separate thread."""
    sleep(30)
    while True:
        {%-for method_name, method in stinger.methods.items()%}
        print("Making call to '{{method_name|snake_case}}'")
        future_resp = client.{{method_name|snake_case}}({%for arg in method.arg_list%}{{arg.name|snake_case}}={{arg.get_random_example_value()}}{%if not loop.last%}, {%endif%}{%endfor%})
        try:
            print(f"RESULT:  {future_resp.result(5)}")
        except futures.TimeoutError:
            print(f"Timed out waiting for response to '{{method_name|snake_case}}' call")
        sleep(5)
        {%endfor%}{# for each method #}
        {%for prop_name, prop in stinger.properties_rw.items()%}
        {%if prop.arg_list|length > 1%}
        client.{{prop_name|snake_case}} = {{prop_name|UpperCamelCase}}Property(
            {%-for arg in prop.arg_list%}
            {{arg.name|snake_case}}={{arg.get_random_example_value()}},
            {%-endfor%}
        )
        {%else%}
        client.{{prop_name|snake_case}} = {{prop.arg_list[0].get_random_example_value()}}
        {%endif%} {# end propertly length cases #}
        {%endfor%} {# for each property #}
        sleep(10)
{%endif%} {# any methods or properties #}

if __name__ == '__main__':

    transport = MqttTransport(MqttTransportType.TCP, "localhost", 1883)
    conn = Mqtt5Connection(transport)

    client_builder = {{stinger.python.client_class_name}}Builder()
    {%for sig_name, sig in stinger.signals.items()%}
    @client_builder.receive_{{sig_name | snake_case }}
    def print_{{sig_name}}_receipt({%for arg in sig.arg_list%}{{arg.name}}: {{arg.python_annotation}}{%if not loop.last%}, {%endif%}{%endfor%}):
        """{{sig.description}}
        {%for arg in sig.arg_list-%}
        @param {{arg.name}} {{arg.python_annotation}} {{arg.description or ''}}
        {%endfor%}"""
        print(f"Got a '{{sig_name}}' signal: {%for arg in sig.arg_list%}{{arg.name}}={ {{arg.name}}{% if 'bytes' in arg.python_annotation %}!r{%endif-%} } {%endfor%}")
    {%endfor%}
    {%for prop_name, prop in stinger.properties.items()%}
    @client_builder.{{prop_name | snake_case}}_updated
    def print_new_{{prop_name}}_value(value: {{prop.python_annotation}}):
        """{{prop.description}}
        """
        print(f"Property '{{prop_name}}' has been updated to: {value{% if 'bytes' in prop.python_annotation %}!r{%endif-%} }")
    {%endfor%}

    discovery = {{stinger.python.client_class_name}}Discoverer(conn, client_builder)
    fut_client = discovery.get_singleton_client()
    try:
        client = fut_client.result(10)
    except futures.TimeoutError:
        print("Timed out waiting for a service to appear")
        exit(1)

    sleep(2)

    threading.Thread(target=request_loop, args=(client,), daemon=True).start()

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