<?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');

/**
 * Live Streaming System with SRS Integration
 */
class VLiveStreaming
{
    private $logger;
    private $db;
    private $queue;
    private $srsConfig;
    
    // SRS default configuration
    private $srsHost = 'localhost';
    private $srsRtmpPort = 1935;
    private $srsHttpPort = 8080;
    private $srsApiPort = 1985;
    
    public function __construct()
    {
        $this->logger = VLogger::getInstance();
        $this->db = VDatabase::getInstance();
        $this->queue = new VQueueManager();
        
        $this->loadSRSConfig();
    }
    
    /**
     * Create live stream
     * @param int $userId User ID
     * @param array $streamData Stream configuration
     * @return array Stream creation result
     */
    public function createStream($userId, $streamData)
    {
        try {
            $streamKey = $this->generateStreamKey();
            
            $stream = [
                'stream_key' => $streamKey,
                'user_id' => $userId,
                'title' => $streamData['title'] ?? 'Live Stream',
                'description' => $streamData['description'] ?? '',
                'category' => $streamData['category'] ?? 'general',
                'privacy' => $streamData['privacy'] ?? 'public',
                'status' => 'created',
                'rtmp_url' => "rtmp://{$this->srsHost}:{$this->srsRtmpPort}/live/{$streamKey}",
                'hls_url' => "http://{$this->srsHost}:{$this->srsHttpPort}/live/{$streamKey}.m3u8",
                'created_at' => date('Y-m-d H:i:s'),
                'updated_at' => date('Y-m-d H:i:s')
            ];
            
            $streamId = $this->db->doInsert('db_live_streams', $stream);
            
            if (!$streamId) {
                throw new Exception('Failed to create stream record');
            }
            
            $this->logger->info('Live stream created', [
                'stream_id' => $streamId,
                'stream_key' => $streamKey,
                'user_id' => $userId
            ]);
            
            return [
                'success' => true,
                'stream_id' => $streamId,
                'stream_key' => $streamKey,
                'rtmp_url' => $stream['rtmp_url'],
                'hls_url' => $stream['hls_url'],
                'stream_data' => $stream
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Failed to create live stream', [
                'user_id' => $userId,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Start live stream
     * @param string $streamKey Stream key
     * @return array Start result
     */
    public function startStream($streamKey)
    {
        try {
            $stream = $this->getStreamByKey($streamKey);
            
            if (!$stream) {
                throw new Exception('Stream not found');
            }
            
            // Update stream status
            $this->db->doUpdate('db_live_streams', 'id', [
                'status' => 'live',
                'started_at' => date('Y-m-d H:i:s'),
                'updated_at' => date('Y-m-d H:i:s')
            ], $stream['id']);
            
            // Notify subscribers
            $this->notifyStreamStart($stream);
            
            $this->logger->info('Live stream started', [
                'stream_key' => $streamKey,
                'stream_id' => $stream['id']
            ]);
            
            return [
                'success' => true,
                'message' => 'Stream started successfully'
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Failed to start stream', [
                'stream_key' => $streamKey,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Stop live stream
     * @param string $streamKey Stream key
     * @param bool $saveRecording Whether to save recording
     * @return array Stop result
     */
    public function stopStream($streamKey, $saveRecording = true)
    {
        try {
            $stream = $this->getStreamByKey($streamKey);
            
            if (!$stream) {
                throw new Exception('Stream not found');
            }
            
            // Update stream status
            $updateData = [
                'status' => 'ended',
                'ended_at' => date('Y-m-d H:i:s'),
                'updated_at' => date('Y-m-d H:i:s')
            ];
            
            if ($saveRecording) {
                // Queue recording processing job
                $this->queue->enqueue('StreamRecordingJob', [
                    'stream_id' => $stream['id'],
                    'stream_key' => $streamKey,
                    'user_id' => $stream['user_id']
                ], 'video_processing', 0, 1);
                
                $updateData['recording_queued'] = 1;
            }
            
            $this->db->doUpdate('db_live_streams', 'id', $updateData, $stream['id']);
            
            $this->logger->info('Live stream stopped', [
                'stream_key' => $streamKey,
                'stream_id' => $stream['id'],
                'save_recording' => $saveRecording
            ]);
            
            return [
                'success' => true,
                'message' => 'Stream stopped successfully',
                'recording_queued' => $saveRecording
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Failed to stop stream', [
                'stream_key' => $streamKey,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Get live streams
     * @param array $filters Filters
     * @param int $limit Limit
     * @param int $offset Offset
     * @return array Streams
     */
    public function getLiveStreams($filters = [], $limit = 20, $offset = 0)
    {
        try {
            $whereClause = "WHERE 1=1";
            $params = [];
            
            if (isset($filters['status'])) {
                $whereClause .= " AND status = ?";
                $params[] = $filters['status'];
            }
            
            if (isset($filters['user_id'])) {
                $whereClause .= " AND user_id = ?";
                $params[] = $filters['user_id'];
            }
            
            if (isset($filters['category'])) {
                $whereClause .= " AND category = ?";
                $params[] = $filters['category'];
            }
            
            $query = "SELECT ls.*, au.usr_user, au.usr_avatar 
                      FROM db_live_streams ls
                      JOIN db_accountuser au ON ls.user_id = au.usr_id
                      {$whereClause}
                      ORDER BY ls.created_at DESC
                      LIMIT ? OFFSET ?";
            
            $params[] = $limit;
            $params[] = $offset;
            
            $result = $this->db->doQuery($query, $params);
            
            $streams = [];
            while ($row = $this->db->doFetch($result)) {
                $streams[] = $this->formatStreamData($row);
            }
            
            return [
                'success' => true,
                'streams' => $streams,
                'total' => $this->getStreamCount($filters)
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Failed to get live streams', [
                'filters' => $filters,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Get stream statistics
     * @param string $streamKey Stream key
     * @return array Statistics
     */
    public function getStreamStats($streamKey)
    {
        try {
            $stream = $this->getStreamByKey($streamKey);
            
            if (!$stream) {
                throw new Exception('Stream not found');
            }
            
            // Get viewer count from SRS API
            $viewerCount = $this->getSRSViewerCount($streamKey);
            
            // Get chat message count
            $chatCount = $this->getChatMessageCount($stream['id']);
            
            // Calculate duration
            $duration = 0;
            if ($stream['started_at']) {
                $endTime = $stream['ended_at'] ? strtotime($stream['ended_at']) : time();
                $duration = $endTime - strtotime($stream['started_at']);
            }
            
            return [
                'success' => true,
                'stats' => [
                    'viewer_count' => $viewerCount,
                    'chat_messages' => $chatCount,
                    'duration' => $duration,
                    'status' => $stream['status'],
                    'started_at' => $stream['started_at'],
                    'ended_at' => $stream['ended_at']
                ]
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Failed to get stream stats', [
                'stream_key' => $streamKey,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Private helper methods
     */
    
    private function loadSRSConfig()
    {
        // Load SRS configuration from database or config file
        $this->srsConfig = [
            'host' => $this->srsHost,
            'rtmp_port' => $this->srsRtmpPort,
            'http_port' => $this->srsHttpPort,
            'api_port' => $this->srsApiPort
        ];
    }
    
    private function generateStreamKey()
    {
        return uniqid('stream_', true) . '_' . time();
    }
    
    private function getStreamByKey($streamKey)
    {
        $query = "SELECT * FROM db_live_streams WHERE stream_key = ?";
        $result = $this->db->doQuery($query, [$streamKey]);
        
        return $this->db->doFetch($result);
    }
    
    private function notifyStreamStart($stream)
    {
        // Get user's followers
        $query = "SELECT follower_id FROM db_user_follows WHERE user_id = ?";
        $result = $this->db->doQuery($query, [$stream['user_id']]);
        
        while ($row = $this->db->doFetch($result)) {
            // Create notification
            $notification = [
                'user_id' => $row['follower_id'],
                'type' => 'live_stream_started',
                'title' => 'Live Stream Started',
                'message' => "User is now live streaming: {$stream['title']}",
                'data' => json_encode([
                    'stream_id' => $stream['id'],
                    'stream_key' => $stream['stream_key'],
                    'streamer' => $stream['user_id']
                ]),
                'created_at' => date('Y-m-d H:i:s'),
                'read_status' => 0
            ];
            
            $this->db->doInsert('db_notifications', $notification);
        }
    }
    
    private function getSRSViewerCount($streamKey)
    {
        try {
            // Call SRS API to get viewer count
            $url = "http://{$this->srsHost}:{$this->srsApiPort}/api/v1/streams/";
            $response = file_get_contents($url);
            
            if ($response) {
                $data = json_decode($response, true);
                // Parse SRS response to get viewer count for specific stream
                // This is a simplified implementation
                return $data['streams'][$streamKey]['clients'] ?? 0;
            }
            
            return 0;
            
        } catch (Exception $e) {
            return 0;
        }
    }
    
    private function getChatMessageCount($streamId)
    {
        try {
            $query = "SELECT COUNT(*) as count FROM db_stream_chat WHERE stream_id = ?";
            $result = $this->db->doQuery($query, [$streamId]);
            $row = $this->db->doFetch($result);
            
            return (int)($row['count'] ?? 0);
            
        } catch (Exception $e) {
            return 0;
        }
    }
    
    private function getStreamCount($filters)
    {
        try {
            $whereClause = "WHERE 1=1";
            $params = [];
            
            if (isset($filters['status'])) {
                $whereClause .= " AND status = ?";
                $params[] = $filters['status'];
            }
            
            if (isset($filters['user_id'])) {
                $whereClause .= " AND user_id = ?";
                $params[] = $filters['user_id'];
            }
            
            $query = "SELECT COUNT(*) as count FROM db_live_streams {$whereClause}";
            $result = $this->db->doQuery($query, $params);
            $row = $this->db->doFetch($result);
            
            return (int)($row['count'] ?? 0);
            
        } catch (Exception $e) {
            return 0;
        }
    }
    
    private function formatStreamData($row)
    {
        return [
            'id' => $row['id'],
            'stream_key' => $row['stream_key'],
            'title' => $row['title'],
            'description' => $row['description'],
            'category' => $row['category'],
            'privacy' => $row['privacy'],
            'status' => $row['status'],
            'rtmp_url' => $row['rtmp_url'],
            'hls_url' => $row['hls_url'],
            'created_at' => $row['created_at'],
            'started_at' => $row['started_at'],
            'ended_at' => $row['ended_at'],
            'user' => [
                'id' => $row['user_id'],
                'username' => $row['usr_user'],
                'avatar' => $row['usr_avatar']
            ]
        ];
    }
}