package main

import (
	// "context"

	// "context"
	_ "Yimaru-Backend/docs"
	dbgen "Yimaru-Backend/gen/db"
	"Yimaru-Backend/internal/config"
	"Yimaru-Backend/internal/domain"
	customlogger "Yimaru-Backend/internal/logger"
	"Yimaru-Backend/internal/logger/mongoLogger"
	"Yimaru-Backend/internal/repository"
	"Yimaru-Backend/internal/services/arifpay"
	"Yimaru-Backend/internal/services/assessment"
	"Yimaru-Backend/internal/services/authentication"
	"Yimaru-Backend/internal/services/course_management"
	issuereporting "Yimaru-Backend/internal/services/issue_reporting"
	"Yimaru-Backend/internal/services/messenger"
	notificationservice "Yimaru-Backend/internal/services/notification"
	"Yimaru-Backend/internal/services/questions"
	"Yimaru-Backend/internal/services/recommendation"
	"Yimaru-Backend/internal/services/settings"
	"Yimaru-Backend/internal/services/subscriptions"
	"Yimaru-Backend/internal/services/team"
	activitylogservice "Yimaru-Backend/internal/services/activity_log"
	cloudconvertservice "Yimaru-Backend/internal/services/cloudconvert"
	vimeoservice "Yimaru-Backend/internal/services/vimeo"
	"context"

	// referralservice "Yimaru-Backend/internal/services/referal"
	"Yimaru-Backend/internal/services/transaction"
	"Yimaru-Backend/internal/services/user"
	httpserver "Yimaru-Backend/internal/web_server"
	jwtutil "Yimaru-Backend/internal/web_server/jwt"
	customvalidator "Yimaru-Backend/internal/web_server/validator"
	"fmt"
	"log"
	"log/slog"
	"net/http"
	"os"
	"time"

	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
)

