package services

import (
	"context"
	"errors"
	"fmt"
	"github.com/google/uuid"
	"time"

	"github.com/golang-jwt/jwt/v5"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"veza-backend-api/internal/models"
)

type ChatService struct {
	jwtSecret string
	logger    *zap.Logger
	db        *gorm.DB
}

func NewChatService(jwtSecret string, logger *zap.Logger) *ChatService {
	if logger == nil {
		logger = zap.NewNop()
	}
	return &ChatService{
		jwtSecret: jwtSecret,
		logger:    logger,
	}
}

// NewChatServiceWithDB crée un nouveau ChatService avec accès à la base de données
func NewChatServiceWithDB(jwtSecret string, db *gorm.DB, logger *zap.Logger) *ChatService {
	if logger == nil {
		logger = zap.NewNop()
	}
	return &ChatService{
		jwtSecret: jwtSecret,
		logger:    logger,
		db:        db,
	}
}

type ChatTokenResponse struct {
	Token     string `json:"token"`
	ExpiresIn int64  `json:"expires_in"`
	WSUrl     string `json:"ws_url"`
}

func (s *ChatService) GenerateToken(userID uuid.UUID, username string) (*ChatTokenResponse, error) {
	if s.jwtSecret == "" {
		return nil, errors.New("JWT secret is not configured")
	}

	now := time.Now()
	expiration := 15 * time.Minute
	exp := now.Add(expiration)

	claims := jwt.MapClaims{
		"sub":  userID.String(),
		"name": username,
		"aud":  "veza-chat",
		"iss":  "veza-backend",
		"iat":  now.Unix(),
		"exp":  exp.Unix(),
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, err := token.SignedString([]byte(s.jwtSecret))
	if err != nil {
		return nil, fmt.Errorf("failed to sign token: %w", err)
	}

	return &ChatTokenResponse{
		Token:     tokenString,
		ExpiresIn: int64(expiration.Seconds()),
		WSUrl:     "/ws", // Relative path, frontend appends base URL
	}, nil
}

// ChatStats représente les statistiques du chat
type ChatStats struct {
	ActiveUsers   int64 `json:"active_users"`
	TotalMessages int64 `json:"total_messages"`
	RoomsActive   int64 `json:"rooms_active"`
}

// GetStats récupère les statistiques du chat
// BE-API-006: Implement chat stats endpoint
func (s *ChatService) GetStats(ctx context.Context) (*ChatStats, error) {
	if s.db == nil {
		return nil, errors.New("database connection not available")
	}

	stats := &ChatStats{}

	// Total messages (non supprimés)
	if err := s.db.WithContext(ctx).Model(&models.Message{}).
		Where("is_deleted = ?", false).
		Count(&stats.TotalMessages).Error; err != nil {
		return nil, fmt.Errorf("failed to count total messages: %w", err)
	}

	// Active users: utilisateurs distincts qui ont envoyé des messages dans les dernières 24h
	activeSince := time.Now().Add(-24 * time.Hour)
	var activeUsersCount int64
	if err := s.db.WithContext(ctx).Model(&models.Message{}).
		Where("is_deleted = ? AND created_at >= ?", false, activeSince).
		Distinct("user_id").
		Count(&activeUsersCount).Error; err != nil {
		return nil, fmt.Errorf("failed to count active users: %w", err)
	}
	stats.ActiveUsers = activeUsersCount

	// Rooms actives: rooms qui ont eu des messages dans les dernières 24h
	var roomsActiveCount int64
	if err := s.db.WithContext(ctx).Model(&models.Message{}).
		Where("is_deleted = ? AND created_at >= ?", false, activeSince).
		Distinct("room_id").
		Count(&roomsActiveCount).Error; err != nil {
		return nil, fmt.Errorf("failed to count active rooms: %w", err)
	}
	stats.RoomsActive = roomsActiveCount

	return stats, nil
}
