package handlers

import (
	"bytes"
	"encoding/csv"
	"encoding/json"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"veza-backend-api/internal/models"
	"veza-backend-api/internal/services"
)

// PlaylistExportHandler gère les exports de playlists
// T0493: Create Playlist Export Feature
type PlaylistExportHandler struct {
	playlistService *services.PlaylistService
}

// NewPlaylistExportHandler crée un nouveau handler d'export de playlists
func NewPlaylistExportHandler(playlistService *services.PlaylistService) *PlaylistExportHandler {
	return &PlaylistExportHandler{
		playlistService: playlistService,
	}
}

// ExportPlaylistJSON exporte une playlist au format JSON
// T0493: Create Playlist Export Feature
func (h *PlaylistExportHandler) ExportPlaylistJSON(c *gin.Context) {
	playlistID, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid playlist id"})
		return
	}

	// Vérifier que la playlist existe et que l'utilisateur a accès
	var userID *int64
	if uid := c.GetInt64("user_id"); uid > 0 {
		userID = &uid
	}

	playlist, err := h.playlistService.GetPlaylist(c.Request.Context(), playlistID, userID)
	if err != nil {
		if err.Error() == "playlist not found" {
			c.JSON(http.StatusNotFound, gin.H{"error": "playlist not found"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Vérifier que l'utilisateur a accès (propriétaire, collaborateur ou playlist publique)
	if playlist.UserID != c.GetInt64("user_id") && !playlist.IsPublic {
		// Vérifier si l'utilisateur est collaborateur
		if userID != nil {
			hasAccess, err := h.playlistService.CheckPermission(c.Request.Context(), playlistID, *userID, models.PlaylistPermissionRead)
			if err != nil || !hasAccess {
				c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
				return
			}
		} else {
			c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
			return
		}
	}

	// Préparer les données d'export
	exportData := map[string]interface{}{
		"playlist": map[string]interface{}{
			"id":          playlist.ID,
			"title":       playlist.Title,
			"description": playlist.Description,
			"is_public":   playlist.IsPublic,
			"cover_url":   playlist.CoverURL,
			"track_count": playlist.TrackCount,
			"created_at":  playlist.CreatedAt,
			"updated_at":  playlist.UpdatedAt,
		},
		"tracks": make([]map[string]interface{}, 0),
		"exported_at": time.Now().Format(time.RFC3339),
	}

	// Ajouter les tracks avec leurs informations
	if playlist.Tracks != nil {
		for _, playlistTrack := range playlist.Tracks {
			// Track est un struct (non-pointer), toujours valide
			{
				trackData := map[string]interface{}{
					"position":   playlistTrack.Position,
					"id":         playlistTrack.Track.ID,
					"title":      playlistTrack.Track.Title,
					"artist":     playlistTrack.Track.Artist,
					"album":      playlistTrack.Track.Album,
					"duration":   playlistTrack.Track.Duration,
					"genre":      playlistTrack.Track.Genre,
					"year":       playlistTrack.Track.Year,
					"added_at":   playlistTrack.AddedAt,
				}
				exportData["tracks"] = append(exportData["tracks"].([]map[string]interface{}), trackData)
			}
		}
	}

	// Convertir en JSON
	jsonData, err := json.MarshalIndent(exportData, "", "  ")
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate JSON export"})
		return
	}

	// Définir les headers pour le téléchargement
	filename := "playlist_" + strconv.FormatInt(playlistID, 10) + "_" + time.Now().Format("20060102") + ".json"
	c.Header("Content-Type", "application/json")
	c.Header("Content-Disposition", "attachment; filename="+filename)
	c.Data(http.StatusOK, "application/json", jsonData)
}

// ExportPlaylistCSV exporte une playlist au format CSV
// T0493: Create Playlist Export Feature
func (h *PlaylistExportHandler) ExportPlaylistCSV(c *gin.Context) {
	playlistID, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid playlist id"})
		return
	}

	// Vérifier que la playlist existe et que l'utilisateur a accès
	var userID *int64
	if uid := c.GetInt64("user_id"); uid > 0 {
		userID = &uid
	}

	playlist, err := h.playlistService.GetPlaylist(c.Request.Context(), playlistID, userID)
	if err != nil {
		if err.Error() == "playlist not found" {
			c.JSON(http.StatusNotFound, gin.H{"error": "playlist not found"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Vérifier que l'utilisateur a accès (propriétaire, collaborateur ou playlist publique)
	if playlist.UserID != c.GetInt64("user_id") && !playlist.IsPublic {
		// Vérifier si l'utilisateur est collaborateur
		if userID != nil {
			hasAccess, err := h.playlistService.CheckPermission(c.Request.Context(), playlistID, *userID, models.PlaylistPermissionRead)
			if err != nil || !hasAccess {
				c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
				return
			}
		} else {
			c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
			return
		}
	}

	// Créer le buffer CSV
	var csvData [][]string

	// En-têtes
	csvData = append(csvData, []string{
		"Position",
		"Track ID",
		"Title",
		"Artist",
		"Album",
		"Duration (seconds)",
		"Genre",
		"Year",
		"Added At",
	})

	// Ajouter les tracks
	if playlist.Tracks != nil {
		for _, playlistTrack := range playlist.Tracks {
			// Track est un struct (non-pointer), toujours valide
			{
				row := []string{
					strconv.Itoa(playlistTrack.Position),
					strconv.FormatInt(playlistTrack.Track.ID, 10),
					playlistTrack.Track.Title,
					playlistTrack.Track.Artist,
					playlistTrack.Track.Album,
					strconv.Itoa(playlistTrack.Track.Duration),
					playlistTrack.Track.Genre,
					strconv.Itoa(playlistTrack.Track.Year),
					playlistTrack.AddedAt.Format(time.RFC3339),
				}
				csvData = append(csvData, row)
			}
		}
	}

	// Générer le CSV
	var csvBuffer bytes.Buffer
	writer := csv.NewWriter(&csvBuffer)
	
	// Écrire toutes les lignes
	for _, row := range csvData {
		if err := writer.Write(row); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate CSV export"})
			return
		}
	}
	writer.Flush()

	if err := writer.Error(); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate CSV export"})
		return
	}

	// Définir les headers pour le téléchargement
	filename := "playlist_" + strconv.FormatInt(playlistID, 10) + "_" + time.Now().Format("20060102") + ".csv"
	c.Header("Content-Type", "text/csv")
	c.Header("Content-Disposition", "attachment; filename="+filename)
	c.Data(http.StatusOK, "text/csv", csvBuffer.Bytes())
}

