package queue

import (
	"github.com/hibiken/asynq"
	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
	"gorm.io/gorm"

	packageExpiryApp "github.com/break/junhong_cmp_fiber/internal/application/packageexpiry"
	"github.com/break/junhong_cmp_fiber/internal/exporter"
	"github.com/break/junhong_cmp_fiber/internal/gateway"
	"github.com/break/junhong_cmp_fiber/internal/infrastructure/integrationlog"
	"github.com/break/junhong_cmp_fiber/internal/infrastructure/messaging/outbox"
	notification "github.com/break/junhong_cmp_fiber/internal/infrastructure/notification"
	packageExpiryInfra "github.com/break/junhong_cmp_fiber/internal/infrastructure/packageexpiry"
	"github.com/break/junhong_cmp_fiber/internal/polling"
	packageExpiryQuery "github.com/break/junhong_cmp_fiber/internal/query/packageexpiry"
	iot_card_svc "github.com/break/junhong_cmp_fiber/internal/service/iot_card"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/internal/task"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/storage"
)

type Handler struct {
	mux                  *asynq.ServeMux
	logger               *zap.Logger
	db                   *gorm.DB
	redis                *redis.Client
	storage              *storage.Service
	gatewayClient        *gateway.Client
	pollingCallback      task.PollingCallback
	workerResult         *WorkerBootstrapResult
	asynqClient          *asynq.Client
	pollingBase          *task.PollingBase
	pollingStopResumeSvc iot_card_svc.StopResumeServiceInterface
}

func NewHandler(
	db *gorm.DB,
	redis *redis.Client,
	storageSvc *storage.Service,
	gatewayClient *gateway.Client,
	pollingCallback task.PollingCallback,
	workerResult *WorkerBootstrapResult,
	asynqClient *asynq.Client,
	logger *zap.Logger,
	pollingBase *task.PollingBase,
	pollingStopResumeSvc iot_card_svc.StopResumeServiceInterface,
) *Handler {
	return &Handler{
		mux:                  asynq.NewServeMux(),
		logger:               logger,
		db:                   db,
		redis:                redis,
		storage:              storageSvc,
		gatewayClient:        gatewayClient,
		pollingCallback:      pollingCallback,
		workerResult:         workerResult,
		asynqClient:          asynqClient,
		pollingBase:          pollingBase,
		pollingStopResumeSvc: pollingStopResumeSvc,
	}
}

func (h *Handler) RegisterHandlers() *asynq.ServeMux {
	emailHandler := task.NewEmailHandler(h.redis, h.logger)

	h.mux.HandleFunc(constants.TaskTypeEmailSend, emailHandler.HandleEmailSend)
	h.logger.Info("注册邮件发送任务处理器", zap.String("task_type", constants.TaskTypeEmailSend))

	h.registerIotCardImportHandler()
	h.registerDeviceImportHandler()
	h.registerOrderPackageInvalidateHandler()
	h.registerAssetPackageBatchOrderHandler()
	h.registerExportHandlers()
	h.registerCommissionStatsHandlers()
	h.registerCommissionCalculationHandler()
	h.registerPollingHandlers()
	h.registerCardObservationSeriesHandler()
	h.registerPackageActivationHandlers()
	h.registerOrderExpireHandler()
	h.registerAlertCheckHandler()
	h.registerDataCleanupHandler()
	h.registerNotificationCleanupHandler()
	h.registerPackageExpiryReminderHandler()
	h.registerAutoPurchaseHandler()
	h.registerDailyTrafficFlushHandler()

	h.logger.Info("所有任务处理器注册完成")
	return h.mux
}

func (h *Handler) registerCardObservationSeriesHandler() {
	handler := task.NewCardObservationSeriesHandler(h.workerResult.Services.CardObservationSeries, h.logger)
	h.mux.HandleFunc(constants.TaskTypeCardObservationSeries, handler.Handle)
	h.logger.Info("注册卡观测事件序列任务处理器", zap.String("task_type", constants.TaskTypeCardObservationSeries))
}

