package websocket

import (
	"api-service/internal/config"
	ws "api-service/internal/services/websocket"
	"fmt"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
)

// WebSocketHandler menangani koneksi WebSocket
type WebSocketHandler struct {
	hub               *ws.Hub
	config            config.WebSocketConfig
	upgrader          websocket.Upgrader
	monitoringManager *ws.MonitoringManager
}

// NewWebSocketHandler membuat handler WebSocket baru
func NewWebSocketHandler(hub *ws.Hub, config config.WebSocketConfig) *WebSocketHandler {
	return &WebSocketHandler{
		hub:               hub,
		config:            config,
		monitoringManager: ws.NewMonitoringManager(hub),
		upgrader: websocket.Upgrader{
			ReadBufferSize:  config.ReadBufferSize,
			WriteBufferSize: config.WriteBufferSize,
			CheckOrigin: func(r *http.Request) bool {
				// Dalam production, implementasikan validasi origin yang proper
				return true
			},
		},
	}
}

// HandleWebSocket menangani upgrade koneksi ke WebSocket
func (h *WebSocketHandler) HandleWebSocket(c *gin.Context) {
	// Ambil parameter dari query atau header
	clientID := c.Query("client_id")
	if clientID == "" {
		clientID = fmt.Sprintf("client_%d", time.Now().UnixNano())
	}

	staticID := c.Query("static_id")
	userID := c.Query("user_id")
	room := c.Query("room")
	ipAddress := c.ClientIP()

	// Upgrade koneksi HTTP ke WebSocket
	conn, err := h.upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   "Failed to upgrade connection",
			"details": err.Error(),
		})
		return
	}

	// Buat klien WebSocket baru
	client := ws.NewClient(clientID, staticID, userID, room, ipAddress, conn, h.hub, h.config)

	// Daftarkan klien ke hub
	h.hub.RegisterChannel() <- client

	// Jalankan goroutine untuk membaca dan menulis
	go client.ReadPump()
	go client.WritePump()
}

// GetWebSocketStats mengembalikan statistik WebSocket
func (h *WebSocketHandler) GetWebSocketStats(c *gin.Context) {
	stats := h.hub.GetStats()
	c.JSON(http.StatusOK, stats)
}

// TestWebSocketConnection endpoint untuk test koneksi WebSocket
func (h *WebSocketHandler) TestWebSocketConnection(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"message":  "WebSocket service is running",
		"status":   "active",
		"endpoint": "/api/v1/ws",
		"parameters": gin.H{
			"client_id": "optional, auto-generated if not provided",
			"static_id": "optional, for persistent client identification",
			"user_id":   "optional, for user identification",
			"room":      "optional, for room-based messaging",
		},
		"example":   "ws://meninjar.dev.rssa.id:8070/api/v1/ws?client_id=test_client&room=test_room",
		"timestamp": time.Now().Unix(),
	})
}

// GetDetailedStats mengembalikan statistik detail WebSocket
func (h *WebSocketHandler) GetDetailedStats(c *gin.Context) {
	detailedStats := h.monitoringManager.GetDetailedStats()
	c.JSON(http.StatusOK, gin.H{
		"admin_stats": detailedStats,
		"timestamp":   time.Now().Unix(),
	})
}

// DisconnectClient memutuskan koneksi klien tertentu
func (h *WebSocketHandler) DisconnectClient(c *gin.Context) {
	clientID := c.Param("clientId")
	success := h.monitoringManager.DisconnectClient(clientID)
	c.JSON(http.StatusOK, gin.H{
		"status":    "force disconnect attempted",
		"client_id": clientID,
		"success":   success,
		"timestamp": time.Now().Unix(),
	})
}

// CleanupInactiveClients membersihkan klien tidak aktif
func (h *WebSocketHandler) CleanupInactiveClients(c *gin.Context) {
	var req struct {
		InactiveMinutes int  `json:"inactive_minutes"`
		Force           bool `json:"force"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		req.InactiveMinutes = 10
		req.Force = false
	}

	cleanedCount := h.monitoringManager.CleanupInactiveClients(time.Duration(req.InactiveMinutes) * time.Minute)
	c.JSON(http.StatusOK, gin.H{
		"status":           "admin cleanup completed",
		"cleaned_clients":  cleanedCount,
		"inactive_minutes": req.InactiveMinutes,
		"force":            req.Force,
		"timestamp":        time.Now().Unix(),
	})
}
