<?php
/*******************************************************************************************************************
| Software Name        : EasyStream
| Software Description : High End YouTube Clone Script with Videos, Shorts, Streams, Images, Audio, Documents, Blogs
| Software Author      : (c) Sami Ahmed
|*******************************************************************************************************************
|
|*******************************************************************************************************************
| This source file is subject to the EasyStream Proprietary License Agreement.
| 
| By using this software, you acknowledge having read this Agreement and agree to be bound thereby.
|*******************************************************************************************************************
| Copyright (c) 2025 Sami Ahmed. All rights reserved.
|*******************************************************************************************************************/

defined('_ISVALID') or header('Location: /error');

/**
 * Social Features and User Interactions System
 */
class VSocial
{
    private $logger;
    private $db;
    private static $instance = null;
    
    public function __construct()
    {
        $this->logger = VLogger::getInstance();
        $this->db = VDatabase::getInstance();
    }
    
    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    /**
     * Handle like/dislike action on content
     * @param string $contentType Content type (video, comment, etc.)
     * @param string $contentId Content ID
     * @param string $userId User ID
     * @param string $action Action (like, dislike, remove)
     * @return array Result
     */
    public function handleVote($contentType, $contentId, $userId, $action)
    {
        try {
            if (!$userId) {
                return [
                    'success' => false,
                    'error' => 'User must be logged in to vote'
                ];
            }
            
            // Validate content exists
            if (!$this->validateContent($contentType, $contentId)) {
                return [
                    'success' => false,
                    'error' => 'Content not found'
                ];
            }
            
            // Check existing vote
            $existingVote = $this->getExistingVote($contentType, $contentId, $userId);
            
            // Handle vote logic
            $result = $this->processVote($contentType, $contentId, $userId, $action, $existingVote);
            
            // Update content vote counts
            $this->updateVoteCounts($contentType, $contentId);
            
            // Log the action
            $this->logVoteAction($contentType, $contentId, $userId, $action, $result);
            
            return [
                'success' => true,
                'action' => $result['action'],
                'vote_counts' => $this->getVoteCounts($contentType, $contentId),
                'user_vote' => $result['user_vote']
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Vote handling failed', [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'user_id' => $userId,
                'action' => $action,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => 'Failed to process vote'
            ];
        }
    }
    
    /**
     * Add comment to content
     * @param string $contentType Content type
     * @param string $contentId Content ID
     * @param string $userId User ID
     * @param string $comment Comment text
     * @param string $parentId Parent comment ID (for replies)
     * @return array Result
     */
    public function addComment($contentType, $contentId, $userId, $comment, $parentId = null)
    {
        try {
            if (!$userId) {
                return [
                    'success' => false,
                    'error' => 'User must be logged in to comment'
                ];
            }
            
            // Validate and sanitize comment
            $comment = trim($comment);
            if (empty($comment)) {
                return [
                    'success' => false,
                    'error' => 'Comment cannot be empty'
                ];
            }
            
            if (strlen($comment) > 2000) {
                return [
                    'success' => false,
                    'error' => 'Comment too long (max 2000 characters)'
                ];
            }
            
            // Validate content exists
            if (!$this->validateContent($contentType, $contentId)) {
                return [
                    'success' => false,
                    'error' => 'Content not found'
                ];
            }
            
            // Check rate limiting
            if (!$this->checkCommentRateLimit($userId)) {
                return [
                    'success' => false,
                    'error' => 'Too many comments. Please wait before commenting again.'
                ];
            }
            
            // Validate parent comment if replying
            if ($parentId && !$this->validateParentComment($parentId, $contentType, $contentId)) {
                return [
                    'success' => false,
                    'error' => 'Parent comment not found'
                ];
            }
            
            // Filter comment content
            $filteredComment = $this->filterCommentContent($comment);
            
            // Create comment
            $commentData = [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'user_id' => $userId,
                'parent_id' => $parentId,
                'comment_text' => $filteredComment,
                'comment_status' => 'approved', // Could be 'pending' for moderation
                'created_at' => date('Y-m-d H:i:s'),
                'updated_at' => date('Y-m-d H:i:s'),
                'likes_count' => 0,
                'dislikes_count' => 0,
                'replies_count' => 0
            ];
            
            $commentId = $this->db->doInsert('db_comments', $commentData);
            
            if (!$commentId) {
                throw new Exception('Failed to create comment');
            }
            
            // Update parent comment reply count
            if ($parentId) {
                $this->db->doQuery(
                    "UPDATE db_comments SET replies_count = replies_count + 1 WHERE id = ?",
                    [$parentId]
                );
            }
            
            // Update content comment count
            $this->updateCommentCount($contentType, $contentId);
            
            // Get comment with user info
            $commentWithUser = $this->getCommentWithUser($commentId);
            
            // Send notifications
            $this->sendCommentNotifications($contentType, $contentId, $userId, $parentId);
            
            $this->logger->info('Comment added successfully', [
                'comment_id' => $commentId,
                'content_type' => $contentType,
                'content_id' => $contentId,
                'user_id' => $userId
            ]);
            
            return [
                'success' => true,
                'comment_id' => $commentId,
                'comment' => $commentWithUser
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Comment creation failed', [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'user_id' => $userId,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => 'Failed to add comment'
            ];
        }
    }
    
