package services

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"veza-backend-api/internal/models"

	"github.com/google/uuid"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// DataExportService gère l'export de données utilisateur pour la conformité GDPR (BE-SVC-022)
type DataExportService struct {
	db     *gorm.DB
	logger *zap.Logger
}

// NewDataExportService crée un nouveau service d'export de données
func NewDataExportService(db *gorm.DB, logger *zap.Logger) *DataExportService {
	return &DataExportService{
		db:     db,
		logger: logger,
	}
}

// UserDataExport représente toutes les données d'un utilisateur à exporter
type UserDataExport struct {
	UserID       uuid.UUID           `json:"user_id"`
	ExportedAt   time.Time           `json:"exported_at"`
	Profile      *UserProfileExport  `json:"profile"`
	Settings     *UserSettingsExport `json:"settings"`
	Tracks       []TrackExport       `json:"tracks"`
	Playlists    []PlaylistExport    `json:"playlists"`
	Comments     []CommentExport     `json:"comments"`
	Likes        []LikeExport        `json:"likes"`
	Analytics    []AnalyticsExport   `json:"analytics"`
	FederatedIDs []FederatedIDExport `json:"federated_identities"`
	Roles        []RoleExport        `json:"roles"`
}

// UserProfileExport représente les données de profil utilisateur
type UserProfileExport struct {
	ID          uuid.UUID  `json:"id"`
	Username    string     `json:"username"`
	Email       string     `json:"email"`
	FirstName   string     `json:"first_name"`
	LastName    string     `json:"last_name"`
	Avatar      string     `json:"avatar"`
	Bio         string     `json:"bio"`
	Location    string     `json:"location"`
	Birthdate   *time.Time `json:"birthdate"`
	Gender      string     `json:"gender"`
	Role        string     `json:"role"`
	IsActive    bool       `json:"is_active"`
	IsVerified  bool       `json:"is_verified"`
	IsPublic    bool       `json:"is_public"`
	LastLoginAt *time.Time `json:"last_login_at"`
	CreatedAt   time.Time  `json:"created_at"`
	UpdatedAt   time.Time  `json:"updated_at"`
}

// UserSettingsExport représente les paramètres utilisateur
type UserSettingsExport struct {
	EmailNotifications   bool `json:"email_notifications"`
	PushNotifications    bool `json:"push_notifications"`
	BrowserNotifications bool `json:"browser_notifications"`
	EmailOnFollow        bool `json:"email_on_follow"`
	EmailOnLike          bool `json:"email_on_like"`
	EmailOnComment       bool `json:"email_on_comment"`
	EmailOnMessage       bool `json:"email_on_message"`
	EmailOnMention       bool `json:"email_on_mention"`
	EmailMarketing       bool `json:"email_marketing"`
	AllowSearchIndexing  bool `json:"allow_search_indexing"`
	ShowActivity         bool `json:"show_activity"`
	ExplicitContent      bool `json:"explicit_content"`
	Autoplay             bool `json:"autoplay"`
}

// TrackExport représente un track exporté
type TrackExport struct {
	ID           uuid.UUID `json:"id"`
	Title        string    `json:"title"`
	Artist       string    `json:"artist"`
	Album        string    `json:"album"`
	Duration     int       `json:"duration"`
	Genre        string    `json:"genre"`
	Year         int       `json:"year"`
	FilePath     string    `json:"file_path"`
	CoverArtPath string    `json:"cover_art_path"`
	IsPublic     bool      `json:"is_public"`
	Status       string    `json:"status"`
	PlayCount    int64     `json:"play_count"`
	LikeCount    int64     `json:"like_count"`
	CreatedAt    time.Time `json:"created_at"`
	UpdatedAt    time.Time `json:"updated_at"`
}

// PlaylistExport représente une playlist exportée
type PlaylistExport struct {
	ID            uuid.UUID `json:"id"`
	Title         string    `json:"title"`
	Description   string    `json:"description"`
	IsPublic      bool      `json:"is_public"`
	TrackCount    int       `json:"track_count"`
	FollowerCount int       `json:"follower_count"`
	CreatedAt     time.Time `json:"created_at"`
	UpdatedAt     time.Time `json:"updated_at"`
}

