{%- import "cloudevents.jinja.include" as cloudEvents -%}
{%- import "kafka.jinja.include" as kafka -%}
{%- import "util.jinja.include" as util -%}
// This code was auto-generated by xRegistry CLI
// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.

package {{ project_name | snake }}_test

import (
	"context"
	"encoding/json"
	"fmt"
	"testing"
	"time"

	"github.com/segmentio/kafka-go"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	testcontainers "github.com/testcontainers/testcontainers-go"
	"github.com/testcontainers/testcontainers-go/wait"
	
	{{ data_project_name | snake }} "github.com/username/{{ data_project_name | snake }}/pkg/{{ data_project_name }}"
	. "{{ project_name | snake }}"
)

// setupKafka creates a Kafka container for testing
func setupKafka(t *testing.T) (string, func()) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
	defer cancel()

	req := testcontainers.ContainerRequest{
		Image:        "confluentinc/cp-kafka:7.5.0",
		ExposedPorts: []string{"9092/tcp", "29092/tcp"},
		Env: map[string]string{
			"KAFKA_BROKER_ID":                    "1",
			"KAFKA_ZOOKEEPER_CONNECT":           "localhost:2181",
			"KAFKA_ADVERTISED_LISTENERS":        "PLAINTEXT://localhost:29092,PLAINTEXT_INTERNAL://kafka:9092",
			"KAFKA_LISTENER_SECURITY_PROTOCOL_MAP": "PLAINTEXT:PLAINTEXT,PLAINTEXT_INTERNAL:PLAINTEXT",
			"KAFKA_INTER_BROKER_LISTENER_NAME":  "PLAINTEXT_INTERNAL",
			"KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR": "1",
		},
		WaitingFor: wait.ForListeningPort("9092/tcp"),
	}

	container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
		ContainerRequest: req,
		Started:          true,
	})
	require.NoError(t, err)

	// Get the bootstrap server address
	host, err := container.Host(ctx)
	require.NoError(t, err)
	port, err := container.MappedPort(ctx, "29092")
	require.NoError(t, err)

	bootstrapServer := fmt.Sprintf("%s:%s", host, port.Port())

	// Create test topic
	conn, err := kafka.Dial("tcp", bootstrapServer)
	require.NoError(t, err)
	defer conn.Close()

	err = conn.CreateTopics(
		kafka.TopicConfig{
			Topic:             "test-topic",
			NumPartitions:     1,
			ReplicationFactor: 1,
		},
	)
	if err != nil && err.Error() != "Topic already exists" {
		require.NoError(t, err)
	}

	cleanup := func() {
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		defer cancel()
		container.Terminate(ctx)
	}

	return bootstrapServer, cleanup
}

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

{%- for messageid, message in messagegroup.messages.items() %}
{%- set messagename = messageid | pascal | strip_namespace %}
{%- set message_body_type = util.body_type(data_project_name, root, message) %}
{%- set topic = kafka.get_topic(message) or messageid %}
{%- set isCloudEvent = cloudEvents.isCloudEvent(message) %}
{%- set needs_source_param = "source" not in message.envelopemetadata %}
{%- if "source" in message.envelopemetadata and message.envelopemetadata.source.value %}
{%- set source_value = message.envelopemetadata.source.value %}
{%- if "{" in source_value and "}" in source_value %}
{%- set needs_source_param = true %}
{%- endif %}
{%- endif %}

func Test{{ class_name }}_{{ messagename }}(t *testing.T) {
	bootstrapServer, cleanup := setupKafka(t)
	defer cleanup()

	// Create producer
	producer, err := New{{ class_name }}(bootstrapServer)
	require.NoError(t, err)
	defer producer.Close()

	// Create consumer to verify message was sent
	reader := kafka.NewReader(kafka.ReaderConfig{
		Brokers:        []string{bootstrapServer},
		Topic:          "{{ topic }}",
		GroupID:        "test-consumer",
		StartOffset:    kafka.LastOffset,
		CommitInterval: time.Second,
	})
	defer reader.Close()

	// Create test data
	{%- if "[]" in message_body_type %}
	testData := {{ message_body_type | replace(data_project_name | snake + ".", "") }}(nil)
	{%- else %}
	testData := {{ data_project_name | snake }}.{{ message_body_type | replace("*", "") | replace(data_project_name | snake + ".", "") }}{}
	{%- endif %}

	// Send message
	sendCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	err = producer.Send{{ messagename }}(sendCtx, testData{% if isCloudEvent %}{% if needs_source_param %}, "tenant123/device456"{% endif %}{% if "type" not in message.envelopemetadata %}, "{{ messageid }}"{% endif %}{% for attrname, attribute in message.envelopemetadata.items() if attribute.required and not attribute.value %}, "test"{% endfor %}{% endif %})
	require.NoError(t, err)

	// Verify message received
	readCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	msg, err := reader.FetchMessage(readCtx)
	require.NoError(t, err)
	assert.NotEmpty(t, msg.Value)

	// Verify content
	{%- if "[]" in message_body_type %}
	// Binary payload - just verify it's not empty
	assert.NotEmpty(t, msg.Value, "Expected message to contain data")
	{%- else %}
	var receivedData {{ data_project_name | snake }}.{{ message_body_type | replace("*", "") | replace(data_project_name | snake + ".", "") }}
	if msg.Value[0] == '{' {
		err = json.Unmarshal(msg.Value, &receivedData)
		require.NoError(t, err)
	}
	{%- endif %}

	// Commit message
	err = reader.CommitMessages(readCtx, msg)
	require.NoError(t, err)
}

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