func (h *Handler) registerIotCardImportHandler() {
	iotCardImportHandler := task.NewIotCardImportHandler(
		h.db,
		h.redis,
		h.workerResult.Stores.IotCardImportTask,
		h.workerResult.Stores.IotCard,
		h.workerResult.Stores.AssetWallet,
		h.storage,
		h.pollingCallback,
		h.logger,
	)

	h.mux.HandleFunc(constants.TaskTypeIotCardImport, iotCardImportHandler.HandleIotCardImport)
	h.logger.Info("注册 IoT 卡导入任务处理器", zap.String("task_type", constants.TaskTypeIotCardImport))
}

func (h *Handler) registerOrderPackageInvalidateHandler() {
	orderPkgHandler := task.NewOrderPackageInvalidateHandler(
		h.workerResult.Stores.OrderPackageInvalidateTask,
		h.workerResult.Stores.Order,
		h.workerResult.Stores.PackageUsage,
		h.storage,
		h.logger,
	)
	h.mux.HandleFunc(constants.TaskTypeOrderPackageInvalidate, orderPkgHandler.Handle)
	h.logger.Info("注册订单套餐批量失效任务处理器", zap.String("task_type", constants.TaskTypeOrderPackageInvalidate))
}

func (h *Handler) registerAssetPackageBatchOrderHandler() {
	handler := task.NewAssetPackageBatchOrderHandler(
		h.workerResult.Stores.AssetPackageBatchOrderTask,
		h.workerResult.Stores.Shop,
		h.workerResult.Services.AssetPackageOrderCreator,
		h.storage,
		h.logger,
	)
	h.mux.HandleFunc(constants.TaskTypeAssetPackageBatchOrder, handler.Handle)
	h.logger.Info("注册资产套餐批量订购任务处理器", zap.String("task_type", constants.TaskTypeAssetPackageBatchOrder))
}

func (h *Handler) registerDeviceImportHandler() {
	deviceImportHandler := task.NewDeviceImportHandler(
		h.db,
		h.redis,
		h.workerResult.Stores.DeviceImportTask,
		h.workerResult.Stores.Device,
		h.workerResult.Stores.DeviceSimBinding,
		h.workerResult.Stores.IotCard,
		h.workerResult.Stores.AssetWallet,
		h.workerResult.Stores.AssetIdentifier,
		h.storage,
		h.logger,
		h.workerResult.Services.DeviceBatchAllocator,
	)

	h.mux.HandleFunc(constants.TaskTypeDeviceImport, deviceImportHandler.HandleDeviceImport)
	h.logger.Info("注册设备导入任务处理器", zap.String("task_type", constants.TaskTypeDeviceImport))
}

func (h *Handler) registerExportHandlers() {
	sceneRegistry := exporter.NewDefaultRegistry(h.db)

	dispatchHandler := task.NewExportDispatchHandler(
		h.db,
		h.redis,
		h.workerResult.Stores.ExportTask,
		h.workerResult.Stores.ExportShardTask,
		h.asynqClient,
		sceneRegistry,
		h.logger,
	)
	shardHandler := task.NewExportShardHandler(
		h.redis,
		h.workerResult.Stores.ExportTask,
		h.workerResult.Stores.ExportShardTask,
		h.asynqClient,
		h.storage,
		sceneRegistry,
		h.logger,
	)
	finalizeHandler := task.NewExportFinalizeHandler(
		h.redis,
		h.workerResult.Stores.ExportTask,
		h.workerResult.Stores.ExportShardTask,
		h.storage,
		sceneRegistry,
		h.logger,
	)

	h.mux.HandleFunc(constants.TaskTypeExportDispatch, dispatchHandler.HandleExportDispatch)
	h.logger.Info("注册导出 dispatch 任务处理器", zap.String("task_type", constants.TaskTypeExportDispatch))

	h.mux.HandleFunc(constants.TaskTypeExportShard, shardHandler.HandleExportShard)
	h.logger.Info("注册导出 shard 任务处理器", zap.String("task_type", constants.TaskTypeExportShard))

	h.mux.HandleFunc(constants.TaskTypeExportFinalize, finalizeHandler.HandleExportFinalize)
	h.logger.Info("注册导出 finalize 任务处理器", zap.String("task_type", constants.TaskTypeExportFinalize))
}

