package services

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

	"veza-backend-api/internal/repositories"

	"go.uber.org/zap"
)

// PlaylistNotificationService handles playlist-specific notifications
// T0508: Create Playlist Notifications
type PlaylistNotificationService struct {
	notificationService *NotificationService
	playlistRepo        repositories.PlaylistRepository
	collaboratorRepo    repositories.PlaylistCollaboratorRepository
	logger              *zap.Logger
}

// NewPlaylistNotificationService creates a new playlist notification service
func NewPlaylistNotificationService(
	notificationService *NotificationService,
	playlistRepo repositories.PlaylistRepository,
	collaboratorRepo repositories.PlaylistCollaboratorRepository,
	logger *zap.Logger,
) *PlaylistNotificationService {
	if logger == nil {
		logger = zap.NewNop()
	}
	return &PlaylistNotificationService{
		notificationService: notificationService,
		playlistRepo:        playlistRepo,
		collaboratorRepo:    collaboratorRepo,
		logger:              logger,
	}
}

// NotifyCollaboratorAdded notifies a user when they are added as a collaborator
// T0508: Create Playlist Notifications
// MIGRATION UUID: Completée.
func (pns *PlaylistNotificationService) NotifyCollaboratorAdded(ctx context.Context, playlistID uuid.UUID, collaboratorUserID uuid.UUID, addedByUserID uuid.UUID) error {
	// Get playlist info
	playlist, err := pns.playlistRepo.GetByID(ctx, playlistID)
	if err != nil {
		return fmt.Errorf("failed to get playlist: %w", err)
	}

	// Get collaborator info using GetCollaborator (which takes playlistID and userID)
	_, err = pns.collaboratorRepo.GetCollaborator(ctx, playlistID, collaboratorUserID)
	if err != nil {
		return fmt.Errorf("failed to get collaborator: %w", err)
	}

	// Get added by user info (we'll use a simple query for now)
	// In a real implementation, you might want to get the username
	title := "Nouveau collaborateur"
	content := fmt.Sprintf("Vous avez été ajouté comme collaborateur à la playlist \"%s\"", playlist.Title)
	link := fmt.Sprintf("/playlists/%s", playlistID.String())

	return pns.notificationService.CreateNotification(
		collaboratorUserID,
		"playlist_collaborator_added",
		title,
		content,
		link,
	)
}

// NotifyTrackAdded notifies playlist owner and collaborators when a track is added
// T0508: Create Playlist Notifications
// trackTitle can be empty if not available, will use a generic message
// MIGRATION UUID: Completée.
func (pns *PlaylistNotificationService) NotifyTrackAdded(ctx context.Context, playlistID uuid.UUID, trackTitle string, addedByUserID uuid.UUID) error {
	// Get playlist info
	playlist, err := pns.playlistRepo.GetByID(ctx, playlistID)
	if err != nil {
		return fmt.Errorf("failed to get playlist: %w", err)
	}

	// Notify playlist owner (if not the one who added the track)
	if playlist.UserID != addedByUserID {
		title := "Track ajouté"
		var content string
		if trackTitle != "" {
			content = fmt.Sprintf("Un nouveau track \"%s\" a été ajouté à votre playlist \"%s\"", trackTitle, playlist.Title)
		} else {
			content = fmt.Sprintf("Un nouveau track a été ajouté à votre playlist \"%s\"", playlist.Title)
		}
		link := fmt.Sprintf("/playlists/%s", playlistID.String())

		if err := pns.notificationService.CreateNotification(
			playlist.UserID,
			"playlist_track_added",
			title,
			content,
			link,
		); err != nil {
			pns.logger.Warn("Failed to notify playlist owner", zap.Error(err))
		}
	}

	// Notify all collaborators (except the one who added the track)
	collaborators, err := pns.collaboratorRepo.GetCollaborators(ctx, playlistID)
	if err != nil {
		pns.logger.Warn("Failed to get collaborators", zap.Error(err))
		return nil // Don't fail the whole operation if we can't notify collaborators
	}

	title := "Track ajouté"
	var content string
	if trackTitle != "" {
		content = fmt.Sprintf("Un nouveau track \"%s\" a été ajouté à la playlist \"%s\"", trackTitle, playlist.Title)
	} else {
		content = fmt.Sprintf("Un nouveau track a été ajouté à la playlist \"%s\"", playlist.Title)
	}
	link := fmt.Sprintf("/playlists/%s", playlistID.String())

	for _, collaborator := range collaborators {
		// Skip the user who added the track
		if collaborator.UserID == addedByUserID {
			continue
		}

		if err := pns.notificationService.CreateNotification(
			collaborator.UserID,
			"playlist_track_added",
			title,
			content,
			link,
		); err != nil {
			pns.logger.Warn("Failed to notify collaborator", zap.String("userID", collaborator.UserID.String()), zap.Error(err))
		}
	}

	return nil
}

