package app

import (
	"context"
	"errors"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"ymhut-box/server/unified-management/internal/auth"
	"ymhut-box/server/unified-management/internal/config"
	"ymhut-box/server/unified-management/internal/db"
	"ymhut-box/server/unified-management/internal/feedback"
	"ymhut-box/server/unified-management/internal/legacy"
	"ymhut-box/server/unified-management/internal/notices"
	"ymhut-box/server/unified-management/internal/releases"
	"ymhut-box/server/unified-management/internal/sources"
	"ymhut-box/server/unified-management/internal/synclegacy"
	"ymhut-box/server/unified-management/internal/web"
)

func Run() {
	cfg, err := config.Load()
	if err != nil {
		log.Fatalf("load config: %v", err)
	}
	log.Printf("YMhut unified management %s preflight", config.Version)
	log.Printf("entrypoint ok: go run main.go")
	log.Printf("listen: %s", cfg.Listen)
	for _, line := range config.FormatPreflight(cfg, config.Preflight(cfg)) {
		log.Print(line)
	}
	if !cfg.Initialized && os.Getenv("YMHUT_SKIP_SETUP") != "1" {
		log.Printf("setup required: open http://%s/setup", cfg.Listen)
		runServer(cfg.Listen, web.NewSetupRouter(cfg))
		return
	}

	store, err := db.Open(cfg)
	if err != nil {
		log.Fatalf("open database: %v", err)
	}
	defer store.Close()

	if err := store.EnsureDefaultAdmin(context.Background()); err != nil {
		log.Fatalf("ensure default admin: %v", err)
	}

	noticeService := notices.NewService(cfg, store)
	if err := noticeService.Import(context.Background()); err != nil {
		log.Printf("update notice import skipped: %v", err)
	}
	releaseService := releases.NewService(cfg, store, noticeService)
	sourceService := sources.NewService(cfg, store)
	feedbackService := feedback.NewService(cfg, store)
	legacyService := legacy.NewService(cfg, store)
	legacySyncService := synclegacy.New(cfg, store, noticeService)
	authService := auth.NewService(store)

	if err := legacyService.EnsureSeedDocuments(context.Background()); err != nil {
		log.Printf("legacy json seed skipped: %v", err)
	}
	if err := sourceService.ImportLegacyMediaTypesIfEmpty(context.Background()); err != nil {
		log.Printf("legacy media source import skipped: %v", err)
	}
	sourceService.Start(context.Background())
	defer sourceService.Stop()

	server := &http.Server{
		Addr:              cfg.Listen,
		Handler:           web.NewRouter(cfg, store, authService, feedbackService, releaseService, sourceService, legacyService, noticeService, legacySyncService),
		ReadHeaderTimeout: 10 * time.Second,
	}

	runHTTPServer(server)
}

func runServer(addr string, handler http.Handler) {
	server := &http.Server{
		Addr:              addr,
		Handler:           handler,
		ReadHeaderTimeout: 10 * time.Second,
	}
	runHTTPServer(server)
}

func runHTTPServer(server *http.Server) {
	go func() {
		log.Printf("YMhut unified management listening on %s", server.Addr)
		if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			log.Fatalf("listen: %v", err)
		}
	}()

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
	<-stop

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	if err := server.Shutdown(ctx); err != nil {
		log.Printf("shutdown: %v", err)
	}
}