// CommentExport représente un commentaire exporté
type CommentExport struct {
	ID        uuid.UUID `json:"id"`
	TrackID   uuid.UUID `json:"track_id"`
	Content   string    `json:"content"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

// LikeExport représente un like exporté
type LikeExport struct {
	ID        uuid.UUID `json:"id"`
	TrackID   uuid.UUID `json:"track_id"`
	CreatedAt time.Time `json:"created_at"`
}

// AnalyticsExport représente des analytics exportées
type AnalyticsExport struct {
	ID             uuid.UUID  `json:"id"`
	TrackID        uuid.UUID  `json:"track_id"`
	PlayTime       int        `json:"play_time"`
	PauseCount     int        `json:"pause_count"`
	SeekCount      int        `json:"seek_count"`
	CompletionRate float64    `json:"completion_rate"`
	StartedAt      time.Time  `json:"started_at"`
	EndedAt        *time.Time `json:"ended_at"`
	CreatedAt      time.Time  `json:"created_at"`
}

// FederatedIDExport représente une identité fédérée exportée
type FederatedIDExport struct {
	ID          uuid.UUID `json:"id"`
	Provider    string    `json:"provider"`
	ProviderID  string    `json:"provider_id"`
	Email       string    `json:"email"`
	DisplayName string    `json:"display_name"`
	CreatedAt   time.Time `json:"created_at"`
}

// RoleExport représente un rôle exporté
type RoleExport struct {
	ID         uuid.UUID  `json:"id"`
	RoleName   string     `json:"role_name"`
	AssignedAt time.Time  `json:"assigned_at"`
	ExpiresAt  *time.Time `json:"expires_at"`
	IsActive   bool       `json:"is_active"`
}

// ExportUserData exporte toutes les données d'un utilisateur (BE-SVC-022)
func (s *DataExportService) ExportUserData(ctx context.Context, userID uuid.UUID) (*UserDataExport, error) {
	export := &UserDataExport{
		UserID:     userID,
		ExportedAt: time.Now(),
	}

	// 1. Récupérer le profil utilisateur
	var user models.User
	if err := s.db.WithContext(ctx).First(&user, "id = ?", userID).Error; err != nil {
		return nil, fmt.Errorf("failed to get user: %w", err)
	}

	export.Profile = &UserProfileExport{
		ID:          user.ID,
		Username:    user.Username,
		Email:       user.Email,
		FirstName:   user.FirstName,
		LastName:    user.LastName,
		Avatar:      user.Avatar,
		Bio:         user.Bio,
		Location:    user.Location,
		Birthdate:   user.Birthdate,
		Gender:      user.Gender,
		Role:        user.Role,
		IsActive:    user.IsActive,
		IsVerified:  user.IsVerified,
		IsPublic:    user.IsPublic,
		LastLoginAt: user.LastLoginAt,
		CreatedAt:   user.CreatedAt,
		UpdatedAt:   user.UpdatedAt,
	}

	// 2. Récupérer les paramètres utilisateur
	var settings models.UserSettings
	if err := s.db.WithContext(ctx).First(&settings, "user_id = ?", userID).Error; err == nil {
		export.Settings = &UserSettingsExport{
			EmailNotifications:   settings.EmailNotifications,
			PushNotifications:    settings.PushNotifications,
			BrowserNotifications: settings.BrowserNotifications,
			EmailOnFollow:        settings.EmailOnFollow,
			EmailOnLike:          settings.EmailOnLike,
			EmailOnComment:       settings.EmailOnComment,
			EmailOnMessage:       settings.EmailOnMessage,
			EmailOnMention:       settings.EmailOnMention,
			EmailMarketing:       settings.EmailMarketing,
			AllowSearchIndexing:  settings.AllowSearchIndexing,
			ShowActivity:         settings.ShowActivity,
			ExplicitContent:      settings.ExplicitContent,
			Autoplay:             settings.Autoplay,
		}
	}

	// 3. Récupérer les tracks de l'utilisateur
	var tracks []models.Track
	if err := s.db.WithContext(ctx).Where("creator_id = ?", userID).Find(&tracks).Error; err == nil {
		export.Tracks = make([]TrackExport, len(tracks))
		for i, track := range tracks {
			export.Tracks[i] = TrackExport{
				ID:           track.ID,
				Title:        track.Title,
				Artist:       track.Artist,
				Album:        track.Album,
				Duration:     track.Duration,
				Genre:        track.Genre,
				Year:         track.Year,
				FilePath:     track.FilePath,
				CoverArtPath: track.CoverArtPath,
				IsPublic:     track.IsPublic,
				Status:       string(track.Status),
				PlayCount:    track.PlayCount,
				LikeCount:    track.LikeCount,
				CreatedAt:    track.CreatedAt,
				UpdatedAt:    track.UpdatedAt,
			}
		}
	}

	// 4. Récupérer les playlists de l'utilisateur
	var playlists []models.Playlist
	if err := s.db.WithContext(ctx).Where("user_id = ?", userID).Find(&playlists).Error; err == nil {
		export.Playlists = make([]PlaylistExport, len(playlists))
		for i, playlist := range playlists {
			export.Playlists[i] = PlaylistExport{
				ID:            playlist.ID,
				Title:         playlist.Title,
				Description:   playlist.Description,
				IsPublic:      playlist.IsPublic,
				TrackCount:    playlist.TrackCount,
				FollowerCount: playlist.FollowerCount,
				CreatedAt:     playlist.CreatedAt,
				UpdatedAt:     playlist.UpdatedAt,
			}
		}
	}

	// 5. Récupérer les commentaires de l'utilisateur
	var comments []models.TrackComment
	if err := s.db.WithContext(ctx).Where("user_id = ?", userID).Find(&comments).Error; err == nil {
		export.Comments = make([]CommentExport, len(comments))
		for i, comment := range comments {
			export.Comments[i] = CommentExport{
				ID:        comment.ID,
				TrackID:   comment.TrackID,
				Content:   comment.Content,
				CreatedAt: comment.CreatedAt,
				UpdatedAt: comment.UpdatedAt,
			}
		}
	}

	// 6. Récupérer les likes de l'utilisateur
	var likes []models.TrackLike
	if err := s.db.WithContext(ctx).Where("user_id = ?", userID).Find(&likes).Error; err == nil {
		export.Likes = make([]LikeExport, len(likes))
		for i, like := range likes {
			export.Likes[i] = LikeExport{
				ID:        like.ID,
				TrackID:   like.TrackID,
				CreatedAt: like.CreatedAt,
			}
		}
	}

	// 7. Récupérer les analytics de l'utilisateur
	var analytics []models.PlaybackAnalytics
	if err := s.db.WithContext(ctx).Where("user_id = ?", userID).Find(&analytics).Error; err == nil {
		export.Analytics = make([]AnalyticsExport, len(analytics))
		for i, a := range analytics {
			export.Analytics[i] = AnalyticsExport{
				ID:             a.ID,
				TrackID:        a.TrackID,
				PlayTime:       a.PlayTime,
				PauseCount:     a.PauseCount,
				SeekCount:      a.SeekCount,
				CompletionRate: a.CompletionRate,
				StartedAt:      a.StartedAt,
				EndedAt:        a.EndedAt,
				CreatedAt:      a.CreatedAt,
			}
		}
	}

	// 8. Récupérer les identités fédérées
	var federatedIDs []models.FederatedIdentity
	if err := s.db.WithContext(ctx).Where("user_id = ?", userID).Find(&federatedIDs).Error; err == nil {
		export.FederatedIDs = make([]FederatedIDExport, len(federatedIDs))
		for i, fid := range federatedIDs {
			export.FederatedIDs[i] = FederatedIDExport{
				ID:          fid.ID,
				Provider:    fid.Provider,
				ProviderID:  fid.ProviderID,
				Email:       fid.Email,
				DisplayName: fid.DisplayName,
				CreatedAt:   fid.CreatedAt,
			}
		}
	}

	// 9. Récupérer les rôles de l'utilisateur
	var userRoles []models.UserRole
	if err := s.db.WithContext(ctx).Where("user_id = ?", userID).Find(&userRoles).Error; err == nil {
		export.Roles = make([]RoleExport, len(userRoles))
		for i, ur := range userRoles {
			export.Roles[i] = RoleExport{
				ID:         ur.ID,
				RoleName:   ur.RoleName,
				AssignedAt: ur.AssignedAt,
				ExpiresAt:  ur.ExpiresAt,
				IsActive:   ur.IsActive,
			}
		}
	}

	s.logger.Info("User data exported",
		zap.String("user_id", userID.String()),
		zap.Int("tracks", len(export.Tracks)),
		zap.Int("playlists", len(export.Playlists)),
		zap.Int("comments", len(export.Comments)),
		zap.Int("likes", len(export.Likes)),
		zap.Int("analytics", len(export.Analytics)),
	)

	return export, nil
}

// ExportUserDataAsJSON exporte les données utilisateur au format JSON
func (s *DataExportService) ExportUserDataAsJSON(ctx context.Context, userID uuid.UUID) ([]byte, error) {
	export, err := s.ExportUserData(ctx, userID)
	if err != nil {
		return nil, err
	}

	jsonData, err := json.MarshalIndent(export, "", "  ")
	if err != nil {
		return nil, fmt.Errorf("failed to marshal export data: %w", err)
	}

	return jsonData, nil
}