func (h *Handler) registerCommissionStatsHandlers() {
	updateHandler := task.NewCommissionStatsUpdateHandler(
		h.redis,
		h.workerResult.Stores.ShopSeriesCommissionStats,
		h.workerResult.Stores.ShopPackageAllocation,
		h.logger,
	)
	syncHandler := task.NewCommissionStatsSyncHandler(
		h.db,
		h.redis,
		h.workerResult.Stores.ShopSeriesCommissionStats,
		h.logger,
	)
	archiveHandler := task.NewCommissionStatsArchiveHandler(
		h.db,
		h.redis,
		h.workerResult.Stores.ShopSeriesCommissionStats,
		h.logger,
	)

	h.mux.HandleFunc(constants.TaskTypeCommissionStatsUpdate, updateHandler.HandleCommissionStatsUpdate)
	h.logger.Info("注册佣金统计更新任务处理器", zap.String("task_type", constants.TaskTypeCommissionStatsUpdate))

	h.mux.HandleFunc(constants.TaskTypeCommissionStatsSync, syncHandler.HandleCommissionStatsSync)
	h.logger.Info("注册佣金统计同步任务处理器", zap.String("task_type", constants.TaskTypeCommissionStatsSync))

	h.mux.HandleFunc(constants.TaskTypeCommissionStatsArchive, archiveHandler.HandleCommissionStatsArchive)
	h.logger.Info("注册佣金统计归档任务处理器", zap.String("task_type", constants.TaskTypeCommissionStatsArchive))
}

func (h *Handler) registerCommissionCalculationHandler() {
	commissionCalculationHandler := task.NewCommissionCalculationHandler(
		h.db,
		h.workerResult.Services.CommissionCalculation,
		h.logger,
	)
	h.mux.HandleFunc(constants.TaskTypeCommission, commissionCalculationHandler.HandleCommissionCalculation)
	h.logger.Info("注册佣金计算任务处理器", zap.String("task_type", constants.TaskTypeCommission))
}

func (h *Handler) registerPollingHandlers() {
	integrationRepository := integrationlog.NewRepository(h.db)
	realnameHandler := task.NewPollingRealnameHandler(
		h.pollingBase, h.gatewayClient, h.workerResult.Services.CardObservation, integrationRepository)
	carrierStore := postgres.NewCarrierStore(h.db)
	carddataHandler := task.NewPollingCarddataHandler(
		h.pollingBase, h.gatewayClient, carrierStore, h.workerResult.Services.CardObservation, integrationRepository)
	packageHandler := task.NewPollingPackageHandler(
		h.pollingBase, h.workerResult.Stores.IotCard,
		h.pollingStopResumeSvc)
	protectHandler := task.NewPollingProtectHandler(
		h.db, h.workerResult.Services.ObservationSeriesEvents,
		h.pollingBase, h.gatewayClient, h.workerResult.Stores.IotCard,
		h.workerResult.Stores.DeviceSimBinding, h.pollingStopResumeSvc)
	cardStatusHandler := task.NewPollingCardStatusHandler(
		h.pollingBase, h.gatewayClient, h.workerResult.Services.CardObservation, integrationRepository)

	h.mux.HandleFunc(constants.TaskTypePollingRealname, realnameHandler.Handle)
	h.mux.HandleFunc(constants.TaskTypePollingCarddata, carddataHandler.Handle)
	h.mux.HandleFunc(constants.TaskTypePollingPackage, packageHandler.Handle)
	h.mux.HandleFunc(constants.TaskTypePollingProtect, protectHandler.Handle)
	h.mux.HandleFunc(constants.TaskTypePollingCardStatus, cardStatusHandler.Handle)
	h.logger.Info("已注册轮询任务处理器（realname/carddata/package/protect/card_status）")
}

func (h *Handler) registerPackageActivationHandlers() {
	packageActivationHandler := polling.NewPackageActivationHandler(
		h.db,
		h.redis,
		h.asynqClient,
		h.workerResult.Services.ActivationService,
		nil,
		h.logger,
	)

	h.mux.HandleFunc(constants.TaskTypePackageFirstActivation, packageActivationHandler.HandlePackageFirstActivation)
	h.logger.Info("注册首次实名激活任务处理器", zap.String("task_type", constants.TaskTypePackageFirstActivation))

	h.mux.HandleFunc(constants.TaskTypePackageQueueActivation, packageActivationHandler.HandlePackageQueueActivation)
	h.logger.Info("注册排队激活任务处理器", zap.String("task_type", constants.TaskTypePackageQueueActivation))
}

