package main

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

	"github.com/edu-cloud/push-gateway/internal/config"
	"github.com/edu-cloud/push-gateway/internal/hub"
	"github.com/edu-cloud/push-gateway/internal/observability"
	"github.com/edu-cloud/push-gateway/internal/ws"
	"github.com/gin-gonic/gin"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
)

func main() {
	cfg := config.Load()
	// 初始化 OpenTelemetry tracer（endpoint 为空时自动跳过）
	tracerShutdown := observability.InitTracer("push-gateway", cfg.OTLPEndpoint)
	defer tracerShutdown()

	gin.SetMode(gin.ReleaseMode)

	h := hub.NewHub()
	wsHandler := ws.NewHandler(h, cfg.JWTSecret, cfg.DevMode, cfg.InternalAPIKey)

	r := gin.New()
	r.Use(gin.Recovery())
	// OpenTelemetry 自动埋点（HTTP 请求/响应 span）
	r.Use(otelgin.Middleware("push-gateway"))

	r.GET("/healthz", func(c *gin.Context) {
		c.JSON(200, gin.H{"status": "ok", "service": "push-gateway"})
	})

	// 就绪探针：检查 WebSocket hub 状态
	r.GET("/readyz", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"status":      "ok",
			"service":     "push-gateway",
			"connections": h.ClientCount(),
		})
	})

	// Prometheus 指标端点
	r.GET("/metrics", gin.WrapH(promhttp.Handler()))

	// WebSocket 升级端点
	r.GET("/ws", wsHandler.HandleWebSocket)

	// 内部推送 API（Msg 服务调用）
	api := r.Group("/internal")
	api.POST("/push", wsHandler.PushHandler)
	api.POST("/broadcast", wsHandler.BroadcastHandler)

	srv := &http.Server{
		Addr:         ":" + cfg.Port,
		Handler:      r,
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 60 * time.Second, // WebSocket 长连接
	}

	go func() {
		log.Printf("Push Gateway listening on :%s", cfg.Port)
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()

	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	log.Println("Shutting down Push Gateway...")

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal("Server forced to shutdown:", err)
	}
}
