package app

import (
	"context"
	"net/http"

	"cmr-backend/internal/httpapi"
	"cmr-backend/internal/platform/assets"
	"cmr-backend/internal/platform/jwtx"
	"cmr-backend/internal/platform/wechatmini"
	"cmr-backend/internal/service"
	"cmr-backend/internal/store/postgres"
)

type App struct {
	router http.Handler
	store  *postgres.Store
}

func New(ctx context.Context, cfg Config) (*App, error) {
	pool, err := postgres.Open(ctx, cfg.DatabaseURL)
	if err != nil {
		return nil, err
	}

	store := postgres.NewStore(pool)
	jwtManager := jwtx.NewManager(cfg.JWTIssuer, cfg.JWTAccessSecret, cfg.JWTAccessTTL)
	wechatMiniClient := wechatmini.NewClient(cfg.WechatMiniAppID, cfg.WechatMiniSecret, cfg.WechatMiniDevPrefix)
	authService := service.NewAuthService(service.AuthSettings{
		AppEnv:          cfg.AppEnv,
		RefreshTTL:      cfg.RefreshTTL,
		SMSCodeTTL:      cfg.SMSCodeTTL,
		SMSCodeCooldown: cfg.SMSCodeCooldown,
		SMSProvider:     cfg.SMSProvider,
		DevSMSCode:      cfg.DevSMSCode,
		WechatMini:      wechatMiniClient,
	}, store, jwtManager)
	entryService := service.NewEntryService(store)
	entryHomeService := service.NewEntryHomeService(store)
	adminResourceService := service.NewAdminResourceService(store)
	adminProductionService := service.NewAdminProductionService(store)
	adminEventService := service.NewAdminEventService(store)
	eventService := service.NewEventService(store)
	eventPlayService := service.NewEventPlayService(store)
	assetPublisher := assets.NewOSSUtilPublisher(cfg.OSSUtilPath, cfg.OSSUtilConfigFile, cfg.AssetBucketRoot, cfg.AssetPublicBaseURL)
	configService := service.NewConfigService(store, cfg.LocalEventDir, cfg.AssetBaseURL, assetPublisher)
	adminPipelineService := service.NewAdminPipelineService(store, configService)
	homeService := service.NewHomeService(store)
	profileService := service.NewProfileService(store)
	resultService := service.NewResultService(store)
	sessionService := service.NewSessionService(store)
	devService := service.NewDevService(cfg.AppEnv, store)
	meService := service.NewMeService(store)
	router := httpapi.NewRouter(cfg.AppEnv, jwtManager, authService, entryService, entryHomeService, adminResourceService, adminProductionService, adminEventService, adminPipelineService, eventService, eventPlayService, configService, homeService, profileService, resultService, sessionService, devService, meService)

	return &App{
		router: router,
		store:  store,
	}, nil
}

func (a *App) Router() http.Handler {
	return a.router
}

func (a *App) Close() {
	if a.store != nil {
		a.store.Close()
	}
}
