package services

import (
	"context"
	"database/sql"
	"fmt"

	"github.com/google/uuid"

	"veza-backend-api/internal/database"

	"go.uber.org/zap"
)

// SocialService handles social features (follows, likes, comments)
type SocialService struct {
	db     *database.Database
	logger *zap.Logger
}

// Comment represents a comment on a track
type Comment struct {
	ID        uuid.UUID  `json:"id" db:"id"`
	UserID    uuid.UUID  `json:"user_id" db:"user_id"`
	TrackID   uuid.UUID  `json:"track_id" db:"track_id"`
	ParentID  *uuid.UUID `json:"parent_id" db:"parent_id"`
	Content   string     `json:"content" db:"content"`
	CreatedAt string     `json:"created_at" db:"created_at"`
	UpdatedAt string     `json:"updated_at" db:"updated_at"`
}

// NewSocialService creates a new social service
func NewSocialService(db *database.Database, logger *zap.Logger) *SocialService {
	return &SocialService{
		db:     db,
		logger: logger,
	}
}

// FollowUser creates a follow relationship
func (ss *SocialService) FollowUser(followerID, followedID uuid.UUID) error {
	ctx := context.Background()

	_, err := ss.db.ExecContext(ctx, `
		INSERT INTO follows (follower_id, followed_id)
		VALUES ($1, $2)
		ON CONFLICT (follower_id, followed_id) DO NOTHING
	`, followerID, followedID)

	if err != nil {
		return fmt.Errorf("failed to follow user: %w", err)
	}

	ss.logger.Info("User followed",
		zap.String("follower_id", followerID.String()),
		zap.String("followed_id", followedID.String()),
	)

	return nil
}

// UnfollowUser removes a follow relationship
func (ss *SocialService) UnfollowUser(followerID, followedID uuid.UUID) error {
	ctx := context.Background()

	_, err := ss.db.ExecContext(ctx, `
		DELETE FROM follows
		WHERE follower_id = $1 AND followed_id = $2
	`, followerID, followedID)

	if err != nil {
		return fmt.Errorf("failed to unfollow user: %w", err)
	}

	return nil
}

// LikeTrack creates a like on a track
func (ss *SocialService) LikeTrack(userID, trackID uuid.UUID) error {
	ctx := context.Background()

	_, err := ss.db.ExecContext(ctx, `
		INSERT INTO likes (user_id, track_id)
		VALUES ($1, $2)
		ON CONFLICT (user_id, track_id) DO NOTHING
	`, userID, trackID)

	if err != nil {
		return fmt.Errorf("failed to like track: %w", err)
	}

	return nil
}

// UnlikeTrack removes a like from a track
func (ss *SocialService) UnlikeTrack(userID, trackID uuid.UUID) error {
	ctx := context.Background()

	_, err := ss.db.ExecContext(ctx, `
		DELETE FROM likes
		WHERE user_id = $1 AND track_id = $2
	`, userID, trackID)

	if err != nil {
		return fmt.Errorf("failed to unlike track: %w", err)
	}

	return nil
}

// CreateComment creates a comment on a track
func (ss *SocialService) CreateComment(userID, trackID uuid.UUID, content string, parentID *uuid.UUID) (*Comment, error) {
	ctx := context.Background()

	var commentID uuid.UUID
	err := ss.db.QueryRowContext(ctx, `
		INSERT INTO comments (id, user_id, track_id, parent_id, content)
		VALUES (gen_random_uuid(), $1, $2, $3, $4)
		RETURNING id
	`, userID, trackID, parentID, content).Scan(&commentID)

	if err != nil {
		return nil, fmt.Errorf("failed to create comment: %w", err)
	}

	// Fetch and return the created comment
	var comment Comment
	err = ss.db.QueryRowContext(ctx, `
		SELECT id, user_id, track_id, parent_id, content, created_at, updated_at
		FROM comments
		WHERE id = $1
	`, commentID).Scan(
		&comment.ID,
		&comment.UserID,
		&comment.TrackID,
		&comment.ParentID,
		&comment.Content,
		&comment.CreatedAt,
		&comment.UpdatedAt,
	)

	if err != nil {
		return nil, fmt.Errorf("failed to fetch comment: %w", err)
	}

	return &comment, nil
}

// GetFollowersCount returns the number of followers for a user
func (ss *SocialService) GetFollowersCount(userID uuid.UUID) (int, error) {
	ctx := context.Background()

	var count int
	err := ss.db.QueryRowContext(ctx, `
		SELECT COUNT(*)
		FROM follows
		WHERE followed_id = $1
	`, userID).Scan(&count)

	if err != nil {
		return 0, fmt.Errorf("failed to get followers count: %w", err)
	}

	return count, nil
}