    /**
     * Get comments for content
     * @param string $contentType Content type
     * @param string $contentId Content ID
     * @param int $page Page number
     * @param int $limit Comments per page
     * @param string $sort Sort order (newest, oldest, popular)
     * @return array Comments data
     */
    public function getComments($contentType, $contentId, $page = 1, $limit = 20, $sort = 'newest')
    {
        try {
            $offset = ($page - 1) * $limit;
            
            // Build sort clause
            $sortClause = $this->buildCommentSortClause($sort);
            
            // Get top-level comments
            $query = "SELECT c.*, u.usr_user, u.usr_avatar, u.usr_verified
                      FROM db_comments c
                      JOIN db_accountuser u ON c.user_id = u.usr_id
                      WHERE c.content_type = ? AND c.content_id = ? 
                      AND c.parent_id IS NULL AND c.comment_status = 'approved'
                      ORDER BY {$sortClause}
                      LIMIT ? OFFSET ?";
            
            $result = $this->db->doQuery($query, [$contentType, $contentId, $limit, $offset]);
            
            $comments = [];
            while ($row = $this->db->doFetch($result)) {
                $comment = $this->formatComment($row);
                
                // Get replies if any
                if ($row['replies_count'] > 0) {
                    $comment['replies'] = $this->getCommentReplies($row['id'], 3); // Get first 3 replies
                    $comment['has_more_replies'] = $row['replies_count'] > 3;
                }
                
                $comments[] = $comment;
            }
            
            // Get total count
            $countQuery = "SELECT COUNT(*) as total FROM db_comments 
                          WHERE content_type = ? AND content_id = ? 
                          AND parent_id IS NULL AND comment_status = 'approved'";
            $countResult = $this->db->doQuery($countQuery, [$contentType, $contentId]);
            $totalCount = $this->db->doFetch($countResult)['total'];
            
            return [
                'success' => true,
                'comments' => $comments,
                'pagination' => [
                    'current_page' => $page,
                    'per_page' => $limit,
                    'total' => $totalCount,
                    'total_pages' => ceil($totalCount / $limit),
                    'has_more' => $page < ceil($totalCount / $limit)
                ]
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Failed to get comments', [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => 'Failed to load comments'
            ];
        }
    }
    
