package routewatch

import (
	"context"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"syscall"
	"time"

	"git.eeqj.de/sneak/routewatch/internal/logger"
	"go.uber.org/fx"
)

const (
	// shutdownTimeout is the maximum time allowed for graceful shutdown
	shutdownTimeout = 60 * time.Second
	// debugInterval is how often to log debug stats
	debugInterval = 60 * time.Second
	// bytesPerMB is bytes per megabyte
	bytesPerMB = 1024 * 1024
)

// logDebugStats logs goroutine count and memory usage
func logDebugStats(logger *logger.Logger) {
	// Only run if DEBUG env var contains "routewatch"
	debugEnv := os.Getenv("DEBUG")
	if !strings.Contains(debugEnv, "routewatch") {
		return
	}

	ticker := time.NewTicker(debugInterval)
	defer ticker.Stop()

	for range ticker.C {
		var m runtime.MemStats
		runtime.ReadMemStats(&m)

		logger.Debug("System stats",
			"goroutines", runtime.NumGoroutine(),
			"alloc_mb", m.Alloc/bytesPerMB,
			"total_alloc_mb", m.TotalAlloc/bytesPerMB,
			"sys_mb", m.Sys/bytesPerMB,
			"num_gc", m.NumGC,
			"heap_alloc_mb", m.HeapAlloc/bytesPerMB,
			"heap_sys_mb", m.HeapSys/bytesPerMB,
			"heap_idle_mb", m.HeapIdle/bytesPerMB,
			"heap_inuse_mb", m.HeapInuse/bytesPerMB,
			"heap_released_mb", m.HeapReleased/bytesPerMB,
			"stack_inuse_mb", m.StackInuse/bytesPerMB,
		)
	}
}

// CLIEntry is the main entry point for the routewatch command-line interface.
// It initializes the application using the fx dependency injection framework,
// sets up signal handling for graceful shutdown, and starts the RouteWatch service.
// This function blocks until the application receives a shutdown signal or encounters
// a fatal error.
func CLIEntry() {
	app := fx.New(
		getModule(),
		fx.StopTimeout(shutdownTimeout), // Allow 60 seconds for graceful shutdown
		fx.Invoke(func(lc fx.Lifecycle, rw *RouteWatch, logger *logger.Logger, shutdowner fx.Shutdowner) {
			lc.Append(fx.Hook{
				OnStart: func(ctx context.Context) error {
					// Start debug stats logging
					go logDebugStats(logger)

					// Handle shutdown signals
					sigCh := make(chan os.Signal, 1)
					signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)

					go func() {
						<-sigCh
						logger.Info("Received shutdown signal")
						if err := shutdowner.Shutdown(); err != nil {
							logger.Error("Failed to shutdown gracefully", "error", err)
						}
					}()

					go func() {
						if err := rw.Run(ctx); err != nil {
							logger.Error("RouteWatch error", "error", err)
						}
					}()

					return nil
				},
				OnStop: func(_ context.Context) error {
					logger.Info("Shutting down RouteWatch")
					rw.Shutdown()

					return nil
				},
			})
		}),
	)

	app.Run()
}