func (h *Handler) registerOrderExpireHandler() {
	orderExpireHandler := task.NewOrderExpireHandler(h.workerResult.Services.OrderExpirer, h.logger)
	h.mux.HandleFunc(constants.TaskTypeOrderExpire, orderExpireHandler.HandleOrderExpire)
	h.logger.Info("注册订单超时取消任务处理器", zap.String("task_type", constants.TaskTypeOrderExpire))
}

func (h *Handler) registerAlertCheckHandler() {
	alertCheckHandler := task.NewAlertCheckHandler(h.workerResult.Services.AlertService, h.logger)
	h.mux.HandleFunc(constants.TaskTypeAlertCheck, alertCheckHandler.HandleAlertCheck)
	h.logger.Info("注册告警检查任务处理器", zap.String("task_type", constants.TaskTypeAlertCheck))
}

func (h *Handler) registerDataCleanupHandler() {
	dataCleanupHandler := task.NewDataCleanupHandler(h.workerResult.Services.CleanupService, h.logger)
	h.mux.HandleFunc(constants.TaskTypeDataCleanup, dataCleanupHandler.HandleDataCleanup)
	h.logger.Info("注册数据清理任务处理器", zap.String("task_type", constants.TaskTypeDataCleanup))
}

func (h *Handler) registerNotificationCleanupHandler() {
	cleanupService := notification.NewCleanupService(h.db, h.logger)
	cleanupHandler := task.NewNotificationCleanupHandler(cleanupService, h.logger)
	h.mux.HandleFunc(constants.TaskTypeNotificationCleanup, cleanupHandler.Handle)
	h.logger.Info("注册站内通知保留清理任务处理器", zap.String("task_type", constants.TaskTypeNotificationCleanup))
}

func (h *Handler) registerPackageExpiryReminderHandler() {
	query := packageExpiryQuery.NewQuery(h.db)
	publisher := packageExpiryInfra.NewReminderPublisher(h.db, outbox.NewRepository())
	service := packageExpiryApp.NewReminderService(query, publisher)
	handler := task.NewPackageExpiryReminderHandler(service, h.logger)
	h.mux.HandleFunc(constants.TaskTypePackageExpiryReminder, handler.Handle)
	h.logger.Info("注册套餐临期节点提醒任务处理器", zap.String("task_type", constants.TaskTypePackageExpiryReminder))
}

func (h *Handler) registerAutoPurchaseHandler() {
	autoPurchaseHandler := task.NewAutoPurchaseHandler(
		h.db,
		h.workerResult.Stores.Order,
		nil, // RechargeOrderStore：在 NewAutoPurchaseHandler 内按需初始化
		nil, // PaymentStore：在 NewAutoPurchaseHandler 内按需初始化
		h.workerResult.Stores.AssetWallet,
		nil, // AssetWalletTransactionStore：在 NewAutoPurchaseHandler 内按需初始化
		h.workerResult.Stores.PackageUsage,
		h.redis,
		h.asynqClient,
		h.logger,
		h.workerResult.Services.ObservationSeriesEvents,
	)
	h.mux.HandleFunc(constants.TaskTypeAutoPurchaseAfterRecharge, autoPurchaseHandler.ProcessTask)
	h.logger.Info("注册自动购包任务处理器", zap.String("task_type", constants.TaskTypeAutoPurchaseAfterRecharge))
}

func (h *Handler) registerDailyTrafficFlushHandler() {
	cardDailyUsageStore := postgres.NewCardDailyUsageStore(h.db)
	dailyTrafficFlushHandler := task.NewDailyTrafficFlushHandler(h.redis, cardDailyUsageStore, h.logger)
	h.mux.HandleFunc(constants.TaskTypeDailyTrafficFlush, dailyTrafficFlushHandler.HandleDailyTrafficFlush)
	h.logger.Info("注册每日流量落盘任务处理器", zap.String("task_type", constants.TaskTypeDailyTrafficFlush))
}

// GetMux 获取 ServeMux（用于启动 Worker 服务器）
func (h *Handler) GetMux() *asynq.ServeMux {
	return h.mux
}
