package main

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	"scheduler-backend/internal/api"
	"scheduler-backend/internal/executor"
	"scheduler-backend/internal/jobdef"
	storemongo "scheduler-backend/internal/store/mongo"
	"scheduler-backend/pkg/config"
	"scheduler-backend/pkg/log"
	redisclient "scheduler-backend/pkg/redis"
)

func main() {
	cfg := config.Load()
	logger := log.New()
	addr := fmt.Sprintf(":%d", cfg.HTTPPort)
	registry := jobdef.NewRegistry(
		jobdef.SampleHandler{},
		jobdef.URLRewriteHandler{},
		jobdef.S3MigrateHandler{},
	)
	rootCtx := context.Background()
	databases, err := storemongo.Connect(rootCtx, cfg)
	if err != nil {
		logger.Error("scheduler api mongo connect failed", "error", err)
		os.Exit(1)
	}
	redisConn, err := redisclient.Connect(rootCtx, cfg)
	if err != nil {
		logger.Error("scheduler api redis connect failed", "error", err)
		os.Exit(1)
	}
	jobConfigStore := storemongo.NewJobConfigStore(databases.MetaDB)
	if err := jobdef.SyncJobConfigs(rootCtx, "job-config-list", jobConfigStore, logger); err != nil {
		logger.Error("sync job configs failed", "error", err)
		os.Exit(1)
	}

	execSvc := executor.NewService(registry, jobdef.Runtime{
		Config:     cfg,
		Logger:     logger,
		MetaDB:     databases.MetaDB,
		BusinessDB: databases.BusinessDB,
		Redis:      redisConn,
	})

	router := api.NewRouter(api.RouterDeps{
		Registry:          registry,
		JobConfigStore:    jobConfigStore,
		ExecutionStore:    storemongo.NewJobExecutionStore(databases.MetaDB),
		ProfileStore:      storemongo.NewAdminProfileStore(databases.MetaDB),
		AdminUserStore:    storemongo.NewAdminUserStore(databases.MetaDB),
		ConfigStore:       storemongo.NewSystemConfigStore(databases.MetaDB),
		GlobalConfigStore: storemongo.NewGlobalConfigStore(databases.MetaDB),
		Executor:          execSvc,
	})
	logger.Info("scheduler api starting", "addr", addr)

	go func() {
		stop := make(chan os.Signal, 1)
		signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
		<-stop

		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()
		_ = redisConn.Close()
		_ = databases.Client.Disconnect(ctx)
		os.Exit(0)
	}()

	if err := router.Run(addr); err != nil {
		logger.Error("scheduler api stopped", "error", err)
	}
}
