package main

import (
	// "context"

	// "context"
	"context"
	"fmt"
	"log"
	"log/slog"
	"os"
	"time"

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

	// "github.com/gofiber/fiber/v2"

	"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/infrastructure"
	customlogger "github.com/SamuelTariku/FortuneBet-Backend/internal/logger"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/logger/mongoLogger"

	// mongologger "github.com/SamuelTariku/FortuneBet-Backend/internal/logger/mongoLogger"

	// "github.com/SamuelTariku/FortuneBet-Backend/internal/logger/mongoLogger"

	"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"

	// "github.com/SamuelTariku/FortuneBet-Backend/internal/router"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/chapa"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/company"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/currency"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/league"
	notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notfication"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation"
	referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/report"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/result"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
	virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame"
	alea "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/Alea"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet/monitor"

	// "github.com/SamuelTariku/FortuneBet-Backend/internal/utils"
	httpserver "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server"
	jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt"
	customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/worker"
)

// @title FortuneBet API
// @version 1.0.1
// @description This is server for FortuneBet.
// @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()
	if err != nil {
		log.Fatalf("Logger initialization failed: %v", err)
	}
	defer domain.MongoDBLogger.Sync()

	zap.ReplaceGlobals(domain.MongoDBLogger)

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

	// Initialize services
	authSvc := authentication.NewService(store, store, cfg.RefreshExpiry)
	userSvc := user.NewService(store, store, cfg)
	eventSvc := event.New(cfg.Bet365Token, store)
	oddsSvc := odds.New(store, cfg, logger)
	ticketSvc := ticket.NewService(store)
	notificationRepo := repository.NewNotificationRepository(store)
	virtuaGamesRepo := repository.NewVirtualGameRepository(store)
	notificationSvc := notificationservice.New(notificationRepo, logger, cfg)

	var notificatioStore notificationservice.NotificationStore

	walletSvc := wallet.NewService(
		wallet.WalletStore(store),
		wallet.TransferStore(store),
		notificatioStore,
		logger,
	)

	transactionSvc := transaction.NewService(store)
	branchSvc := branch.NewService(store)
	companySvc := company.NewService(store)
	leagueSvc := league.New(store)
	betSvc := bet.NewService(store, eventSvc, *oddsSvc, *walletSvc, *branchSvc, logger, domain.MongoDBLogger)
	resultSvc := result.NewService(store, cfg, logger, *betSvc, *oddsSvc, eventSvc, leagueSvc)
	referalRepo := repository.NewReferralRepository(store)
	vitualGameRepo := repository.NewVirtualGameRepository(store)
	recommendationRepo := repository.NewRecommendationRepository(store)

	referalSvc := referralservice.New(referalRepo, *walletSvc, store, cfg, logger)
	virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger)
	aleaService := alea.NewAleaPlayService(vitualGameRepo, *walletSvc, cfg, logger)
	veliService := veli.NewVeliPlayService(vitualGameRepo, *walletSvc, cfg, logger)
	recommendationSvc := recommendation.NewService(recommendationRepo)
	chapaClient := chapa.NewClient(cfg.CHAPA_BASE_URL, cfg.CHAPA_SECRET_KEY)

	chapaSvc := chapa.NewService(
		wallet.TransferStore(store),
		*walletSvc,
		user.UserStore(store),
		chapaClient,
	)

	reportRepo := repository.NewReportRepo(store)
	currRepo := repository.NewCurrencyPostgresRepository(store)

	fixerFertcherSvc := currency.NewFixerFetcher(
		cfg.FIXER_API_KEY,
		cfg.FIXER_BASE_URL,
	)

	reportSvc := report.NewService(
		bet.BetStore(store),
		wallet.WalletStore(store),
		transaction.TransactionStore(store),
		branch.BranchStore(store),
		user.UserStore(store),
		reportRepo,
		company.CompanyStore(store),
		virtuaGamesRepo,
		notificationRepo,
		logger,
	)

	// 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

	// Initialize wallet monitoring
	walletMonitorSvc := monitor.NewService(
		*walletSvc,
		*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.StartDataFetchingCrons(eventSvc, *oddsSvc, resultSvc)
	httpserver.StartTicketCrons(*ticketSvc)
	go httpserver.SetupReportCronJob(reportWorker)

	// Initialize and start HTTP server
	app := httpserver.NewApp(
		currSvc,
		cfg.Port,
		v,
		authSvc,
		logger,
		jwtutil.JwtConfig{
			JwtAccessKey:    cfg.JwtKey,
			JwtAccessExpiry: cfg.AccessExpiry,
		},
		userSvc,
		ticketSvc,
		betSvc,
		reportSvc, // Make sure httpserver.NewApp accepts this parameter
		chapaSvc,
		walletSvc,
		transactionSvc,
		branchSvc,
		companySvc,
		notificationSvc,
		oddsSvc,
		eventSvc,
		leagueSvc,
		referalSvc,
		virtualGameSvc,
		aleaService,
		veliService,
		recommendationSvc,
		resultSvc,
		cfg,
	)

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