{%- import "cloudevents.jinja.include" as cloudEvents %}
{%- import "util.jinja.include" as util -%}
{%- set messagegroups = root.messagegroups %}
{%- set uses_ce_message = (root | exists("envelope","CloudEvents/1.0")) %}
{%- set uses_plain_kafka_message = (root | exists( "protocol", "kafka" )) %}
// 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 { Kafka, Producer, Consumer } from 'kafkajs';
import { KafkaContainer, StartedKafkaContainer } from '@testcontainers/kafka';
{%- if uses_ce_message %}
import { CloudEvent } from 'cloudevents';
{%- endif %}
import { KafkaProcessor } from '../src/tools';
{% for messagegroupid, messagegroup in messagegroups.items() -%}
{%- set pascal_group_name = messagegroupid | pascal %}
{%- set class_name = ( pascal_group_name | strip_namespace ) + "EventDispatcher" %}
import { {{ class_name }} } from '../src/dispatcher';
{%- endfor %}

describe('{{ project_name }} Kafka Consumer Tests', () => {
    let kafkaContainer: StartedKafkaContainer;
    let kafka: Kafka;
    let producer: Producer;
    let consumer: Consumer;
    let bootstrapServers: string;
    const topicName = 'testtopic';
    
    beforeAll(async () => {
        // Start Kafka container using official testcontainers module
        kafkaContainer = await new KafkaContainer('confluentinc/cp-kafka:7.5.0')
            .withKraft()
            .start();
            
        const host = kafkaContainer.getHost();
        const port = kafkaContainer.getMappedPort(9093);
        bootstrapServers = `${host}:${port}`;
        
        // Give Kafka time to fully initialize
        await new Promise(resolve => setTimeout(resolve, 10000));
        
        kafka = new Kafka({
            clientId: 'test-client',
            brokers: [bootstrapServers],
            retry: {
                initialRetryTime: 100,
                retries: 8
            }
        });
        
        // Create single shared topic for all tests (matches C# pattern)
        const admin = kafka.admin();
        await admin.connect();
        await admin.createTopics({
            topics: [{
                topic: topicName,
                numPartitions: 1,
                replicationFactor: 1
            }]
        });
        await admin.disconnect();
        
        // Create producer
        producer = kafka.producer();
        await producer.connect();
    }, 60000);
    
    afterAll(async () => {
        if (producer) {
            await producer.disconnect();
        }
        if (consumer) {
            await consumer.disconnect();
        }
        if (kafkaContainer) {
            await kafkaContainer.stop();
        }
    });
    
    beforeEach(async () => {
        // Create a new consumer with unique group ID for each test
        const groupId = `test-group-${Date.now()}-${Math.random()}`;
        consumer = kafka.consumer({ groupId });
        await consumer.connect();
    });
    
    afterEach(async () => {
        if (consumer) {
            await consumer.disconnect();
        }
    });
    
    {% for messagegroupid, messagegroup in messagegroups.items() -%}
    {%- set uses_cloudevents_message = (messagegroup | exists("envelope","CloudEvents/1.0")) %}
    {%- set pascal_group_name = messagegroupid | pascal %}
    {%- set class_name = ( pascal_group_name | strip_namespace ) + "EventDispatcher" %}
    
    describe('{{ pascal_group_name }} Message Group', () => {
        {% for messageid, message in messagegroup.messages.items() -%}
        {%- set messagename = messageid | strip_namespace | pascal -%}
        {%- set message_body_type = util.body_type(data_project_name, root, message) -%}
        {%- set isCloudEvent = cloudEvents.isCloudEvent(message) %}
        
        test('should receive and dispatch {{ messagename }} event', async () => {
            const dispatcher = new {{ class_name }}();
            const processor = new KafkaProcessor(consumer, topicName);
            
            const receivedMessages: any[] = [];
            let receivedCount = 0;
            
            dispatcher.{{ messagename }}Handler = async (message, {% if isCloudEvent %}cloudEvent, {% endif %}data) => {
                receivedMessages.push({ message, {% if isCloudEvent %}cloudEvent, {% endif %}data });
                receivedCount++;
            };
            
            processor.processMessage = async (payload) => {
                await dispatcher.processMessage(payload);
            };
            
            // Start consuming
            const processorPromise = processor.start();
            
            // Wait a bit for consumer to be ready
            await new Promise(resolve => setTimeout(resolve, 2000));
            
            // Send 5 test messages
            {%- if isCloudEvent %}
            const testData = { test: 'data' };
            for (let i = 0; i < 5; i++) {
                const cloudEvent = new CloudEvent({
                    {%- if "type" in message.envelopemetadata and "value" in message.envelopemetadata["type"] %}
                    type: '{{ message.envelopemetadata["type"]["value"] }}',
                    {%- else %}
                    type: '{{ messageid }}',
                    {%- endif %}
                    source: 'test/source',
                    id: `test-${i}`,
                    data: testData
                });
                
                await producer.send({
                    topic: topicName,
                    messages: [{
                        headers: {
                            'content-type': 'application/cloudevents+json'
                        },
                        value: JSON.stringify(cloudEvent)
                    }]
                });
            }
            {%- else %}
            const testData = { test: 'data' };
            for (let i = 0; i < 5; i++) {
                await producer.send({
                    topic: topicName,
                    messages: [{
                        headers: {
                            'subject': '{{ messageid }}',
                            'content-type': 'application/json'
                        },
                        value: JSON.stringify(testData)
                    }]
                });
            }
            {%- endif %}
            
            // Wait for all messages to be processed
            await new Promise(resolve => setTimeout(resolve, 5000));
            
            // Stop processor
            await processor.stop();
            
            // Verify all 5 messages received
            expect(receivedMessages.length).toBe(5);
            expect(receivedCount).toBe(5);
            {%- if isCloudEvent %}
            {%- if "type" in message.envelopemetadata and "value" in message.envelopemetadata["type"] %}
            expect(receivedMessages[0].cloudEvent.type).toBe('{{ message.envelopemetadata["type"]["value"] }}');
            {%- else %}
            expect(receivedMessages[0].cloudEvent.type).toBe('{{ messageid }}');
            {%- endif %}
            {%- endif %}
            expect(receivedMessages[0].data).toMatchObject({ test: 'data' });
        }, 30000);
        {% endfor %}
    });
    {% endfor %}
});
