{%- import "cloudevents.jinja.include" as cloudEvents -%}
{%- import "mqtt.jinja.include" as mqtt -%}
{%- import "util.jinja.include" as util -%}
{{ util.CommonFileHeader() }}
{%- set messagegroups = root.messagegroups %}
{%- set uses_cloudevents_message = (root | exists("envelope","CloudEvents/1.0")) %}
{%- set uses_mqtt_message = (root | exists( "protocol", "mqtt")) %}
{%- set uses_mqtt_endpoint = (root | exists("protocol", "mqtt")) %}

#nullable enable

using CloudNative.CloudEvents;
using CloudNative.CloudEvents.SystemTextJson;
using MQTTnet;
using MQTTnet.Client;

{% for messagegroupid, messagegroup in messagegroups.items() -%}
{%- set groupname = messagegroupid | pascal -%}
namespace {{ groupname | concat_namespace(project_name) | pascal }}
{
    {%- set class_name = (groupname | strip_namespace) + "Producer" %}
    /// <summary>
    /// Producer class to send events in the `{{ messagegroupid }}` message group.
    /// </summary>
    public partial class {{ class_name }}
    {
        {%- if root.endpoints -%}
        {%- for endpointid, endpoint in root.endpoints.items() -%}
                {%- if endpoint.usage and "producer" in endpoint.usage -%}
        {%- set protocol = endpoint.protocol | lower -%}
        {%- if protocol == "mqtt" -%}
        {%- set options = endpoint.protocoloptions -%}
        {%- set endpoints = endpoint.endpoints %}
        {%- macro createforbody(class_name, endpoints, options) -%}
            var options = new MqttClientOptionsBuilder()
                .WithClientId("{{ class_name }}Client")
                {% set ep = endpoints[0] if len(endpoints) > 0 else None %}
                {% if ep %}
                .WithTcpServer("{{ ep.uri }}")
                {% endif %}
                .WithCleanSession()
                .Build();
            var factory = new MqttFactory();
            var client = factory.CreateMqttClient();
            return new {{ class_name }}(client);
        {%- endmacro %}

        /// <summary>
        /// Create a new instance of the `IMqttClient` for the {{ endpointid }} endpoint.
        /// </summary>
        /// <returns>A new instance of the `IMqttClient`.</returns>
        public static {{ class_name }} CreateFor{{ endpointid | pascal | strip_namespace }}() 
        {   
            {{ createforbody(class_name, endpoints, options) }}
        }
        {%- endif -%}
        {%- endif -%}
        {%- endfor -%}
        {% endif %}

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="client">The MQTT client instance.</param>
        public {{ class_name }}(IMqttClient client)
        {
            this.Client = client;
        }

        /// <summary>
        /// MQTT client
        /// </summary>
        public IMqttClient Client
        {
            get; private set;
        }

        {% for messageid, message in messagegroup.messages.items() -%}
        {%- set messagename = messageid | pascal %}
        {%- set isCloudEvent = cloudEvents.isCloudEvent(message) %}
        {%- set isMqtt = not isCloudEvent and message.envelope and message.envelope.lower().startswith("mqtt") %}
        {%- set type_name = util.body_type(data_project_name, root, message) -%}
        {%- if isCloudEvent %}
        {%- set uriargs = cloudEvents.DeclareUriTemplateArguments(message) -%}
        {%- elif isMqtt %}
        {%- set uriargs = mqtt.DeclareUriTemplateArguments(message) -%}
        {%- endif %}
        /// <summary>
        /// Publish the `{{ messagename }}` event
        {%- if message.description %}
        /// Event description: "{{ message.description }}"
        {%- endif %}
        /// </summary>
        /// <param name="data">The event data object.</param>
        {%- if uriargs %}
        {%- for arg in uriargs.split(',') if arg.strip() %}
        {%- set splitarg = arg.strip().split(' ') %}
        /// <param name="{{ splitarg[1] }}"> URI template argument</param>
        {%- endfor %}
        {%- endif %}
        /// <param name="topic">Optional topic name override. If not provided, uses the default topic '{{ mqtt.GetDefaultTopic(message, messageid) }}'.</param>
        /// <param name="contentType">The desired content type of the message data.</param>
        {%- if isCloudEvent %}
        /// <param name="formatter">The CloudEvent formatter to use for structured mode, e.g. JsonEventFormatter.</param>
        {%- endif %}
        /// <returns>A `Task` object representing the asynchronous publish operation.</returns>
        public async Task Send{{ messagename | strip_namespace }}Async(
        {{ type_name }} data
        {%- if uriargs -%}
        {{- uriargs -}}
        {%- endif -%}
        , string? topic = null
        {%- if isCloudEvent and "datacontenttype" in message.envelopemetadata and "value" in message.envelopemetadata["datacontenttype"] -%}
        , string contentType = "{{ message.envelopemetadata["datacontenttype"]["value"] }}"
        {%- else -%}
        , string contentType = System.Net.Mime.MediaTypeNames.Application.Json
        {%- endif %}
        {%- if isCloudEvent %}, CloudEventFormatter? formatter = null{% endif %})
        {
            var topicName = topic ?? "{{ mqtt.GetDefaultTopic(message, messageid) }}";
            
            var message = {{groupname | strip_namespace}}EventFactory.Create{{ messagename | strip_namespace }}Message(topicName, data,
                {%- if uriargs %}
                {%- for arg in uriargs.split(',') if arg.strip() %}
                {%- set splitarg = arg.strip().split(' ') %}
                {{- splitarg[1] -}},
                {%- endfor -%}
                {%- endif -%}
                contentType
                {%- if isCloudEvent %}, formatter{% endif -%}
            );
            await this.Client.PublishAsync(message);
        }

        {% endfor %}
    }
}
{% endfor -%}
