package handlers

import (
	"github.com/google/uuid"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"veza-backend-api/internal/database"
)

// HealthResponse représente la réponse du health check
type HealthResponse struct {
	Status    string                 `json:"status"`
	Timestamp string                 `json:"timestamp"`
	Checks    map[string]HealthCheck `json:"checks"`
}

// HealthCheck représente le résultat d'un check individuel
type HealthCheck struct {
	Status    string  `json:"status"`
	Message   string  `json:"message,omitempty"`
	Duration  float64 `json:"duration_ms,omitempty"`
	Threshold float64 `json:"threshold_ms,omitempty"`
}

// HealthHandler gère les health checks
type HealthHandler struct {
	db     *gorm.DB
	logger *zap.Logger
	redis  interface{} // TODO: Typé avec le vrai type Redis
}

// NewHealthHandler crée un nouveau handler de health
func NewHealthHandler(db *gorm.DB, logger *zap.Logger, redis interface{}) *HealthHandler {
	return &HealthHandler{
		db:     db,
		logger: logger,
		redis:  redis,
	}
}

// NewHealthHandlerSimple crée un nouveau handler de health simple (sans logger/redis)
// Pour compatibilité avec la spécification T0012
func NewHealthHandlerSimple(db *gorm.DB) *HealthHandler {
	return &HealthHandler{
		db: db,
	}
}

// Check vérifie l'état de la base de données et retourne un status simple
// Cette méthode implémente la spécification T0012
func (h *HealthHandler) Check(c *gin.Context) {
	sqlDB, err := h.db.DB()
	dbStatus := "up"
	
	if err != nil || sqlDB.Ping() != nil {
		dbStatus = "down"
	}
	
	status := "ok"
	if dbStatus == "down" {
		status = "degraded"
	}
	
	c.JSON(http.StatusOK, gin.H{
		"status":    status,
		"database":  dbStatus,
		"timestamp": uuid.New(),
	})
}

// Health check endpoint (/health)
func (h *HealthHandler) Health(c *gin.Context) {
	response := HealthResponse{
		Status:    "ok",
		Timestamp: time.Now().UTC().Format(time.RFC3339),
		Checks:    make(map[string]HealthCheck),
	}

	// Check database
	dbCheck := h.checkDatabase()
	response.Checks["database"] = dbCheck

	// Check Redis
	redisCheck := h.checkRedis()
	response.Checks["redis"] = redisCheck

	// Déterminer le statut global
	for _, check := range response.Checks {
		if check.Status == "error" {
			response.Status = "degraded"
			break
		}
		if check.Status == "slow" {
			if response.Status != "degraded" {
				response.Status = "degraded"
			}
		}
	}

	statusCode := http.StatusOK
	if response.Status == "degraded" {
		statusCode = http.StatusServiceUnavailable
	}

	c.JSON(statusCode, response)
}

// Readiness check endpoint (/ready)
func (h *HealthHandler) Readiness(c *gin.Context) {
	response := HealthResponse{
		Status:    "ready",
		Timestamp: time.Now().UTC().Format(time.RFC3339),
		Checks:    make(map[string]HealthCheck),
	}

	// Vérifier que la DB est accessible
	dbCheck := h.checkDatabase()
	response.Checks["database"] = dbCheck

	// Vérifier que Redis est accessible
	redisCheck := h.checkRedis()
	response.Checks["redis"] = redisCheck

	// Si un check est en erreur, on n'est pas ready
	for _, check := range response.Checks {
		if check.Status == "error" {
			response.Status = "not_ready"
			c.JSON(http.StatusServiceUnavailable, response)
			return
		}
	}

	c.JSON(http.StatusOK, response)
}

// Liveness check endpoint (/live)
func (h *HealthHandler) Liveness(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"status":    "alive",
		"timestamp": time.Now().UTC().Format(time.RFC3339),
	})
}

// SimpleHealthCheck est une fonction simple pour le health check endpoint public
func SimpleHealthCheck(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"status":  "healthy",
		"service": "veza-backend-api",
	})
}

// checkDatabase vérifie la connexion à la base de données avec pool stats
func (h *HealthHandler) checkDatabase() HealthCheck {
	start := time.Now()

	// Utiliser IsConnectionHealthy avec timeout de 5 secondes
	err := database.IsConnectionHealthy(h.db, 5*time.Second)
	duration := time.Since(start)

	if err != nil {
		return HealthCheck{
			Status:  "error",
			Message: err.Error(),
			Duration: float64(duration.Nanoseconds()) / 1e6,
		}
	}

	threshold := 100.0 // 100ms threshold
	status := "ok"

	if duration.Milliseconds() > int64(threshold) {
		status = "slow"
	}

	// Récupérer les statistiques du pool
	poolStats, statsErr := database.GetPoolStats(h.db)
	var message string
	if statsErr == nil {
		message = "pool_connections"
		// On pourrait ajouter plus d'informations sur le pool ici
		_ = poolStats // Utiliser dans le futur pour plus de détails
	}

	return HealthCheck{
		Status:    status,
		Message:   message,
		Duration:  float64(duration.Nanoseconds()) / 1e6, // Convert to ms
		Threshold: threshold,
	}
}

// checkRedis vérifie la connexion à Redis
func (h *HealthHandler) checkRedis() HealthCheck {
	start := time.Now()

	// TODO: Implémenter le vrai check Redis
	// Pour l'instant, on simule
	duration := time.Since(start)
	status := "ok"

	if h.redis == nil {
		return HealthCheck{
			Status:  "error",
			Message: "Redis connection not configured",
		}
	}

	threshold := 50.0 // 50ms threshold
	if duration.Milliseconds() > int64(threshold) {
		status = "slow"
	}

	return HealthCheck{
		Status:    status,
		Duration:  float64(duration.Nanoseconds()) / 1e6,
		Threshold: threshold,
	}
}