    /**
     * Get comment replies
     * @param string $parentId Parent comment ID
     * @param int $limit Number of replies to get
     * @return array Replies
     */
    public function getCommentReplies($parentId, $limit = 10)
    {
        try {
            $query = "SELECT c.*, u.usr_user, u.usr_avatar, u.usr_verified
                      FROM db_comments c
                      JOIN db_accountuser u ON c.user_id = u.usr_id
                      WHERE c.parent_id = ? AND c.comment_status = 'approved'
                      ORDER BY c.created_at ASC
                      LIMIT ?";
            
            $result = $this->db->doQuery($query, [$parentId, $limit]);
            
            $replies = [];
            while ($row = $this->db->doFetch($result)) {
                $replies[] = $this->formatComment($row);
            }
            
            return $replies;
            
        } catch (Exception $e) {
            $this->logger->error('Failed to get comment replies', [
                'parent_id' => $parentId,
                'error' => $e->getMessage()
            ]);
            
            return [];
        }
    }
    
    /**
     * Delete comment
     * @param string $commentId Comment ID
     * @param string $userId User ID
     * @return array Result
     */
    public function deleteComment($commentId, $userId)
    {
        try {
            // Get comment details
            $comment = $this->getComment($commentId);
            
            if (!$comment) {
                return [
                    'success' => false,
                    'error' => 'Comment not found'
                ];
            }
            
            // Check permissions (owner or admin)
            if ($comment['user_id'] != $userId && !$this->isAdmin($userId)) {
                return [
                    'success' => false,
                    'error' => 'Permission denied'
                ];
            }
            
            // Soft delete comment
            $this->db->doUpdate('db_comments', 'id', [
                'comment_status' => 'deleted',
                'updated_at' => date('Y-m-d H:i:s')
            ], $commentId);
            
            // Update parent reply count if this is a reply
            if ($comment['parent_id']) {
                $this->db->doQuery(
                    "UPDATE db_comments SET replies_count = replies_count - 1 WHERE id = ?",
                    [$comment['parent_id']]
                );
            }
            
            // Update content comment count
            $this->updateCommentCount($comment['content_type'], $comment['content_id']);
            
            $this->logger->info('Comment deleted', [
                'comment_id' => $commentId,
                'user_id' => $userId
            ]);
            
            return [
                'success' => true,
                'message' => 'Comment deleted successfully'
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Comment deletion failed', [
                'comment_id' => $commentId,
                'user_id' => $userId,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => 'Failed to delete comment'
            ];
        }
    }
    
    /**
     * Generate social sharing URLs
     * @param string $contentType Content type
     * @param string $contentId Content ID
     * @return array Sharing URLs
     */
    public function generateSharingUrls($contentType, $contentId)
    {
        try {
            // Get content details
            $content = $this->getContentDetails($contentType, $contentId);
            
            if (!$content) {
                return [
                    'success' => false,
                    'error' => 'Content not found'
                ];
            }
            
            $baseUrl = $this->getBaseUrl();
            $contentUrl = $baseUrl . $this->getContentUrl($contentType, $contentId);
            $title = urlencode($content['title']);
            $description = urlencode(substr($content['description'], 0, 200));
            
            $sharingUrls = [
                'facebook' => "https://www.facebook.com/sharer/sharer.php?u=" . urlencode($contentUrl),
                'twitter' => "https://twitter.com/intent/tweet?url=" . urlencode($contentUrl) . "&text=" . $title,
                'linkedin' => "https://www.linkedin.com/sharing/share-offsite/?url=" . urlencode($contentUrl),
                'reddit' => "https://reddit.com/submit?url=" . urlencode($contentUrl) . "&title=" . $title,
                'whatsapp' => "https://wa.me/?text=" . $title . "%20" . urlencode($contentUrl),
                'telegram' => "https://t.me/share/url?url=" . urlencode($contentUrl) . "&text=" . $title,
                'email' => "mailto:?subject=" . $title . "&body=" . $description . "%0A%0A" . urlencode($contentUrl),
                'copy_link' => $contentUrl
            ];
            
            return [
                'success' => true,
                'sharing_urls' => $sharingUrls,
                'content_url' => $contentUrl,
                'title' => $content['title']
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Failed to generate sharing URLs', [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => 'Failed to generate sharing URLs'
            ];
        }
    }
    
