package bootstrap

import (
	notificationApp "github.com/break/junhong_cmp_fiber/internal/application/notification"
	roleApp "github.com/break/junhong_cmp_fiber/internal/application/role"
	shopApp "github.com/break/junhong_cmp_fiber/internal/application/shop"
	systemConfigApp "github.com/break/junhong_cmp_fiber/internal/application/systemconfig"
	walletApp "github.com/break/junhong_cmp_fiber/internal/application/wallet"
	wecomApp "github.com/break/junhong_cmp_fiber/internal/application/wecom"
	"github.com/break/junhong_cmp_fiber/internal/handler/admin"
	"github.com/break/junhong_cmp_fiber/internal/handler/app"
	authHandler "github.com/break/junhong_cmp_fiber/internal/handler/auth"
	"github.com/break/junhong_cmp_fiber/internal/handler/callback"
	openapiHandler "github.com/break/junhong_cmp_fiber/internal/handler/openapi"
	"github.com/break/junhong_cmp_fiber/internal/infrastructure/carriercallback"
	"github.com/break/junhong_cmp_fiber/internal/infrastructure/integrationlog"
	systemConfigInfra "github.com/break/junhong_cmp_fiber/internal/infrastructure/systemconfig"
	wecomInfra "github.com/break/junhong_cmp_fiber/internal/infrastructure/wecom"
	pollingPkg "github.com/break/junhong_cmp_fiber/internal/polling"
	assetQuery "github.com/break/junhong_cmp_fiber/internal/query/asset"
	exchangeQuery "github.com/break/junhong_cmp_fiber/internal/query/exchange"
	notificationQuery "github.com/break/junhong_cmp_fiber/internal/query/notification"
	packageExpiryQuery "github.com/break/junhong_cmp_fiber/internal/query/packageexpiry"
	shopQuery "github.com/break/junhong_cmp_fiber/internal/query/shop"
	systemConfigQuery "github.com/break/junhong_cmp_fiber/internal/query/systemconfig"
	clientOrderSvc "github.com/break/junhong_cmp_fiber/internal/service/client_order"
	"github.com/break/junhong_cmp_fiber/internal/service/paymentmethod"
	pollingSvcPkg "github.com/break/junhong_cmp_fiber/internal/service/polling"
	rechargeOrderSvc "github.com/break/junhong_cmp_fiber/internal/service/recharge_order"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/config"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
)