// @title Yimaru API
// @version 1.0.1
// @description This is server for Yimaru.
// @termsOfService http://swagger.io/terms/
// @contact.name API Support
// @contact.url http://www.swagger.io/support
// @contact.email support@swagger.io
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @SecurityDefinitions.apiKey Bearer
// @in header
// @name Authorization
// @BasePath /
func main() {
	cfg, err := config.NewConfig()
	if err != nil {
		slog.Error("Config error:", "err", err)
		os.Exit(1)
	}

	db, _, err := repository.OpenDB(cfg.DbUrl)
	if err != nil {
		fmt.Println("Database error:", err)
		os.Exit(1)
	}

	logger := customlogger.NewLogger(cfg.Env, cfg.LogLevel)

	domain.MongoDBLogger, err = mongoLogger.InitLogger(cfg)
	if err != nil {
		log.Fatalf("Logger initialization failed: %v", err)
	}
	defer domain.MongoDBLogger.Sync()

	zap.ReplaceGlobals(domain.MongoDBLogger)

	store := repository.NewStore(db)
	analyticsDB := dbgen.New(db)
	v := customvalidator.NewCustomValidator(validator.New())

	// Initialize services
	settingRepo := repository.NewSettingStore(store)

	if err := settingRepo.EnsureAllSettingsExist(context.Background()); err != nil {
		log.Fatalf("failed to ensure settings: %v", err)
	}
	settingSvc := settings.NewService(settingRepo)

	messengerSvc := messenger.NewService(settingSvc, cfg)
	// statSvc := stats.NewService(
	// 	repository.NewCompanyStatStore(store),
	// 	repository.NewBranchStatStore(store),
	// )

	userSvc := user.NewService(
		repository.NewTokenStore(store),
		repository.NewUserStore(store),
		repository.NewOTPStore(store),
		messengerSvc,
		cfg,
	)

	authSvc := authentication.NewService(
		repository.NewOTPStore(store),
		repository.NewUserStore(store),
		*userSvc,
		repository.NewTokenStore(store),
		cfg.RefreshExpiry,
	)

	authSvc.InitGoogleOAuth(cfg.GoogleOAuthClientID, cfg.GoogleOAuthClientSecret, cfg.GoogleOAuthRedirectURL)
	// leagueSvc := league.New(repository.NewLeagueStore(store))
	// eventSvc := event.New(
	// 	cfg.Bet365Token,
	// 	repository.NewEventStore(store),
	// 	repository.NewEventHistoryStore(store),
	// 	*leagueSvc,
	// 	settingSvc,
	// 	domain.MongoDBLogger,
	// 	cfg,
	// )

	// marketSettingRepo := repository.NewMarketSettingStore(store)

	// if err := marketSettingRepo.EnsureAllMarketSettingsExist(context.Background()); err != nil {
	// 	log.Fatalf("failed to ensure market settings: %v", err)
	// }

	// oddsSvc := odds.New(
	// 	repository.NewOddStore(store),
	// 	marketSettingRepo,
	// 	cfg,
	// 	eventSvc,
	// 	logger,
	// 	domain.MongoDBLogger,
	// )

	// virtuaGamesRepo := repository.NewVirtualGameRepository(store)

	// Initialize producer
	// topic := "wallet-balance-topic"
	// producer := kafka.NewProducer(cfg.KafkaBrokers, topic)

	notificationSvc := notificationservice.New(
		repository.NewNotificationStore(store),
		domain.MongoDBLogger,
		logger,
		cfg,
		messengerSvc,
		userSvc,
	)

	// / := wallet.NewService(
	// 	repository.NewWalletStore(store),
	// 	repository.NewTransferStore(store),
	// 	// repository.NewDirectDepositStore(store),
	// 	notificationSvc,
	// 	userSvc,
	// 	domain.MongoDBLogger,
	// 	logger,
	// )

	// branchSvc := branch.NewService(repository.NewBranchStore(store))
	// companySvc := company.NewService(repository.NewCompanyStore(store))

	// ticketSvc := ticke.NewService(
	// 	repository.NewTicketStore(store),
	// 	// eventSvc,
	// 	// *oddsSvc,
	// 	domain.MongoDBLogger,
	// 	settingSvc,
	// )
	// betSvc := bet.NewService(
	// 	repository.NewBetStore(store),
	// 	eventSvc,
	// 	*oddsSvc,
	// ,
	// 	*branchSvc,
	// 	*companySvc,
	// 	*settingSvc,
	// 	*userSvc,
	// 	notificationSvc,
	// 	logger,
	// 	domain.MongoDBLogger,
	// )

	// resultSvc := result.NewService(
	// 	repository.NewResultLogStore(store),
	// 	cfg,
	// 	logger,
	// 	domain.MongoDBLogger,
	// 	// *betSvc,
	// 	// *oddsSvc,
	// 	// eventSvc,
	// 	// leagueSvc,
	// 	notificationSvc,
	// 	messengerSvc,
	// 	*userSvc,
	// )

	// bonusSvc := bonus.NewService(
	// 	repository.NewBonusStore(store),
	// 	settingSvc,
	// 	notificationSvc,
	// 	domain.MongoDBLogger,
	// )
	// virtualGamesRepo := repository.NewVirtualGameRepository(store)
	recommendationRepo := repository.NewRecommendationRepository(store)

	// referalSvc := referralservice.New(
	// 	repository.NewReferralStore(store),
	// 	*settingSvc,
	// 	cfg,
	// 	logger,
	// 	domain.MongoDBLogger,
	// )
	// raffleSvc := raffle.NewService(
	// 	repository.NewRaffleStore(store),
	// )
	// virtualGameSvc := virtualgameservice.New(virtualGamesRepo,, store, cfg, logger)
	// aleaService := alea.NewAleaPlayService(virtualGamesRepo,, cfg, logger)
	// veliCLient := veli.NewClient(cfg)
	// veliVirtualGameService := veli.New(virtualGameSvc, virtualGamesRepo, *store, veliCLient, repository.NewTransferStore(store), domain.MongoDBLogger, cfg)
	// orchestrationSvc := orchestration.New(
	// 	virtualGameSvc,
	// 	virtualGamesRepo,
	// 	cfg,
	// 	veliCLient,
	// )
	// atlasClient := atlas.NewClient(cfg)
	// atlasVirtualGameService := atlas.New(virtualGameSvc, virtualGamesRepo, atlasClient, repository.NewTransferStore(store), cfg)
	recommendationSvc := recommendation.NewService(recommendationRepo)
	// chapaClient := chapa.NewClient(cfg.CHAPA_BASE_URL, cfg.CHAPA_SECRET_KEY)

	// chapaSvc := chapa.NewService(
	// 	repository.NewUserStore(store),
	// 	cfg,
	// 	chapaClient,
	// )

	// currRepo := repository.NewCurrencyPostgresRepository(store)

	// fixerFertcherSvc := currency.NewFixerFetcher(
	// 	cfg.FIXER_API_KEY,
	// 	cfg.FIXER_BASE_URL,
	// )
	transactionSvc := transaction.NewService(
		repository.NewTransactionStore(store),
		*userSvc,
	)

	// reportSvc := report.NewService(
	// 	repository.NewVirtualGameReportStore(store),
	// 	repository.NewBetStore(store),
	// 	repository.NewWalletStore(store),
	// 	repository.NewTransactionStore(store),
	// 	repository.NewBranchStore(store),
	// 	repository.NewUserStore(store),
	// 	repository.NewOldRepositoryStore(store),
	// 	repository.NewCompanyStore(store),
	// 	repository.NewVirtualGameRepository(store),
	// 	repository.NewNotificationStore(store),
	// 	notificationSvc,
	// 	statSvc,
	// 	logger,
	// 	domain.MongoDBLogger,
	// 	cfg,
	// )

	// enePulseSvc := enetpulse.New(
	// 	*cfg,
	// 	store,
	// )

	// go httpserver.StartEnetPulseCron(enePulseSvc, domain.MongoDBLogger)
	// go httpserver.SetupReportandVirtualGameCronJobs(context.Background(), reportSvc, orchestrationSvc, "C:/Users/User/Desktop")
	// go httpserver.ProcessBetCashback(context.TODO(), betSvc)

	// bankRepository := repository.NewBankRepository(store)
	// instSvc := institutions.New(bankRepository)
	// Initialize report worker with CSV exporter
	// csvExporter := infrastructure.CSVExporter{
	// 	ExportPath: cfg.ReportExportPath, // Make sure to add this to your config
	// }

	// reportWorker := worker.NewReportWorker(
	// 	reportSvc,
	// 	csvExporter,
	// )

	// Start cron jobs for automated reporting

	// directdeposit := directdeposit.NewService(
	// 	repository.NewDirectDepositRepository(store),
	// 	notificationSvc,
	// 	userSvc,
	// )

	// enetPulseSvc := enetpulse.New(
	// 	*cfg,
	// 	store,
	// )

	// Initialize wallet monitoring service
	// walletMonitorSvc := monitor.NewService(
	// ,
	// 	*branchSvc,
	// 	notificationSvc,
	// 	logger,
	// 	5*time.Minute,
	// )

	// currSvc := currency.NewService(
	// 	currRepo,
	// 	cfg.BASE_CURRENCY,
	// 	fixerFertcherSvc,
	// )

	// exchangeWorker := currency.NewExchangeRateWorker(fixerFertcherSvc, logger, cfg)
	// exchangeWorker.Start(context.Background())
	// defer exchangeWorker.Stop()
	// go walletMonitorSvc.Start()

	// // httpserver.StartBetAPIDataFetchingCrons(eventSvc, *oddsSvc, resultSvc, domain.MongoDBLogger)
	// httpserver.StartCleanupCrons(*ticketSvc, notificationSvc, domain.MongoDBLogger)
	// httpserver.StartStatCrons(statSvc, domain.MongoDBLogger)
	// httpserver.StartReportCrons(reportSvc, domain.MongoDBLogger)

	issueReportingRepo := repository.NewReportedIssueRepository(store)

	issueReportingSvc := issuereporting.New(issueReportingRepo)

	// transferStore := repository.NewTransferStore(store)
	// walletStore := wallet.WalletStore(store)

	assessmentSvc := assessment.NewService(
		repository.NewUserStore(store),
		store, // Use store directly as it implements QuestionStore
		notificationSvc,
		cfg,
	)

	// Vimeo service for video hosting
	var vimeoSvc *vimeoservice.Service
	if cfg.Vimeo.Enabled && cfg.Vimeo.AccessToken != "" {
		vimeoSvc = vimeoservice.NewService(cfg.Vimeo.AccessToken, domain.MongoDBLogger)
		logger.Info("Vimeo service initialized")
	} else {
		logger.Info("Vimeo service disabled (VIMEO_ENABLED not set or missing access token)")
	}

	// Course management service
	courseSvc := course_management.NewService(
		repository.NewUserStore(store),
		repository.NewCourseStore(store),
		notificationSvc,
		cfg,
	)
	// Wire up Vimeo service to course management
	if vimeoSvc != nil {
		courseSvc.SetVimeoService(vimeoSvc)
	}

	// CloudConvert service for video compression
	if cfg.CloudConvert.Enabled && cfg.CloudConvert.APIKey != "" {
		ccSvc := cloudconvertservice.NewService(cfg.CloudConvert.APIKey, domain.MongoDBLogger)
		courseSvc.SetCloudConvertService(ccSvc)
		logger.Info("CloudConvert service initialized")
	} else {
		logger.Info("CloudConvert service disabled (CLOUDCONVERT_ENABLED not set or missing API key)")
	}

	// Questions service (unified questions system)
	questionsSvc := questions.NewService(store)

	// Subscriptions service
	subscriptionsSvc := subscriptions.NewService(store)

	// ArifPay service with payment and subscription stores
	arifpaySvc := arifpay.NewArifpayService(
		cfg,
		&http.Client{Timeout: 30 * time.Second},
		store, // implements PaymentStore
		store, // implements SubscriptionStore
	)

	// Team management service
	teamSvc := team.NewService(repository.NewTeamStore(store))

	// santimpayClient := santimpay.NewSantimPayClient(cfg)

	// santimpaySvc := santimpay.NewSantimPayService(santimpayClient, cfg, transferStore)
	// telebirrSvc := telebirr.NewTelebirrService(cfg, transferStore)

	// Activity Log service
	activityLogSvc := activitylogservice.NewService(store, domain.MongoDBLogger)

	// Initialize and start HTTP server
	app := httpserver.NewApp(
		assessmentSvc,
		courseSvc,
		questionsSvc,
		subscriptionsSvc,
		arifpaySvc,
		issueReportingSvc,
		vimeoSvc,
		teamSvc,
		activityLogSvc,
		cfg.Port,
		v,
		settingSvc,
		authSvc,
		logger,
		jwtutil.JwtConfig{
			JwtAccessKey:    cfg.JwtKey,
			JwtAccessExpiry: cfg.AccessExpiry,
		},
		userSvc,
		transactionSvc,
		notificationSvc,
		recommendationSvc,
		cfg,
		domain.MongoDBLogger,
		analyticsDB,
	)

	logger.Info("Starting server", "port", cfg.Port)
	if err := app.Run(); err != nil {
		logger.Error("Failed to start server", "error", err)
		os.Exit(1)
	}
	select {}
}