    /**
     * Track social sharing action
     * @param string $contentType Content type
     * @param string $contentId Content ID
     * @param string $platform Sharing platform
     * @param string $userId User ID (optional)
     */
    public function trackShare($contentType, $contentId, $platform, $userId = null)
    {
        try {
            $shareData = [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'platform' => $platform,
                'user_id' => $userId,
                'ip_address' => $this->getRealIpAddress(),
                'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
                'created_at' => date('Y-m-d H:i:s')
            ];
            
            $this->db->doInsert('db_social_shares', $shareData);
            
            // Update content share count
            $this->updateShareCount($contentType, $contentId);
            
            $this->logger->info('Social share tracked', [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'platform' => $platform,
                'user_id' => $userId
            ]);
            
        } catch (Exception $e) {
            $this->logger->error('Failed to track share', [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'platform' => $platform,
                'error' => $e->getMessage()
            ]);
        }
    }
    
    /**
     * Get social statistics for content
     * @param string $contentType Content type
     * @param string $contentId Content ID
     * @return array Social stats
     */
    public function getSocialStats($contentType, $contentId)
    {
        try {
            // Get vote counts
            $voteCounts = $this->getVoteCounts($contentType, $contentId);
            
            // Get comment count
            $commentCount = $this->getCommentCount($contentType, $contentId);
            
            // Get share count
            $shareCount = $this->getShareCount($contentType, $contentId);
            
            return [
                'success' => true,
                'stats' => [
                    'likes' => $voteCounts['likes'],
                    'dislikes' => $voteCounts['dislikes'],
                    'comments' => $commentCount,
                    'shares' => $shareCount,
                    'engagement_score' => $this->calculateEngagementScore($voteCounts, $commentCount, $shareCount)
                ]
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Failed to get social stats', [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => 'Failed to get social statistics'
            ];
        }
    }
    
    /**
     * Private helper methods
     */
    
    private function validateContent($contentType, $contentId)
    {
        $table = $this->getContentTable($contentType);
        $idField = $this->getContentIdField($contentType);
        
        $query = "SELECT 1 FROM {$table} WHERE {$idField} = ? AND file_active = 1 LIMIT 1";
        $result = $this->db->doQuery($query, [$contentId]);
        
        return $this->db->doFetch($result) !== false;
    }
    
    private function getExistingVote($contentType, $contentId, $userId)
    {
        $query = "SELECT vote_type FROM db_votes 
                  WHERE content_type = ? AND content_id = ? AND user_id = ?";
        $result = $this->db->doQuery($query, [$contentType, $contentId, $userId]);
        
        $vote = $this->db->doFetch($result);
        return $vote ? $vote['vote_type'] : null;
    }
    
    private function processVote($contentType, $contentId, $userId, $action, $existingVote)
    {
        if ($action === 'remove' || $action === $existingVote) {
            // Remove existing vote
            $this->db->doQuery(
                "DELETE FROM db_votes WHERE content_type = ? AND content_id = ? AND user_id = ?",
                [$contentType, $contentId, $userId]
            );
            
            return [
                'action' => 'removed',
                'user_vote' => null
            ];
        } else {
            // Add or update vote
            $voteData = [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'user_id' => $userId,
                'vote_type' => $action,
                'created_at' => date('Y-m-d H:i:s')
            ];
            
            if ($existingVote) {
                // Update existing vote
                $this->db->doQuery(
                    "UPDATE db_votes SET vote_type = ?, created_at = ? 
                     WHERE content_type = ? AND content_id = ? AND user_id = ?",
                    [$action, date('Y-m-d H:i:s'), $contentType, $contentId, $userId]
                );
            } else {
                // Insert new vote
                $this->db->doInsert('db_votes', $voteData);
            }
            
            return [
                'action' => $existingVote ? 'updated' : 'added',
                'user_vote' => $action
            ];
        }
    }
    
