package app

import (
	"errors"

	roomv1 "hyapp.local/api/proto/room/v1"
	walletv1 "hyapp.local/api/proto/wallet/v1"
	"hyapp/pkg/tencentim"
	activityclient "hyapp/services/activity-service/internal/client"
	"hyapp/services/activity-service/internal/config"
	achievementservice "hyapp/services/activity-service/internal/service/achievement"
	activityservice "hyapp/services/activity-service/internal/service/activity"
	broadcastservice "hyapp/services/activity-service/internal/service/broadcast"
	cumulativerechargeservice "hyapp/services/activity-service/internal/service/cumulativerecharge"
	firstrechargeservice "hyapp/services/activity-service/internal/service/firstrecharge"
	growthservice "hyapp/services/activity-service/internal/service/growth"
	inviteactivityservice "hyapp/services/activity-service/internal/service/inviteactivity"
	luckygiftservice "hyapp/services/activity-service/internal/service/luckygift"
	messageservice "hyapp/services/activity-service/internal/service/message"
	registrationrewardservice "hyapp/services/activity-service/internal/service/registrationreward"
	roomturnoverrewardservice "hyapp/services/activity-service/internal/service/roomturnoverreward"
	sevendaycheckinservice "hyapp/services/activity-service/internal/service/sevendaycheckin"
	taskservice "hyapp/services/activity-service/internal/service/task"
	weeklystarservice "hyapp/services/activity-service/internal/service/weeklystar"
	mysqlstorage "hyapp/services/activity-service/internal/storage/mysql"
)

type serviceBundle struct {
	activity                    *activityservice.Service
	message                     *messageservice.Service
	task                        *taskservice.Service
	registrationReward          *registrationrewardservice.Service
	sevenDayCheckIn             *sevendaycheckinservice.Service
	growth                      *growthservice.Service
	achievement                 *achievementservice.Service
	weeklyStar                  *weeklystarservice.Service
	roomTurnoverReward          *roomturnoverrewardservice.Service
	broadcast                   *broadcastservice.Service
	luckyGift                   *luckygiftservice.Service
	firstRechargeReward         *firstrechargeservice.Service
	cumulativeRecharge          *cumulativerechargeservice.Service
	inviteActivityReward        *inviteactivityservice.Service
	broadcastPublisherAvailable bool
}

func buildServiceBundle(cfg config.Config, repository *mysqlstorage.Repository, clients externalClients) (*serviceBundle, error) {
	walletClient := walletv1.NewWalletServiceClient(clients.walletConn)
	roomClient := roomv1.NewRoomQueryServiceClient(clients.roomConn)

	activitySvc := activityservice.New(activityservice.Config{NodeID: cfg.NodeID}, repository)
	messageSvc := messageservice.New(messageservice.Config{NodeID: cfg.NodeID}, repository, messageservice.WithTargetSource(activityclient.NewGRPCUserTargetSource(clients.userConn)))
	taskSvc := taskservice.New(repository, walletClient)
	registrationRewardSvc := registrationrewardservice.New(repository, walletClient)
	sevenDayCheckInSvc := sevendaycheckinservice.New(repository, walletClient)
	growthSvc := growthservice.New(repository, walletClient)
	achievementSvc := achievementservice.New(repository, walletClient)
	weeklyStarSvc := weeklystarservice.New(repository, walletClient)
	roomTurnoverRewardSvc := roomturnoverrewardservice.New(repository, walletClient, roomClient)

	// Tencent IM 是区域广播、房间礼物播报和红包播报的外部发布器。
	// 如果配置要求启动广播 worker，就必须先确认 publisher 可用，避免 worker 启动后只写 outbox 不发消息。
	var tencentClient *tencentim.RESTClient
	var broadcastPublisher broadcastservice.Publisher
	if cfg.TencentIM.Enabled {
		client, err := tencentim.NewRESTClient(cfg.TencentIM.RESTConfig())
		if err != nil {
			return nil, err
		}
		tencentClient = client
		broadcastPublisher = client
	}
	if cfg.Broadcast.Enabled && broadcastPublisher == nil {
		return nil, errors.New("broadcast worker requires tencent_im.enabled")
	}

	broadcastSvc := broadcastservice.New(broadcastservice.Config{
		NodeID:                cfg.NodeID,
		SuperGiftMinValue:     cfg.Broadcast.SuperGiftMinValue,
		WorkerBatchSize:       cfg.Broadcast.WorkerBatchSize,
		WorkerLockTTL:         cfg.Broadcast.WorkerLockTTL,
		WorkerMaxRetry:        cfg.Broadcast.WorkerMaxRetry,
		WorkerPollInterval:    cfg.Broadcast.WorkerPollInterval,
		EnsureGroupsOnStartup: cfg.Broadcast.EnsureGroupsOnStartup,
		GroupIDPrefix:         cfg.TencentIM.GroupIDPrefix,
	}, repository, broadcastPublisher, activityclient.NewGRPCRegionSource(clients.userConn))
	broadcastSvc.SetSenderProfileSource(activityclient.NewGRPCUserProfileSource(clients.userConn))

	luckyGiftSvc := luckygiftservice.New(repository,
		luckygiftservice.WithWallet(walletClient),
		luckygiftservice.WithRoomPublisher(tencentClient),
		luckygiftservice.WithRegionBroadcaster(broadcastSvc),
	)
	firstRechargeRewardSvc := firstrechargeservice.New(repository, walletClient)
	cumulativeRechargeSvc := cumulativerechargeservice.New(repository, walletClient)
	inviteActivityRewardSvc := inviteactivityservice.New(repository, walletClient, activityclient.NewGRPCInviteAttributionSource(clients.userConn))

	return &serviceBundle{
		activity:                    activitySvc,
		message:                     messageSvc,
		task:                        taskSvc,
		registrationReward:          registrationRewardSvc,
		sevenDayCheckIn:             sevenDayCheckInSvc,
		growth:                      growthSvc,
		achievement:                 achievementSvc,
		weeklyStar:                  weeklyStarSvc,
		roomTurnoverReward:          roomTurnoverRewardSvc,
		broadcast:                   broadcastSvc,
		luckyGift:                   luckyGiftSvc,
		firstRechargeReward:         firstRechargeRewardSvc,
		cumulativeRecharge:          cumulativeRechargeSvc,
		inviteActivityReward:        inviteActivityRewardSvc,
		broadcastPublisherAvailable: broadcastPublisher != nil,
	}, nil
}
