{%- import "cloudevents.jinja.include" as cloudEvents -%}
{%- import "util.jinja.include" as util -%}
{%- set data_module_name = data_project_name | strip_invalid_identifier_characters %}
// This code was generated by the xRegistry tool.
// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.

import { EventHubProducerClient, EventData } from '@azure/event-hubs';
import { TokenCredential, DefaultAzureCredential } from '@azure/identity';
{%- set messagegroups = root.messagegroups %}
{%- set uses_cloudevents_message = cloudEvents.usesCloudEvents(root) %}
{%- if uses_cloudevents_message %}
import { CloudEvent, HTTP } from 'cloudevents';
{%- endif %}
import { v4 as uuidv4 } from 'uuid';

// Import data types (need to compile data project first: cd ../{{ data_project_name }} && npm install && npm run build)
// NOTE: In real usage, the data project should be a proper npm package dependency
import * as {{ data_module_name }} from '../../{{ data_project_name }}/dist/index.js';

{% for messagegroupid, messagegroup in messagegroups.items() -%}
{%- set groupname = messagegroupid | pascal -%}
{%- set class_name = (groupname | strip_namespace) + "Producer" %}

/**
 * Producer class to send events in the `{{ messagegroupid }}` message group.
 */
export class {{ class_name }} {
    private client: EventHubProducerClient;
    private mode: 'binary' | 'structured';
    private format: string;
    
    /**
     * Constructor
     * @param client The Azure Event Hubs producer client
     * @param mode CloudEvents binding mode: 'binary' or 'structured' (default: 'structured')
     * @param format CloudEvents format for structured mode (default: 'application/json')
     */
    constructor(client: EventHubProducerClient, mode: 'binary' | 'structured' = 'structured', format: string = 'application/json') {
        this.client = client;
        this.mode = mode;
        this.format = format;
    }
    
    {%- 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 == "amqp" %}
    {%- set options = endpoint.protocoloptions %}
    {%- set endpoints = endpoint.endpoints %}
    
    /**
     * Create a new instance for the {{ endpointid }} endpoint
     * @param credential The Azure credential to use for authentication
     * @param fullyQualifiedNamespace The fully qualified namespace of the Event Hub
     * @param eventHubName The name of the Event Hub
     * @returns A new instance of {{ class_name }}
     */
    static createFor{{ endpointid | pascal | strip_namespace }}(
        credential?: TokenCredential,
        fullyQualifiedNamespace?: string,
        eventHubName?: string
    ): {{ class_name }} {
        const cred = credential || new DefaultAzureCredential();
        const ns = fullyQualifiedNamespace || {% if endpoints %}'{{ endpoints[0].uri }}'{% else %}''{% endif %};
        const hub = eventHubName || {% if options and 'node' in options %}'{{ options['node'] }}'{% else %}''{% endif %};
        
        if (!ns) {
            throw new Error('fullyQualifiedNamespace is required');
        }
        if (!hub) {
            throw new Error('eventHubName is required');
        }
        
        const client = new EventHubProducerClient(ns, hub, cred);
        return new {{ class_name }}(client);
    }
    {%- endif %}
    {%- endif %}
    {%- endfor %}
    {%- endif %}
    
    {% for messageid, message in messagegroup.messages.items() -%}
    {%- set messagename = messageid | pascal | strip_namespace %}
    {%- set isCloudEvent = cloudEvents.isCloudEvent(message) %}
    {%- set type_name = util.body_type(data_project_name, root, message) %}
    
