package main

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

	"proxyrotator/internal/api"
	"proxyrotator/internal/config"
	"proxyrotator/internal/importer"
	"proxyrotator/internal/selector"
	"proxyrotator/internal/store"
	"proxyrotator/internal/telegram"
	"proxyrotator/internal/tester"
)

func main() {
	// 配置日志
	slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
		Level: slog.LevelInfo,
	})))

	// 加载配置
	cfg := config.Load()

	slog.Info("starting proxyrotator",
		"listen_addr", cfg.ListenAddr,
		"max_concurrency", cfg.MaxConcurrency,
		"max_test_limit", cfg.MaxTestLimit,
		"lease_ttl", cfg.LeaseTTL,
		"telegram_enabled", cfg.TelegramBotToken != "",
	)

	// 连接数据库
	ctx := context.Background()
	pgStore, err := store.NewPgStore(ctx, cfg.DatabaseURL)
	if err != nil {
		log.Fatalf("failed to connect to database: %v", err)
	}
	defer pgStore.Close()

	slog.Info("connected to database")

	// 初始化组件
	imp := importer.NewImporter()
	tst := tester.NewHTTPTester()
	sel := selector.NewSelector(pgStore, cfg.LeaseTTL)

	// 初始化 Telegram Bot
	bot := telegram.NewBot(cfg, pgStore)

	// 启动 Telegram Bot
	if err := bot.Start(ctx); err != nil {
		slog.Warn("failed to start telegram bot", "error", err)
	}
	defer bot.Stop()

	// 创建路由
	router := api.NewRouter(pgStore, imp, tst, sel, cfg)

	// 创建 HTTP 服务器
	server := &http.Server{
		Addr:         cfg.ListenAddr,
		Handler:      router,
		ReadTimeout:  30 * time.Second,
		WriteTimeout: 120 * time.Second,
		IdleTimeout:  60 * time.Second,
	}

	// 启动后台任务：清理过期租约
	go cleanupLoop(ctx, pgStore)

	// 启动服务器（在 goroutine 中）
	go func() {
		slog.Info("server listening", "addr", cfg.ListenAddr)
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("server error: %v", err)
		}
	}()

	// 等待中断信号
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit

	slog.Info("shutting down server...")

	// 优雅关闭
	shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	if err := server.Shutdown(shutdownCtx); err != nil {
		log.Fatalf("server shutdown error: %v", err)
	}

	slog.Info("server stopped")
}

// cleanupLoop 定期清理过期租约
func cleanupLoop(ctx context.Context, s *store.PgStore) {
	ticker := time.NewTicker(1 * time.Minute)
	defer ticker.Stop()

	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			deleted, err := s.DeleteExpiredLeases(ctx)
			if err != nil {
				slog.Error("failed to cleanup expired leases", "error", err)
			} else if deleted > 0 {
				slog.Info("cleaned up expired leases", "count", deleted)
			}
		}
	}
}