// NotifyPlaylistShared notifies when a playlist is shared via a share link
// T0508: Create Playlist Notifications
// MIGRATION UUID: Completée.
func (pns *PlaylistNotificationService) NotifyPlaylistShared(ctx context.Context, playlistID uuid.UUID, sharedByUserID uuid.UUID) error {
	// Get playlist info
	playlist, err := pns.playlistRepo.GetByID(ctx, playlistID)
	if err != nil {
		return fmt.Errorf("failed to get playlist: %w", err)
	}

	// Notify playlist owner (if not the one who shared)
	if playlist.UserID != sharedByUserID {
		title := "Playlist partagée"
		content := fmt.Sprintf("Votre playlist \"%s\" a été partagée", playlist.Title)
		link := fmt.Sprintf("/playlists/%s", playlistID.String())

		return pns.notificationService.CreateNotification(
			playlist.UserID,
			"playlist_shared",
			title,
			content,
			link,
		)
	}

	return nil
}

// NotifyPlaylistUpdated notifies collaborators when a playlist is updated
// T0508: Create Playlist Notifications
// MIGRATION UUID: Completée.
func (pns *PlaylistNotificationService) NotifyPlaylistUpdated(ctx context.Context, playlistID uuid.UUID, updatedByUserID uuid.UUID) error {
	// Get playlist info
	playlist, err := pns.playlistRepo.GetByID(ctx, playlistID)
	if err != nil {
		return fmt.Errorf("failed to get playlist: %w", err)
	}

	// Notify playlist owner (if not the one who updated)
	if playlist.UserID != updatedByUserID {
		title := "Playlist mise à jour"
		content := fmt.Sprintf("La playlist \"%s\" a été mise à jour", playlist.Title)
		link := fmt.Sprintf("/playlists/%s", playlistID.String())

		if err := pns.notificationService.CreateNotification(
			playlist.UserID,
			"playlist_updated",
			title,
			content,
			link,
		); err != nil {
			pns.logger.Warn("Failed to notify playlist owner", zap.Error(err))
		}
	}

	// Notify all collaborators (except the one who updated)
	collaborators, err := pns.collaboratorRepo.GetCollaborators(ctx, playlistID)
	if err != nil {
		pns.logger.Warn("Failed to get collaborators", zap.Error(err))
		return nil
	}

	title := "Playlist mise à jour"
	content := fmt.Sprintf("La playlist \"%s\" a été mise à jour", playlist.Title)
	link := fmt.Sprintf("/playlists/%s", playlistID.String())

	for _, collaborator := range collaborators {
		// Skip the user who updated
		if collaborator.UserID == updatedByUserID {
			continue
		}

		if err := pns.notificationService.CreateNotification(
			collaborator.UserID,
			"playlist_updated",
			title,
			content,
			link,
		); err != nil {
			pns.logger.Warn("Failed to notify collaborator", zap.String("userID", collaborator.UserID.String()), zap.Error(err))
		}
	}

	return nil
}
