package services

import (
	"context"
	"errors"
	"fmt"

	"veza-backend-api/internal/models"
	"go.uber.org/zap"
)

// PlaylistDuplicateService gère la duplication de playlists
// T0495: Create Playlist Duplicate Feature
type PlaylistDuplicateService struct {
	playlistService *PlaylistService
	logger          *zap.Logger
}

// NewPlaylistDuplicateService crée un nouveau service de duplication de playlists
func NewPlaylistDuplicateService(playlistService *PlaylistService, logger *zap.Logger) *PlaylistDuplicateService {
	if logger == nil {
		logger = zap.NewNop()
	}
	return &PlaylistDuplicateService{
		playlistService: playlistService,
		logger:          logger,
	}
}

// DuplicatePlaylistRequest représente la requête de duplication
type DuplicatePlaylistRequest struct {
	NewTitle       string `json:"new_title"`
	NewDescription string `json:"new_description,omitempty"`
	IsPublic       *bool  `json:"is_public,omitempty"`
}

// DuplicatePlaylist duplique une playlist avec tous ses tracks
// T0495: Create Playlist Duplicate Feature
func (s *PlaylistDuplicateService) DuplicatePlaylist(
	ctx context.Context,
	playlistID int64,
	userID int64,
	request DuplicatePlaylistRequest,
) (*models.Playlist, error) {
	// Récupérer la playlist originale
	userIDPtr := &userID
	originalPlaylist, err := s.playlistService.GetPlaylist(ctx, playlistID, userIDPtr)
	if err != nil {
		if err.Error() == "playlist not found" {
			return nil, errors.New("playlist not found")
		}
		return nil, fmt.Errorf("failed to get playlist: %w", err)
	}

	// Vérifier que l'utilisateur a accès à la playlist (propriétaire, collaborateur ou publique)
	if originalPlaylist.UserID != userID && !originalPlaylist.IsPublic {
		// Vérifier si l'utilisateur est collaborateur
		hasAccess, err := s.playlistService.CheckPermission(ctx, playlistID, userID, models.PlaylistPermissionRead)
		if err != nil || !hasAccess {
			return nil, errors.New("forbidden: you don't have access to this playlist")
		}
	}

	// Déterminer le titre de la nouvelle playlist
	newTitle := request.NewTitle
	if newTitle == "" {
		newTitle = originalPlaylist.Title + " (Copy)"
	}

	// Déterminer la description
	newDescription := request.NewDescription
	if newDescription == "" {
		newDescription = originalPlaylist.Description
	}

	// Déterminer si la playlist est publique
	isPublic := originalPlaylist.IsPublic
	if request.IsPublic != nil {
		isPublic = *request.IsPublic
	}

	// Créer la nouvelle playlist
	newPlaylist, err := s.playlistService.CreatePlaylist(
		ctx,
		userID,
		newTitle,
		newDescription,
		isPublic,
	)
	if err != nil {
		return nil, fmt.Errorf("failed to create duplicate playlist: %w", err)
	}

	// Dupliquer les tracks
	if originalPlaylist.Tracks != nil && len(originalPlaylist.Tracks) > 0 {
		for _, playlistTrack := range originalPlaylist.Tracks {
			// Track est un struct (non-pointeur), toujours valide
			{
				// Ajouter le track à la nouvelle playlist avec la même position
				err := s.playlistService.AddTrackToPlaylist(
					ctx,
					newPlaylist.ID,
					playlistTrack.Track.ID,
					userID,
					playlistTrack.Position,
				)
				if err != nil {
					// Log l'erreur mais continue avec les autres tracks
					s.logger.Warn("Failed to add track to duplicated playlist",
						zap.String("playlist_id", newPlaylist.ID.String()),
						zap.Int64("track_id", playlistTrack.Track.ID),
						zap.Error(err),
					)
					// On continue avec les autres tracks plutôt que d'échouer complètement
					continue
				}
			}
		}
	}

	s.logger.Info("Playlist duplicated",
		zap.Int64("original_playlist_id", playlistID),
		zap.String("new_playlist_id", newPlaylist.ID.String()),
		zap.Int64("user_id", userID),
		zap.Int("tracks_count", len(originalPlaylist.Tracks)),
	)

	return newPlaylist, nil
}

