package handlers

import (
	"net/http"
	"strconv"

	"veza-backend-api/internal/models"
	"veza-backend-api/internal/services"

	"github.com/gin-gonic/gin"
)

// GetPlaylists handles getting user's playlists
func GetPlaylists(playlistService *services.PlaylistService) gin.HandlerFunc {
	return func(c *gin.Context) {
		userID, exists := c.Get("user_id")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
			return
		}

		uid := userID.(int64)
		// Utiliser GetPlaylists avec filterUserID pour obtenir les playlists de l'utilisateur
		playlists, _, err := playlistService.GetPlaylists(c.Request.Context(), &uid, &uid, 1, 100)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}

		c.JSON(http.StatusOK, gin.H{"playlists": playlists})
	}
}

// CreatePlaylist handles playlist creation
func CreatePlaylist(playlistService *services.PlaylistService) gin.HandlerFunc {
	return func(c *gin.Context) {
		userID, exists := c.Get("user_id")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
			return
		}

		type CreatePlaylistRequest struct {
			Title       string `json:"title" binding:"required,min=1,max=255"`
			Description string `json:"description"`
			IsPublic    bool   `json:"is_public"`
		}

		var req CreatePlaylistRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		uid := userID.(int64)
		playlist, err := playlistService.CreatePlaylist(c.Request.Context(), uid, req.Title, req.Description, req.IsPublic)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}

		c.JSON(http.StatusCreated, gin.H{"playlist": playlist})
	}
}

// GetPlaylist handles getting a single playlist
func GetPlaylist(playlistService *services.PlaylistService) gin.HandlerFunc {
	return func(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
		}

		// Obtenir userID si disponible
		var userIDPtr *int64
		if userID, exists := c.Get("user_id"); exists {
			uid := userID.(int64)
			userIDPtr = &uid
		}

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

		c.JSON(http.StatusOK, playlist)
	}
}

// AddTrackToPlaylistRequest représente la requête pour ajouter un track à une playlist
type AddTrackToPlaylistRequest struct {
	TrackID  int64 `json:"track_id" binding:"required"`
	Position int   `json:"position,omitempty"`
}

// AddTrackToPlaylist handles adding a track to a playlist
// T0467: POST /api/v1/playlists/:id/tracks
func AddTrackToPlaylist(playlistService *services.PlaylistService) gin.HandlerFunc {
	return func(c *gin.Context) {
		userID, exists := c.Get("user_id")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
			return
		}

		playlistID, err := strconv.ParseInt(c.Param("id"), 10, 64)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid playlist id"})
			return
		}

		var req AddTrackToPlaylistRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		userIDInt64 := int64(userID.(int))
		err = playlistService.AddTrackToPlaylist(c.Request.Context(), playlistID, req.TrackID, userIDInt64, req.Position)
		if err != nil {
			if err.Error() == "playlist not found" {
				c.JSON(http.StatusNotFound, gin.H{"error": "playlist not found"})
				return
			}
			if err.Error() == "track not found" {
				c.JSON(http.StatusNotFound, gin.H{"error": "track not found"})
				return
			}
			if err.Error() == "track already in playlist" {
				c.JSON(http.StatusBadRequest, gin.H{"error": "track already in playlist"})
				return
			}
			if err.Error() == "forbidden" {
				c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
				return
			}
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}

		c.JSON(http.StatusOK, gin.H{"message": "track added to playlist"})
	}
}

// RemoveTrackFromPlaylist handles removing a track from a playlist
// T0467: DELETE /api/v1/playlists/:id/tracks/:trackId
func RemoveTrackFromPlaylist(playlistService *services.PlaylistService) gin.HandlerFunc {
	return func(c *gin.Context) {
		userID, exists := c.Get("user_id")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
			return
		}

		playlistID, err := strconv.ParseInt(c.Param("id"), 10, 64)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid playlist id"})
			return
		}

		trackID, err := strconv.ParseInt(c.Param("track_id"), 10, 64)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid track id"})
			return
		}

		userIDInt64 := int64(userID.(int))
		err = playlistService.RemoveTrackFromPlaylist(c.Request.Context(), playlistID, trackID, userIDInt64)
		if err != nil {
			if err.Error() == "playlist not found" {
				c.JSON(http.StatusNotFound, gin.H{"error": "playlist not found"})
				return
			}
			if err.Error() == "track not found in playlist" {
				c.JSON(http.StatusNotFound, gin.H{"error": "track not found in playlist"})
				return
			}
			if err.Error() == "forbidden" {
				c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
				return
			}
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}

		c.JSON(http.StatusOK, gin.H{"message": "track removed from playlist"})
	}
}

// UpdatePlaylist handles updating a playlist
func UpdatePlaylist(playlistService *services.PlaylistService) gin.HandlerFunc {
	return func(c *gin.Context) {
		userID, exists := c.Get("user_id")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
			return
		}

		playlistID, err := strconv.ParseInt(c.Param("id"), 10, 64)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid playlist ID"})
			return
		}

		var req models.CreatePlaylistRequest // Reuse CreatePlaylistRequest for update fields
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		uid := userID.(int64)
		
		updatedPlaylist, err := playlistService.UpdatePlaylist(
			c.Request.Context(), 
			playlistID, 
			uid, 
			&req.Name, // Pass pointer so nil means "not provided"
			&req.Description, 
			&req.IsPublic,
		)
		if err != nil {
			if err.Error() == "playlist not found" {
				c.JSON(http.StatusNotFound, gin.H{"error": "Playlist not found"})
				return
			}
			if err.Error() == "forbidden" {
				c.JSON(http.StatusForbidden, gin.H{"error": "Forbidden"})
				return
			}
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}

		c.JSON(http.StatusOK, updatedPlaylist)
	}
}

// DeletePlaylist handles deleting a playlist
func DeletePlaylist(playlistService *services.PlaylistService) gin.HandlerFunc {
	return func(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
		}

		userID, exists := c.Get("user_id")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
			return
		}

		uid := userID.(int64)
		err = playlistService.DeletePlaylist(c.Request.Context(), playlistID, uid)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}

		c.JSON(http.StatusOK, gin.H{"message": "Playlist deleted"})
	}
}

// ReorderPlaylistTracksRequest représente la requête pour réorganiser les tracks
type ReorderPlaylistTracksRequest struct {
	TrackPositions map[int64]int `json:"track_positions" binding:"required"`
}

// ReorderPlaylistTracks handles reordering tracks in a playlist
// T0467: PUT /api/v1/playlists/:id/tracks/reorder
func ReorderPlaylistTracks(playlistService *services.PlaylistService) gin.HandlerFunc {
	return func(c *gin.Context) {
		userID, exists := c.Get("user_id")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
			return
		}

		playlistID, err := strconv.ParseInt(c.Param("id"), 10, 64)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid playlist id"})
			return
		}

		var req ReorderPlaylistTracksRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		userIDInt64 := int64(userID.(int))
		err = playlistService.ReorderPlaylistTracks(c.Request.Context(), playlistID, userIDInt64, req.TrackPositions)
		if err != nil {
			if err.Error() == "playlist not found" {
				c.JSON(http.StatusNotFound, gin.H{"error": "playlist not found"})
				return
			}
			if err.Error() == "forbidden" {
				c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
				return
			}
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}

		c.JSON(http.StatusOK, gin.H{"message": "tracks reordered"})
	}
}
