package app

import (
	"context"

	"hyapp/pkg/appcode"
	"hyapp/pkg/rocketmqx"
	servicemq "hyapp/pkg/servicekit/mq"
	"hyapp/pkg/walletmq"
	"hyapp/services/wallet-service/internal/config"
	walletservice "hyapp/services/wallet-service/internal/service/wallet"
)

func (a *App) startMQ() error {
	if err := servicemq.StartProducers([]*rocketmqx.Producer{a.outboxProducer, a.realtimeOutboxProducer}); err != nil {
		return err
	}
	if err := servicemq.StartConsumers([]*rocketmqx.Consumer{a.projectionConsumer}); err != nil {
		servicemq.ShutdownProducers([]*rocketmqx.Producer{a.outboxProducer, a.realtimeOutboxProducer})
		return err
	}
	return nil
}

func (a *App) shutdownMQ() {
	servicemq.ShutdownConsumers([]*rocketmqx.Consumer{a.projectionConsumer})
	servicemq.ShutdownProducers([]*rocketmqx.Producer{a.outboxProducer, a.realtimeOutboxProducer})
}

func newWalletProjectionConsumer(cfg config.Config, svc *walletservice.Service) (*rocketmqx.Consumer, error) {
	if svc == nil || !cfg.ProjectionWorker.Enabled {
		return nil, nil
	}
	// 钱包自有投影只关心礼物墙和徽章发放事实；兼容 selector 同时保留
	// legacy Tag，待旧消息排空后可在后续阶段只留下这三个 typed Tag。
	tagExpression, err := walletmq.LegacyCompatibleTagExpression(
		walletmq.EventTypeWalletGiftDebited,
		walletmq.EventTypeResourceGranted,
		walletmq.EventTypeResourceGroupGranted,
	)
	if err != nil {
		return nil, err
	}
	consumer, err := rocketmqx.NewConsumer(rocketMQProjectionConsumerConfig(cfg.RocketMQ, cfg.ProjectionWorker))
	if err != nil {
		return nil, err
	}
	workerID := "wallet-projection-" + cfg.NodeID
	if err := consumer.Subscribe(cfg.RocketMQ.WalletOutbox.Topic, tagExpression, func(ctx context.Context, message rocketmqx.ConsumedMessage) error {
		walletMessage, err := walletmq.DecodeWalletOutboxMessage(message.Body)
		if err != nil {
			return err
		}
		_, err = svc.ProcessWalletProjectionMessage(appcode.WithContext(ctx, walletMessage.AppCode), workerID, walletMessage, cfg.ProjectionWorker.LockTTL)
		return err
	}); err != nil {
		_ = consumer.Shutdown()
		return nil, err
	}
	return consumer, nil
}

func rocketMQProjectionConsumerConfig(cfg config.RocketMQConfig, projection config.ProjectionWorkerConfig) rocketmqx.ConsumerConfig {
	return rocketmqx.ConsumerConfig{
		EndpointConfig: rocketmqx.EndpointConfig{
			NameServers:      cfg.NameServers,
			NameServerDomain: cfg.NameServerDomain,
			AccessKey:        cfg.AccessKey,
			SecretKey:        cfg.SecretKey,
			SecurityToken:    cfg.SecurityToken,
			Namespace:        cfg.Namespace,
			VIPChannel:       cfg.VIPChannel,
		},
		GroupName:         projection.ConsumerGroup,
		MaxReconsumeTimes: projection.ConsumerMaxReconsumeTimes,
		ConsumePullBatch:  int32(projection.BatchSize),
	}
}

func rocketMQProducerConfig(cfg config.RocketMQConfig, groupName string) rocketmqx.ProducerConfig {
	return rocketmqx.ProducerConfig{
		EndpointConfig: rocketmqx.EndpointConfig{
			NameServers:      cfg.NameServers,
			NameServerDomain: cfg.NameServerDomain,
			AccessKey:        cfg.AccessKey,
			SecretKey:        cfg.SecretKey,
			SecurityToken:    cfg.SecurityToken,
			Namespace:        cfg.Namespace,
			VIPChannel:       cfg.VIPChannel,
		},
		GroupName:   groupName,
		SendTimeout: cfg.SendTimeout,
		Retry:       cfg.Retry,
	}
}

func shutdownProducers(producers ...*rocketmqx.Producer) {
	servicemq.ShutdownProducers(producers)
}
