package rabbitmq

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

	amqp "github.com/rabbitmq/amqp091-go"
	"github.com/rwadurian/mpc-system/services/account/application/ports"
)

const (
	exchangeName = "account.events"
	exchangeType = "topic"
)

// EventPublisherAdapter implements EventPublisher using RabbitMQ
type EventPublisherAdapter struct {
	conn    *amqp.Connection
	channel *amqp.Channel
}

// NewEventPublisherAdapter creates a new EventPublisherAdapter
func NewEventPublisherAdapter(conn *amqp.Connection) (*EventPublisherAdapter, error) {
	channel, err := conn.Channel()
	if err != nil {
		return nil, err
	}

	// Declare exchange
	err = channel.ExchangeDeclare(
		exchangeName,
		exchangeType,
		true,  // durable
		false, // auto-deleted
		false, // internal
		false, // no-wait
		nil,   // arguments
	)
	if err != nil {
		channel.Close()
		return nil, err
	}

	return &EventPublisherAdapter{
		conn:    conn,
		channel: channel,
	}, nil
}

// Publish publishes an account event
func (p *EventPublisherAdapter) Publish(ctx context.Context, event ports.AccountEvent) error {
	body, err := json.Marshal(event)
	if err != nil {
		return err
	}

	routingKey := string(event.Type)

	return p.channel.PublishWithContext(ctx,
		exchangeName,
		routingKey,
		false, // mandatory
		false, // immediate
		amqp.Publishing{
			ContentType:  "application/json",
			DeliveryMode: amqp.Persistent,
			Timestamp:    time.Now().UTC(),
			Body:         body,
		},
	)
}

// Close closes the publisher
func (p *EventPublisherAdapter) Close() error {
	if p.channel != nil {
		return p.channel.Close()
	}
	return nil
}