func initHandlers(svc *services, deps *Dependencies) *Handlers {
	validate := validator.New()
	packageExpiry := packageExpiryQuery.NewQuery(deps.DB)
	svc.Asset.SetPackageExpiryQuery(packageExpiry)
	svc.IotCard.SetPackageExpiryQuery(packageExpiry)
	svc.Device.SetPackageExpiryQuery(packageExpiry)
	assetWalletStore := postgres.NewAssetWalletStore(deps.DB, deps.Redis)
	packageStore := postgres.NewPackageStore(deps.DB)
	shopPackageAllocationStore := postgres.NewShopPackageAllocationStore(deps.DB)
	iotCardStore := postgres.NewIotCardStore(deps.DB, deps.Redis)
	deviceStore := postgres.NewDeviceStore(deps.DB, deps.Redis)
	assetWalletTransactionStore := postgres.NewAssetWalletTransactionStore(deps.DB, deps.Redis)
	personalCustomerOpenIDStore := postgres.NewPersonalCustomerOpenIDStore(deps.DB)
	personalCustomerStore := postgres.NewPersonalCustomerStore(deps.DB, deps.Redis)
	personalCustomerPhoneStore := postgres.NewPersonalCustomerPhoneStore(deps.DB)
	orderStore := postgres.NewOrderStore(deps.DB, deps.Redis)
	packageSeriesStore := postgres.NewPackageSeriesStore(deps.DB)
	shopSeriesAllocationStore := postgres.NewShopSeriesAllocationStore(deps.DB)
	deviceSimBindingStore := postgres.NewDeviceSimBindingStore(deps.DB, deps.Redis)
	carrierStore := postgres.NewCarrierStore(deps.DB)
	rechargeOrderStore := postgres.NewRechargeOrderStore(deps.DB, deps.Redis)
	paymentStore := postgres.NewPaymentStore(deps.DB, deps.Redis)
	commissionRecordStore := postgres.NewCommissionRecordStore(deps.DB, deps.Redis)
	rechargeOrderService := rechargeOrderSvc.New(
		deps.DB,
		rechargeOrderStore,
		paymentStore,
		assetWalletStore,
		assetWalletTransactionStore,
		iotCardStore,
		deviceStore,
		packageSeriesStore,
		shopSeriesAllocationStore,
		commissionRecordStore,
		deps.QueueClient,
		deps.Logger,
	)
	clientOrderService := clientOrderSvc.New(
		svc.Asset,
		svc.PurchaseValidation,
		orderStore,
		rechargeOrderStore,
		paymentStore,
		assetWalletStore,
		svc.CustomerBinding,
		personalCustomerOpenIDStore,
		personalCustomerStore,
		personalCustomerPhoneStore,
		svc.WechatConfig,
		svc.Order,
		packageSeriesStore,
		shopSeriesAllocationStore,
		iotCardStore,
		deviceStore,
		deps.DB,
		deps.Redis,
		deps.Logger,
	)
	systemConfigRegistry := deps.SystemConfigRegistry
	if systemConfigRegistry == nil {
		systemConfigRegistry = systemConfigInfra.NewRegistry()
	}
	registerCarrierCallbackConfigDefinitions(systemConfigRegistry, deps.Logger)
	registerPaymentMethodConfigDefinitions(systemConfigRegistry, deps.Logger)
	systemConfigAlerts := systemConfigInfra.NewLogAlertSink(deps.Logger)
	var systemConfigCache systemConfigInfra.Cache
	if deps.Redis != nil {
		systemConfigCache = systemConfigInfra.NewRedisCache(deps.Redis)
	}
	systemConfigReader := systemConfigInfra.NewReader(deps.DB, systemConfigRegistry, systemConfigCache, systemConfigAlerts)
	paymentMethodPolicy := paymentmethod.NewPolicy(systemConfigReader)
	clientOrderService.SetPaymentMethodPolicy(paymentMethodPolicy)
	systemConfigList := systemConfigQuery.NewListQuery(systemConfigReader)
	systemConfigUpdate := systemConfigApp.NewUpdateService(
		deps.DB, systemConfigRegistry, systemConfigCache, deps.SystemConfigAudit, systemConfigAlerts, nil,
	)
	wecomRepository := wecomInfra.NewApplicationRepository(deps.DB)
	var credentialCipher *wecomInfra.CredentialCipher
	wecomBaseURL := ""
	wecomTimeout := constants.WeComDefaultHTTPTimeout
	if cfg := config.Get(); cfg != nil {
		wecomBaseURL = cfg.WeCom.BaseURL
		wecomTimeout = cfg.WeCom.Timeout
		cipher, err := wecomInfra.NewCredentialCipher(cfg.WeCom.CredentialEncryptionKey)
		if err != nil {
			if deps.Logger != nil {
				deps.Logger.Warn("企业微信凭据加密密钥未配置或无效，相关接口将拒绝业务调用", zap.Error(err))
			}
		} else {
			credentialCipher = cipher
		}
	}
	wecomTokens := wecomInfra.NewTokenProvider(
		wecomRepository, credentialCipher, deps.Redis, integrationlog.NewRepository(deps.DB),
		wecomBaseURL, wecomTimeout, deps.Logger,
	)
	wecomConnections := wecomApp.NewConnectionService(
		deps.DB, wecomRepository, credentialCipher, wecomTokens, deps.SystemConfigAudit,
	)
	wecomMembers := wecomInfra.NewMemberRepository(deps.DB)
	wecomConnections.SetDefaultCreatorMemberFinder(wecomMembers)
	wecomDirectory := wecomApp.NewDirectoryService(
		wecomRepository,
		wecomInfra.NewDirectoryClient(wecomTokens, integrationlog.NewRepository(deps.DB), wecomBaseURL, wecomTimeout),
		wecomMembers,
	)
	wecomScenes := wecomApp.NewSceneService(
		deps.DB,
		wecomInfra.NewTemplateClient(wecomTokens, integrationlog.NewRepository(deps.DB), wecomBaseURL, wecomTimeout),
		wecomInfra.NewSceneRepository(deps.DB), deps.SystemConfigAudit,
	)
	wecomApprovalCallback := callback.NewWeComApprovalHandler(wecomInfra.NewCallbackService(
		wecomRepository, credentialCipher, integrationlog.NewRepository(deps.DB), deps.QueueClient,
	))
	svc.Account.SetWeComMemberFinder(wecomMembers)

	return &Handlers{
		Auth:    authHandler.NewHandler(svc.Auth, validate),
		Account: admin.NewAccountHandler(svc.Account),
		Role: func() *admin.RoleHandler {
			handler := admin.NewRoleHandler(svc.Role, validate)
			handler.SetDefaultCreditService(roleApp.NewDefaultCreditService(deps.DB, svc.Permission))
			return handler
		}(),
		Permission:       admin.NewPermissionHandler(svc.Permission),
		PersonalCustomer: app.NewPersonalCustomerHandler(svc.PersonalCustomer, deps.Logger),
		ClientAuth:       app.NewClientAuthHandler(svc.ClientAuth, deps.Logger),
		ClientAsset: func() *app.ClientAssetHandler {
			handler := app.NewClientAssetHandler(svc.Asset, svc.CustomerBinding, assetWalletStore, packageStore, shopPackageAllocationStore, iotCardStore, deviceStore, deps.DB, deps.Logger)
			handler.SetObservationSeriesDispatcher(svc.ObservationSeries)
			handler.SetPaymentMethodPolicy(paymentMethodPolicy)
			handler.SetForceRechargeChecker(svc.Recharge)
			return handler
		}(),
		ClientWallet: func() *app.ClientWalletHandler {
			handler := app.NewClientWalletHandler(svc.Asset, svc.CustomerBinding, assetWalletStore, assetWalletTransactionStore, rechargeOrderStore, paymentStore, svc.Recharge, personalCustomerOpenIDStore, svc.WechatConfig, deps.Redis, deps.Logger, deps.DB, iotCardStore, deviceStore)
			handler.SetPaymentMethodPolicy(paymentMethodPolicy)
			return handler
		}(),
		ClientOrder:    app.NewClientOrderHandler(clientOrderService, deps.Logger),
		ClientExchange: app.NewClientExchangeHandler(svc.Exchange),
		ClientRealname: func() *app.ClientRealnameHandler {
			handler := app.NewClientRealnameHandler(svc.Asset, svc.CustomerBinding, iotCardStore, deviceSimBindingStore, carrierStore, deps.GatewayClient, deps.Logger, svc.PollingManualTrigger)
			handler.SetObservationSeriesDispatcher(svc.ObservationSeries)
			return handler
		}(),
		ClientDevice: func() *app.ClientDeviceHandler {
			handler := app.NewClientDeviceHandler(svc.Asset, svc.CustomerBinding, deviceStore, deviceSimBindingStore, iotCardStore, deps.GatewayClient, deps.Logger)
			handler.SetDeviceService(svc.Device)
			return handler
		}(),
		ClientRechargeOrder: app.NewClientRechargeOrderHandler(rechargeOrderStore, paymentStore, deps.Logger),
		ClientNotification:  app.NewClientNotificationHandler(notificationQuery.NewQuery(deps.DB), notificationApp.NewReadService(deps.DB), validate),
		Shop: func() *admin.ShopHandler {
			handler := admin.NewShopHandler(svc.Shop, validate)
			handler.SetCreateService(shopApp.NewCreateService(deps.DB))
			handler.SetUpdateService(shopApp.NewUpdateService(deps.DB))
			handler.SetBusinessOwnerQuery(shopQuery.NewBusinessOwnerQuery(deps.DB))
			handler.SetChangeCreditService(walletApp.NewChangeCreditService(deps.DB))
			return handler
		}(),
		ShopRole:  admin.NewShopRoleHandler(svc.Shop),
		AdminAuth: admin.NewAuthHandler(svc.Auth, validate),
		ShopCommission: func() *admin.ShopCommissionHandler {
			handler := admin.NewShopCommissionHandler(svc.ShopCommission)
			handler.SetFundSummaryQuery(shopQuery.NewFundSummaryQuery(deps.DB))
			return handler
		}(),
		CommissionWithdrawal:        admin.NewCommissionWithdrawalHandler(svc.CommissionWithdrawal, validate),
		CommissionWithdrawalSetting: admin.NewCommissionWithdrawalSettingHandler(svc.CommissionWithdrawalSetting),
		Enterprise:                  admin.NewEnterpriseHandler(svc.Enterprise),
		EnterpriseCard:              admin.NewEnterpriseCardHandler(svc.EnterpriseCard),
		EnterpriseDevice:            admin.NewEnterpriseDeviceHandler(svc.EnterpriseDevice),
		Authorization:               admin.NewAuthorizationHandler(svc.Authorization),
		IotCard:                     admin.NewIotCardHandler(svc.IotCard),
		IotCardImport:               admin.NewIotCardImportHandler(svc.IotCardImport),
		ExportTask:                  admin.NewExportTaskHandler(svc.ExportTask),
		Notification:                admin.NewNotificationHandler(notificationQuery.NewQuery(deps.DB), notificationApp.NewReadService(deps.DB), validate),
		Device:                      admin.NewDeviceHandler(svc.Device),
		DeviceImport:                admin.NewDeviceImportHandler(svc.DeviceImport),
		AssetAllocationRecord:       admin.NewAssetAllocationRecordHandler(svc.AssetAllocationRecord),
		Storage:                     admin.NewStorageHandler(deps.StorageService),
		Carrier:                     admin.NewCarrierHandler(svc.Carrier),
		PackageSeries:               admin.NewPackageSeriesHandler(svc.PackageSeries),
		Package:                     admin.NewPackageHandler(svc.Package),
		PackageUsage:                admin.NewPackageUsageHandler(svc.PackageDailyRecord),
		ShopPackageBatchAllocation:  admin.NewShopPackageBatchAllocationHandler(svc.ShopPackageBatchAllocation),
		ShopPackageBatchPricing:     admin.NewShopPackageBatchPricingHandler(svc.ShopPackageBatchPricing),
		ShopSeriesGrant:             admin.NewShopSeriesGrantHandler(svc.ShopSeriesGrant),
		AdminOrder:                  admin.NewOrderHandler(svc.Order, validate),
		AdminExchange:               admin.NewExchangeHandler(svc.Exchange, exchangeQuery.NewListQuery(deps.DB), validate),
		PaymentCallback:             callback.NewPaymentHandler(svc.Order, svc.Recharge, rechargeOrderService, svc.AgentRecharge, deps.WechatPayment, svc.WechatConfig, paymentStore, deps.Logger),
		CTCCRealnameCallback: callback.NewCTCCRealnameHandler(
			carriercallback.NewCTCCRealnameTranslator(), carriercallback.NewCTCCCardResolver(deps.DB),
			integrationlog.NewRepository(deps.DB), svc.CardObservation, svc.CardObservationSeries, systemConfigReader, deps.Logger,
		),
		CMCCRealnameCallback: callback.NewCMCCRealnameHandler(
			carriercallback.NewCMCCRealnameTranslator(), carriercallback.NewCMCCCardResolver(deps.DB),
			integrationlog.NewRepository(deps.DB), svc.CardObservation, svc.CardObservationSeries, systemConfigReader, deps.Logger,
		),
		CUCCRealnameCallback: callback.NewCUCCRealnameHandler(
			carriercallback.NewCUCCRealnameTranslator(), carriercallback.NewCUCCCardResolver(deps.DB),
			integrationlog.NewRepository(deps.DB), svc.CardObservation, svc.CardObservationSeries, systemConfigReader, deps.Logger,
		),
		CUCCRealnameRemovalCallback: callback.NewCUCCRealnameRemovalHandler(
			carriercallback.NewCUCCRealnameRemovalTranslator(), carriercallback.NewCUCCCardResolver(deps.DB),
			integrationlog.NewRepository(deps.DB), systemConfigReader, deps.Logger,
		),
		WeComApprovalCallback: wecomApprovalCallback,
		PollingConfig:         admin.NewPollingConfigHandler(svc.PollingConfig),
		PollingConcurrency:    admin.NewPollingConcurrencyHandler(svc.PollingConcurrency),
		PollingMonitoring:     admin.NewPollingMonitoringHandler(svc.PollingMonitoring),
		PollingAlert:          admin.NewPollingAlertHandler(svc.PollingAlert),
		PollingCleanup:        admin.NewPollingCleanupHandler(svc.PollingCleanup),
		PollingManualTrigger:  admin.NewPollingManualTriggerHandler(svc.PollingManualTrigger),
		Asset: func() *admin.AssetHandler {
			pollingQueueMgr := pollingPkg.NewPollingQueueManager(deps.Redis, constants.PollingShardCount, deps.Logger)
			assetPollingSvc := pollingSvcPkg.NewAssetPollingService(
				deviceStore,
				deviceSimBindingStore,
				svc.IotCard,
				pollingQueueMgr,
				deps.Logger,
				svc.AssetAudit,
			)
			h := admin.NewAssetHandler(svc.Asset, svc.AssetAudit, svc.Device, svc.IotCard, svc.StopResumeService, assetPollingSvc, assetQuery.NewExchangeTraceQuery(deps.DB, deps.Logger))
			h.SetLifecycleService(svc.AssetLifecycle)
			h.SetObservationSeriesDispatcher(svc.ObservationSeries)
			h.SetPackageExpiryQuery(packageExpiry)
			return h
		}(),
		AssetLifecycle: admin.NewAssetLifecycleHandler(svc.AssetLifecycle),
		AssetWallet: func() *admin.AssetWalletHandler {
			h := admin.NewAssetWalletHandler(svc.AssetWallet)
			h.SetAssetService(svc.Asset)
			return h
		}(),
		WechatConfig:           admin.NewWechatConfigHandler(svc.WechatConfig),
		AgentRecharge:          admin.NewAgentRechargeHandler(svc.AgentRecharge, validate),
		Refund:                 admin.NewRefundHandler(svc.Refund),
		OrderPackageInvalidate: admin.NewOrderPackageInvalidateHandler(svc.OrderPackageInvalidate),
		AssetPackageBatchOrder: admin.NewAssetPackageBatchOrderHandler(svc.AssetPackageBatchOrder, validate),
		ClientWechat:           app.NewClientWechatHandler(svc.WechatConfig, deps.Redis, deps.Logger),
		SuperAdmin:             admin.NewSuperAdminHandler(svc.OperationPassword),
		SystemConfig:           admin.NewSystemConfigHandler(systemConfigList, systemConfigUpdate),
		WeCom: func() *admin.WeComHandler {
			handler := admin.NewWeComHandler(wecomConnections, validate)
			handler.SetDirectoryService(wecomDirectory)
			handler.SetSceneService(wecomScenes)
			return handler
		}(),
		AgentOpenAPI: openapiHandler.NewHandler(svc.AgentOpenAPI, validate),
	}
}