    /**
     * Send the `{{ messagename }}` event
     {%- if message.description %}
     * Event description: "{{ message.description }}"
     {%- endif %}
     * @param data The event data object
     {%- if isCloudEvent %}
     {%- for attrname in ['source', 'type'] if attrname not in message.envelopemetadata %}
     * @param {{ attrname }} CloudEvent required attribute '{{ attrname }}'
     {%- endfor %}
     {%- for attrname, attribute in message.envelopemetadata.items() if attribute.type == "uritemplate" %}
     {%- for placeholder in attribute.value | regex_search('\\{([A-Za-z0-9_]+)\\}') %}
     * @param {{ placeholder }} Value for placeholder {{ placeholder }} in attribute {{ attrname }}
     {%- endfor %}
     {%- endfor %}
     {%- for attrname, attribute in message.envelopemetadata.items() if attribute.value is not defined and attrname not in ["time", "id", "datacontenttype", "dataschema"] %}
     * @param {{ attrname }} CloudEvent {{ attrname }} attribute{% if not attribute.required %} (optional){% endif %}
     {%- endfor %}
     {%- endif %}
     * @param contentType The content type of the message data
     * @returns Promise that resolves when the event is sent
     */
    async send{{ messagename }}(
        data: {{ type_name }},
        {%- if isCloudEvent %}
        {%- for attrname in ['source', 'type'] if attrname not in message.envelopemetadata %}
        {{ attrname }}: string,
        {%- endfor %}
        {%- for attrname, attribute in message.envelopemetadata.items() if attribute.type == "uritemplate" %}
        {%- for placeholder in attribute.value | regex_search('\\{([A-Za-z0-9_]+)\\}') %}
        {{ placeholder }}: string,
        {%- endfor %}
        {%- endfor %}
        {%- for attrname, attribute in message.envelopemetadata.items() if attribute.value is not defined and attrname not in ["time", "id", "datacontenttype", "dataschema"] %}
        {{ attrname }}{% if not attribute.required %}?{% endif %}: string,
        {%- endfor %}
        {%- endif %}
        contentType: string = 'application/json'
    ): Promise<void> {
        {%- if isCloudEvent %}
        const cloudEvent = new CloudEvent({
        {%- for attrname in ['source', 'type'] if attrname not in message.envelopemetadata %}
        {%- if attrname == "type" %}
            type: {{ attrname }},
        {%- elif attrname == "source" %}
            source: {{ attrname }},
        {%- endif %}
        {%- endfor %}
        {%- for attrname, attribute in message.envelopemetadata.items() %}
        {%- if attrname == "type" %}
            type: {% if attribute.value %}'{{ attribute.value }}'{% else %}{{ attrname }}{% endif %},
        {%- elif attrname == "source" %}
            source: {% if attribute.value %}{% if attribute.type == "uritemplate" %}`{{ attribute.value | regex_replace('\\{([A-Za-z0-9_]+)\\}', '${\\1}') }}`{% else %}'{{ attribute.value }}'{% endif %}{% else %}{{ attrname }} || '/producer'{% endif %},
        {%- elif attrname in ["id", "time"] %}
            {# id and time are auto-generated #}
        {%- elif attrname == "datacontenttype" %}
            {# handled separately #}
        {%- elif attrname == "dataschema" %}
            {# handled separately if needed #}
        {%- elif attribute.value %}
            {{ attrname }}: {% if attribute.type == "uritemplate" %}`{{ attribute.value | regex_replace('\\{([A-Za-z0-9_]+)\\}', '${\\1}') }}`{% else %}'{{ attribute.value }}'{% endif %},
        {%- else %}
            {% if not attribute.required %}...({{ attrname }} && { {{ attrname }} }),{% else %}{{ attrname }},{% endif %}
        {%- endif %}
        {%- endfor %}
            id: uuidv4(),
            data: data,
            datacontenttype: contentType
        });
        
        let eventData: EventData;
        if (this.mode === 'structured') {
            // Structured content mode - entire CloudEvent as JSON payload
            eventData = {
                body: cloudEvent.toJSON(),
                contentType: this.format
            };
        } else {
            // Binary content mode - CloudEvent attributes as properties, data as body
            eventData = {
                body: data,
                contentType: contentType,
                properties: {
                    'ce_specversion': '1.0',
                    'ce_id': cloudEvent.id,
                    'ce_type': cloudEvent.type,
                    'ce_source': cloudEvent.source
                }
            };
            
            {%- for attrname, attribute in message.envelopemetadata.items() %}
            {%- if attrname not in ["id", "type", "source", "specversion", "datacontenttype", "data"] %}
            if (cloudEvent.{{ attrname }}) {
                eventData.properties!['ce_{{ attrname }}'] = String(cloudEvent.{{ attrname }});
            }
            {%- endif %}
            {%- endfor %}
        }
        {%- else %}
        const eventData: EventData = {
            body: data,
            properties: {
                subject: '{{ messageid }}'
            }
        };
        
        if (contentType) {
            eventData.contentType = contentType;
        }
        {%- endif %}
        
        await this.client.sendBatch([eventData]);
    }
    
    /**
     * Send multiple `{{ messagename }}` events in a batch
     * @param dataArray Array of event data objects
     {%- if isCloudEvent %}
     {%- for attrname in ['source', 'type'] if attrname not in message.envelopemetadata %}
     * @param {{ attrname }} CloudEvent required attribute '{{ attrname }}'
     {%- endfor %}
     {%- for attrname, attribute in message.envelopemetadata.items() if attribute.type == "uritemplate" %}
     {%- for placeholder in attribute.value | regex_search('\\{([A-Za-z0-9_]+)\\}') %}
     * @param {{ placeholder }} Value for placeholder {{ placeholder }} in attribute {{ attrname }}
     {%- endfor %}
     {%- endfor %}
     {%- for attrname, attribute in message.envelopemetadata.items() if attribute.value is not defined and attrname not in ["time", "id", "datacontenttype", "dataschema"] %}
     * @param {{ attrname }} CloudEvent {{ attrname }} attribute{% if not attribute.required %} (optional){% endif %}
     {%- endfor %}
     {%- endif %}
     * @param contentType The content type of the message data
     * @returns Promise that resolves when all events are sent
     */
    async send{{ messagename }}Batch(
        dataArray: {{ type_name }}[],
        {%- if isCloudEvent %}
        {%- for attrname in ['source', 'type'] if attrname not in message.envelopemetadata %}
        {{ attrname }}: string,
        {%- endfor %}
        {%- for attrname, attribute in message.envelopemetadata.items() if attribute.type == "uritemplate" %}
        {%- for placeholder in attribute.value | regex_search('\\{([A-Za-z0-9_]+)\\}') %}
        {{ placeholder }}: string,
        {%- endfor %}
        {%- endfor %}
        {%- for attrname, attribute in message.envelopemetadata.items() if attribute.value is not defined and attrname not in ["time", "id", "datacontenttype", "dataschema"] %}
        {{ attrname }}{% if not attribute.required %}?{% endif %}: string,
        {%- endfor %}
        {%- endif %}
        contentType: string = 'application/json'
    ): Promise<void> {
        const eventDataArray: EventData[] = dataArray.map(data => {
            {%- if isCloudEvent %}
            const cloudEvent = new CloudEvent({
            {%- for attrname in ['source', 'type'] if attrname not in message.envelopemetadata %}
            {%- if attrname == "type" %}
                type: {{ attrname }},
            {%- elif attrname == "source" %}
                source: {{ attrname }},
            {%- endif %}
            {%- endfor %}
            {%- for attrname, attribute in message.envelopemetadata.items() %}
            {%- if attrname == "type" %}
                type: {% if attribute.value %}'{{ attribute.value }}'{% else %}{{ attrname }}{% endif %},
            {%- elif attrname == "source" %}
                source: {% if attribute.value %}{% if attribute.type == "uritemplate" %}`{{ attribute.value | regex_replace('\\{([A-Za-z0-9_]+)\\}', '${\\1}') }}`{% else %}'{{ attribute.value }}'{% endif %}{% else %}{{ attrname }} || '/producer'{% endif %},
            {%- elif attrname in ["id", "time"] %}
                {# id and time are auto-generated #}
            {%- elif attrname == "datacontenttype" %}
                {# handled separately #}
            {%- elif attrname == "dataschema" %}
                {# handled separately if needed #}
            {%- elif attribute.value %}
                {{ attrname }}: {% if attribute.type == "uritemplate" %}`{{ attribute.value | regex_replace('\\{([A-Za-z0-9_]+)\\}', '${\\1}') }}`{% else %}'{{ attribute.value }}'{% endif %},
            {%- else %}
                {% if not attribute.required %}...({{ attrname }} && { {{ attrname }} }),{% else %}{{ attrname }},{% endif %}
            {%- endif %}
            {%- endfor %}
                id: uuidv4(),
                data: data,
                datacontenttype: contentType
            });
            
            if (this.mode === 'structured') {
                // Structured content mode
                return {
                    body: cloudEvent.toJSON(),
                    contentType: this.format
                };
            } else {
                // Binary content mode
                const properties: Record<string, any> = {
                    'ce_specversion': '1.0',
                    'ce_id': cloudEvent.id,
                    'ce_type': cloudEvent.type,
                    'ce_source': cloudEvent.source
                };
                
                {%- for attrname, attribute in message.envelopemetadata.items() %}
                {%- if attrname not in ["id", "type", "source", "specversion", "datacontenttype", "data"] %}
                if (cloudEvent.{{ attrname }}) {
                    properties['ce_{{ attrname }}'] = String(cloudEvent.{{ attrname }});
                }
                {%- endif %}
                {%- endfor %}
                
                return {
                    body: data,
                    contentType: contentType,
                    properties
                };
            }
            {%- else %}
            const eventData: EventData = {
                body: data,
                properties: {
                    subject: '{{ messageid }}'
                }
            };
            
            if (contentType) {
                eventData.contentType = contentType;
            }
            
            return eventData;
            {%- endif %}
        });
        
        await this.client.sendBatch(eventDataArray);
    }
    {% endfor %}
    
    /**
     * Close the producer client
     */
    async close(): Promise<void> {
        await this.client.close();
    }
}
{% endfor %}