    private function updateVoteCounts($contentType, $contentId)
    {
        $table = $this->getContentTable($contentType);
        $idField = $this->getContentIdField($contentType);
        
        // Get current vote counts
        $query = "SELECT 
                    SUM(CASE WHEN vote_type = 'like' THEN 1 ELSE 0 END) as likes,
                    SUM(CASE WHEN vote_type = 'dislike' THEN 1 ELSE 0 END) as dislikes
                  FROM db_votes 
                  WHERE content_type = ? AND content_id = ?";
        
        $result = $this->db->doQuery($query, [$contentType, $contentId]);
        $counts = $this->db->doFetch($result);
        
        // Update content table
        $updateQuery = "UPDATE {$table} SET 
                        file_likes = ?, file_dislikes = ? 
                        WHERE {$idField} = ?";
        
        $this->db->doQuery($updateQuery, [
            $counts['likes'] ?? 0,
            $counts['dislikes'] ?? 0,
            $contentId
        ]);
    }
    
    private function getVoteCounts($contentType, $contentId)
    {
        $query = "SELECT 
                    SUM(CASE WHEN vote_type = 'like' THEN 1 ELSE 0 END) as likes,
                    SUM(CASE WHEN vote_type = 'dislike' THEN 1 ELSE 0 END) as dislikes
                  FROM db_votes 
                  WHERE content_type = ? AND content_id = ?";
        
        $result = $this->db->doQuery($query, [$contentType, $contentId]);
        $counts = $this->db->doFetch($result);
        
        return [
            'likes' => (int)($counts['likes'] ?? 0),
            'dislikes' => (int)($counts['dislikes'] ?? 0)
        ];
    }
    
    private function checkCommentRateLimit($userId)
    {
        // Check if user has posted more than 10 comments in the last hour
        $query = "SELECT COUNT(*) as count FROM db_comments 
                  WHERE user_id = ? AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)";
        $result = $this->db->doQuery($query, [$userId]);
        $count = $this->db->doFetch($result)['count'];
        
        return $count < 10;
    }
    
    private function filterCommentContent($comment)
    {
        // Basic content filtering
        $comment = strip_tags($comment);
        $comment = htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');
        
        // Remove excessive whitespace
        $comment = preg_replace('/\s+/', ' ', $comment);
        
        return trim($comment);
    }
    
    private function formatComment($row)
    {
        return [
            'id' => $row['id'],
            'content_type' => $row['content_type'],
            'content_id' => $row['content_id'],
            'parent_id' => $row['parent_id'],
            'comment_text' => $row['comment_text'],
            'created_at' => $row['created_at'],
            'likes_count' => (int)$row['likes_count'],
            'dislikes_count' => (int)$row['dislikes_count'],
            'replies_count' => (int)$row['replies_count'],
            'user' => [
                'id' => $row['user_id'],
                'username' => $row['usr_user'],
                'avatar' => $row['usr_avatar'],
                'verified' => (bool)$row['usr_verified']
            ],
            'replies' => []
        ];
    }
    
    private function getContentTable($contentType)
    {
        $tables = [
            'video' => 'db_videofiles',
            'image' => 'db_imagefiles',
            'audio' => 'db_audiofiles',
            'document' => 'db_documentfiles'
        ];
        
        return $tables[$contentType] ?? 'db_videofiles';
    }
    
    private function getContentIdField($contentType)
    {
        return 'file_key';
    }
    
    private function getBaseUrl()
    {
        $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
        $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
        return $protocol . '://' . $host;
    }
    
    private function getRealIpAddress()
    {
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            return $_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            return $_SERVER['HTTP_X_FORWARDED_FOR'];
        } else {
            return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
        }
    }
    
    private function calculateEngagementScore($voteCounts, $commentCount, $shareCount)
    {
        // Simple engagement score calculation
        $likes = $voteCounts['likes'];
        $dislikes = $voteCounts['dislikes'];
        
        return ($likes * 1) + ($commentCount * 2) + ($shareCount * 3) - ($dislikes * 0.5);
    }
    
    // Additional helper methods would be implemented here...
}