package httpserver

import (
	dbgen "Yimaru-Backend/gen/db"
	"Yimaru-Backend/internal/config"
	activitylogservice "Yimaru-Backend/internal/services/activity_log"
	"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"
	notificationservice "Yimaru-Backend/internal/services/notification"
	"Yimaru-Backend/internal/services/questions"
	"Yimaru-Backend/internal/services/recommendation"
	"Yimaru-Backend/internal/services/subscriptions"
	"Yimaru-Backend/internal/services/team"
	vimeoservice "Yimaru-Backend/internal/services/vimeo"

	"Yimaru-Backend/internal/services/settings"
	"Yimaru-Backend/internal/services/transaction"
	"Yimaru-Backend/internal/services/user"
	jwtutil "Yimaru-Backend/internal/web_server/jwt"
	customvalidator "Yimaru-Backend/internal/web_server/validator"
	"fmt"
	"log/slog"

	"go.uber.org/zap"

	"github.com/bytedance/sonic"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/cors"
)

type App struct {
	assessmentSvc     *assessment.Service
	courseSvc         *course_management.Service
	questionsSvc      *questions.Service
	subscriptionsSvc  *subscriptions.Service
	arifpaySvc        *arifpay.ArifpayService
	issueReportingSvc *issuereporting.Service
	vimeoSvc          *vimeoservice.Service
	teamSvc           *team.Service
	activityLogSvc    *activitylogservice.Service
	fiber             *fiber.App
	recommendationSvc recommendation.RecommendationService
	cfg               *config.Config
	logger            *slog.Logger
	NotidicationStore *notificationservice.Service
	port              int
	settingSvc        *settings.Service
	authSvc           *authentication.Service
	userSvc           *user.Service
	transactionSvc    *transaction.Service
	validator         *customvalidator.CustomValidator
	JwtConfig         jwtutil.JwtConfig
	Logger            *slog.Logger
	mongoLoggerSvc    *zap.Logger
	analyticsDB       *dbgen.Queries
}

func NewApp(
	assessmentSvc *assessment.Service,
	courseSvc *course_management.Service,
	questionsSvc *questions.Service,
	subscriptionsSvc *subscriptions.Service,
	arifpaySvc *arifpay.ArifpayService,
	issueReportingSvc *issuereporting.Service,
	vimeoSvc *vimeoservice.Service,
	teamSvc *team.Service,
	activityLogSvc *activitylogservice.Service,
	port int, validator *customvalidator.CustomValidator,
	settingSvc *settings.Service,
	authSvc *authentication.Service,
	logger *slog.Logger,
	JwtConfig jwtutil.JwtConfig,
	userSvc *user.Service,
	transactionSvc *transaction.Service,
	notidicationStore *notificationservice.Service,
	recommendationSvc recommendation.RecommendationService,
	cfg *config.Config,
	mongoLoggerSvc *zap.Logger,
	analyticsDB *dbgen.Queries,
) *App {
	app := fiber.New(fiber.Config{
		CaseSensitive:            true,
		DisableHeaderNormalizing: true,
		JSONEncoder:              sonic.Marshal,
		JSONDecoder:              sonic.Unmarshal,
		BodyLimit:                500 * 1024 * 1024, // 500 MB
	})

	app.Use(cors.New(cors.Config{
		AllowOrigins: "*",
		AllowMethods: "GET,POST,PUT,PATCH,DELETE,OPTIONS",
		AllowHeaders: "Content-Type,Authorization,platform",
		// AllowCredentials: true,
	}))

	app.Static("/static", "./static")

	s := &App{
		assessmentSvc:    assessmentSvc,
		courseSvc:        courseSvc,
		questionsSvc:     questionsSvc,
		subscriptionsSvc: subscriptionsSvc,
		arifpaySvc:       arifpaySvc,
		vimeoSvc:         vimeoSvc,
		teamSvc:          teamSvc,
		activityLogSvc:   activityLogSvc,
		issueReportingSvc: issueReportingSvc,
		fiber:             app,
		port:              port,
		settingSvc:        settingSvc,
		authSvc:           authSvc,
		validator:         validator,
		logger:            logger,
		JwtConfig:         JwtConfig,
		userSvc:           userSvc,
		transactionSvc:    transactionSvc,
		NotidicationStore: notidicationStore,
		Logger:            logger,
		recommendationSvc: recommendationSvc,
		cfg:               cfg,
		mongoLoggerSvc:    mongoLoggerSvc,
		analyticsDB:       analyticsDB,
	}

	s.initAppRoutes()

	return s
}

func (a *App) Run() error {
	return a.fiber.Listen(fmt.Sprintf(":%d", a.port))
}
