package services

import (
	"context"
	"fmt"

	"github.com/google/uuid"

	"veza-backend-api/internal/models"

	"go.uber.org/zap"
	"gorm.io/gorm"
)

// TrackLikeService gère les opérations sur les likes de tracks
type TrackLikeService struct {
	db     *gorm.DB
	logger *zap.Logger
}

// NewTrackLikeService crée un nouveau service de likes de tracks
func NewTrackLikeService(db *gorm.DB, logger *zap.Logger) *TrackLikeService {
	if logger == nil {
		logger = zap.NewNop()
	}
	return &TrackLikeService{
		db:     db,
		logger: logger,
	}
}

// LikeTrack ajoute un like d'un utilisateur sur un track
// MIGRATION UUID: userID migré vers uuid.UUID, trackID reste int64 - Corrected: trackID est maintenant uuid.UUID
func (s *TrackLikeService) LikeTrack(ctx context.Context, userID uuid.UUID, trackID uuid.UUID) error { // Changed trackID to uuid.UUID
	// Vérifier si le track existe
	var track models.Track
	if err := s.db.WithContext(ctx).First(&track, "id = ?", trackID).Error; err != nil { // Updated query
		if err == gorm.ErrRecordNotFound {
			return fmt.Errorf("track not found")
		}
		return fmt.Errorf("failed to check track: %w", err)
	}

	// Vérifier si l'utilisateur a déjà liké ce track
	var existing models.TrackLike
	if err := s.db.WithContext(ctx).Where("user_id = ? AND track_id = ?", userID, trackID).First(&existing).Error; err == nil {
		// Déjà liké, retourner nil (idempotent)
		return nil
	} else if err != gorm.ErrRecordNotFound {
		return fmt.Errorf("failed to check existing like: %w", err)
	}

	// Créer le like
	like := models.TrackLike{
		UserID:  userID,
		TrackID: trackID,
	}
	if err := s.db.WithContext(ctx).Create(&like).Error; err != nil {
		return fmt.Errorf("failed to create like: %w", err)
	}

	// Mettre à jour le compteur de likes du track
	if err := s.db.WithContext(ctx).Model(&track).UpdateColumn("like_count", gorm.Expr("like_count + ?", 1)).Error; err != nil {
		s.logger.Warn("Failed to update track like_count",
			zap.Any("track_id", trackID), // Changed to zap.Any for uuid.UUID
			zap.Error(err),
		)
		// Ne pas retourner l'erreur, le like a été créé avec succès
	}

	s.logger.Info("Track liked",
		zap.String("user_id", userID.String()),
		zap.Any("track_id", trackID), // Changed to zap.Any for uuid.UUID
	)

	return nil
}

// UnlikeTrack supprime un like d'un utilisateur sur un track
// MIGRATION UUID: userID migré vers uuid.UUID, trackID reste int64 - Corrected: trackID est maintenant uuid.UUID
func (s *TrackLikeService) UnlikeTrack(ctx context.Context, userID uuid.UUID, trackID uuid.UUID) error { // Changed trackID to uuid.UUID
	// Vérifier si le like existe
	var like models.TrackLike
	if err := s.db.WithContext(ctx).Where("user_id = ? AND track_id = ?", userID, trackID).First(&like).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			// Pas de like à supprimer, retourner nil (idempotent)
			return nil
		}
		return fmt.Errorf("failed to check like: %w", err)
	}

	// Supprimer le like
	if err := s.db.WithContext(ctx).Delete(&like).Error; err != nil {
		return fmt.Errorf("failed to delete like: %w", err)
	}

	// Mettre à jour le compteur de likes du track
	var track models.Track
	if err := s.db.WithContext(ctx).First(&track, "id = ?", trackID).Error; err == nil { // Updated query
		// Use CASE expression for SQLite compatibility (GREATEST is not supported in SQLite)
		if err := s.db.WithContext(ctx).Model(&track).UpdateColumn("like_count", gorm.Expr("CASE WHEN like_count - 1 < 0 THEN 0 ELSE like_count - 1 END")).Error; err != nil {
			s.logger.Warn("Failed to update track like_count",
				zap.Any("track_id", trackID), // Changed to zap.Any for uuid.UUID
				zap.Error(err),
			)
			// Ne pas retourner l'erreur, le like a été supprimé avec succès
		}
	}

	s.logger.Info("Track unliked",
		zap.String("user_id", userID.String()),
		zap.Any("track_id", trackID), // Changed to zap.Any for uuid.UUID
	)

	return nil
}

// IsLiked vérifie si un utilisateur a liké un track
func (s *TrackLikeService) IsLiked(ctx context.Context, userID uuid.UUID, trackID uuid.UUID) (bool, error) { // Changed trackID to uuid.UUID
	var count int64
	err := s.db.WithContext(ctx).Model(&models.TrackLike{}).
		Where("user_id = ? AND track_id = ?", userID, trackID).
		Count(&count).Error
	if err != nil {
		return false, fmt.Errorf("failed to check like: %w", err)
	}
	return count > 0, nil
}

// GetTrackLikesCount retourne le nombre de likes d'un track
func (s *TrackLikeService) GetTrackLikesCount(ctx context.Context, trackID uuid.UUID) (int64, error) { // Changed trackID to uuid.UUID
	var count int64
	err := s.db.WithContext(ctx).Model(&models.TrackLike{}).
		Where("track_id = ?", trackID).
		Count(&count).Error
	if err != nil {
		return 0, fmt.Errorf("failed to get likes count: %w", err)
	}
	return count, nil
}

// GetUserLikedTracks retourne la liste des tracks likés par un utilisateur
func (s *TrackLikeService) GetUserLikedTracks(ctx context.Context, userID uuid.UUID, limit, offset int) ([]models.Track, error) {
	var tracks []models.Track

	query := s.db.WithContext(ctx).
		Joins("INNER JOIN track_likes ON tracks.id = track_likes.track_id").
		Where("track_likes.user_id = ?", userID).
		Order("track_likes.created_at DESC")

	if limit > 0 {
		query = query.Limit(limit)
	}
	if offset > 0 {
		query = query.Offset(offset)
	}

	if err := query.Find(&tracks).Error; err != nil {
		return nil, fmt.Errorf("failed to get user liked tracks: %w", err)
	}

	return tracks, nil
}

// GetUserLikedTracksCount retourne le nombre total de tracks likés par un utilisateur
func (s *TrackLikeService) GetUserLikedTracksCount(ctx context.Context, userID uuid.UUID) (int64, error) {
	var count int64
	err := s.db.WithContext(ctx).Model(&models.TrackLike{}).
		Where("user_id = ?", userID).
		Count(&count).Error
	if err != nil {
		return 0, fmt.Errorf("failed to get user liked tracks count: %w", err)
	}
	return count, nil
}
