{%- 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"
	"sync"
	"testing"
	"time"

	cloudevents "github.com/cloudevents/sdk-go/v2"
	"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 setupKafkaConsumerTest(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 + "Consumer" %}

// Mock handler for testing
type Mock{{ class_name }}Handler struct {
	mu       sync.Mutex
	messages map[string]int
}

func NewMock{{ class_name }}Handler() *Mock{{ class_name }}Handler {
	return &Mock{{ class_name }}Handler{
		messages: make(map[string]int),
	}
}

{%- 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 isCloudEvent = cloudEvents.isCloudEvent(message) %}

func (m *Mock{{ class_name }}Handler) Handle{{ messagename }}(ctx context.Context, {% if isCloudEvent %}event cloudevents.Event, {% endif %}data {{ message_body_type }}) error {
	m.mu.Lock()
	defer m.mu.Unlock()
	m.messages["{{ messageid }}"]++
	return nil
}

{%- endfor %}

func (m *Mock{{ class_name }}Handler) HandleError(ctx context.Context, err error) {
	// Log errors but don't fail the handler
	fmt.Printf("Handler error: %v\n", err)
}

{%- 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 %}

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

	// Create producer to send test message
	writer := &kafka.Writer{
		Addr:     kafka.TCP(bootstrapServer),
		Topic:    "{{ topic }}",
		Balancer: &kafka.LeastBytes{},
	}
	defer writer.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 %}
	dataBytes, _ := json.Marshal(testData)

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

	err := writer.WriteMessages(ctx, kafka.Message{
		Topic: "{{ topic }}",
		Value: dataBytes,
	})
	require.NoError(t, err)

	// Create consumer with mock handler
	handler := NewMock{{ class_name }}Handler()
	consumer, err := New{{ class_name }}(bootstrapServer, "test-group", []string{"{{ topic }}"}, handler)
	require.NoError(t, err)
	defer consumer.Close()

	// Start consumer in goroutine
	consumerCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	go func() {
		consumer.Start(consumerCtx)
	}()

	// Wait for message to be consumed
	time.Sleep(2 * time.Second)

	// Stop consumer
	consumer.Stop()

	// Verify handler was called
	handler.mu.Lock()
	count := handler.messages["{{ messageid }}"]
	handler.mu.Unlock()

	assert.Greater(t, count, 0, "Expected handler to receive message")
}

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