// GetFollowingCount returns the number of users being followed
func (ss *SocialService) GetFollowingCount(userID uuid.UUID) (int, error) {
	ctx := context.Background()

	var count int
	err := ss.db.QueryRowContext(ctx, `
		SELECT COUNT(*)
		FROM follows
		WHERE follower_id = $1
	`, userID).Scan(&count)

	if err != nil {
		return 0, fmt.Errorf("failed to get following count: %w", err)
	}

	return count, nil
}

// GetLikesCount returns the number of likes for a track
func (ss *SocialService) GetLikesCount(trackID uuid.UUID) (int, error) {
	ctx := context.Background()

	var count int
	err := ss.db.QueryRowContext(ctx, `
		SELECT COUNT(*)
		FROM likes
		WHERE track_id = $1
	`, trackID).Scan(&count)

	if err != nil {
		return 0, fmt.Errorf("failed to get likes count: %w", err)
	}

	return count, nil
}

// IsFollowing checks if a user is following another user
func (ss *SocialService) IsFollowing(followerID, followedID uuid.UUID) (bool, error) {
	ctx := context.Background()

	var exists bool
	err := ss.db.QueryRowContext(ctx, `
		SELECT EXISTS(
			SELECT 1 FROM follows
			WHERE follower_id = $1 AND followed_id = $2
		)
	`, followerID, followedID).Scan(&exists)

	if err != nil {
		if err == sql.ErrNoRows {
			return false, nil
		}
		return false, fmt.Errorf("failed to check follow status: %w", err)
	}

	return exists, nil
}

// IsTrackLiked checks if a user has liked a track
func (ss *SocialService) IsTrackLiked(userID, trackID uuid.UUID) (bool, error) {
	ctx := context.Background()

	var exists bool
	err := ss.db.QueryRowContext(ctx, `
		SELECT EXISTS(
			SELECT 1 FROM likes
			WHERE user_id = $1 AND track_id = $2
		)
	`, userID, trackID).Scan(&exists)

	if err != nil {
		if err == sql.ErrNoRows {
			return false, nil
		}
		return false, fmt.Errorf("failed to check like status: %w", err)
	}

	return exists, nil
}

// BlockUser creates a block relationship between users
// BE-API-018: Implement user block/unblock endpoints
func (ss *SocialService) BlockUser(blockerID, blockedID uuid.UUID) error {
	ctx := context.Background()

	// Vérifier qu'on ne peut pas se bloquer soi-même
	if blockerID == blockedID {
		return fmt.Errorf("cannot block yourself")
	}

	_, err := ss.db.ExecContext(ctx, `
		INSERT INTO user_blocks (blocker_id, blocked_id)
		VALUES ($1, $2)
		ON CONFLICT (blocker_id, blocked_id) DO NOTHING
	`, blockerID, blockedID)

	if err != nil {
		return fmt.Errorf("failed to block user: %w", err)
	}

	ss.logger.Info("User blocked",
		zap.String("blocker_id", blockerID.String()),
		zap.String("blocked_id", blockedID.String()),
	)

	return nil
}

// UnblockUser removes a block relationship between users
// BE-API-018: Implement user block/unblock endpoints
func (ss *SocialService) UnblockUser(blockerID, blockedID uuid.UUID) error {
	ctx := context.Background()

	_, err := ss.db.ExecContext(ctx, `
		DELETE FROM user_blocks
		WHERE blocker_id = $1 AND blocked_id = $2
	`, blockerID, blockedID)

	if err != nil {
		return fmt.Errorf("failed to unblock user: %w", err)
	}

	ss.logger.Info("User unblocked",
		zap.String("blocker_id", blockerID.String()),
		zap.String("blocked_id", blockedID.String()),
	)

	return nil
}

// IsBlocked checks if a user is blocked by another user
// BE-API-018: Helper method to check block status
func (ss *SocialService) IsBlocked(blockerID, blockedID uuid.UUID) (bool, error) {
	ctx := context.Background()

	var exists bool
	err := ss.db.QueryRowContext(ctx, `
		SELECT EXISTS(
			SELECT 1 FROM user_blocks
			WHERE blocker_id = $1 AND blocked_id = $2
		)
	`, blockerID, blockedID).Scan(&exists)

	if err != nil {
		if err == sql.ErrNoRows {
			return false, nil
		}
		return false, fmt.Errorf("failed to check block status: %w", err)
	}

	return exists, nil
}
