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

/**
 * Content Metadata Management System
 */
class VContentManager
{
    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;
    }
    
    /**
     * Update content metadata
     * @param string $contentType Content type (video, image, audio, document)
     * @param string $contentId Content ID
     * @param array $metadata Metadata to update
     * @param int $userId User ID (for permission check)
     * @return array Update result
     */
    public function updateContentMetadata($contentType, $contentId, $metadata, $userId)
    {
        try {
            // Validate content type
            $table = $this->getContentTable($contentType);
            if (!$table) {
                return [
                    'success' => false,
                    'error' => 'Invalid content type'
                ];
            }
            
            // Get existing content
            $content = $this->getContent($contentType, $contentId);
            if (!$content) {
                return [
                    'success' => false,
                    'error' => 'Content not found'
                ];
            }
            
            // Check permissions
            if ($content['usr_id'] != $userId && !$this->isAdmin($userId)) {
                return [
                    'success' => false,
                    'error' => 'Permission denied'
                ];
            }
            
            // Validate and sanitize metadata
            $validatedMetadata = $this->validateMetadata($metadata);
            if (!$validatedMetadata['valid']) {
                return [
                    'success' => false,
                    'error' => $validatedMetadata['error'],
                    'details' => $validatedMetadata['details']
                ];
            }
            
            // Update content
            $updateData = $validatedMetadata['data'];
            $updateData['updated_at'] = date('Y-m-d H:i:s');
            
            $this->db->doUpdate($table, 'file_key', $updateData, $contentId);
            
            // Update tags if provided
            if (isset($metadata['tags'])) {
                $this->updateContentTags($contentType, $contentId, $metadata['tags']);
            }
            
            // Update categories if provided
            if (isset($metadata['categories'])) {
                $this->updateContentCategories($contentType, $contentId, $metadata['categories']);
            }
            
            $this->logger->info('Content metadata updated', [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'user_id' => $userId,
                'updated_fields' => array_keys($updateData)
            ]);
            
            return [
                'success' => true,
                'message' => 'Content metadata updated successfully',
                'updated_fields' => array_keys($updateData)
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Failed to update content metadata', [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'user_id' => $userId,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => 'Failed to update content metadata'
            ];
        }
    }
    
    /**
     * Bulk update content metadata
     * @param string $contentType Content type
     * @param array $contentIds Array of content IDs
     * @param array $metadata Metadata to update
     * @param int $userId User ID
     * @return array Update result
     */
    public function bulkUpdateMetadata($contentType, $contentIds, $metadata, $userId)
    {
        try {
            $results = [
                'success' => 0,
                'failed' => 0,
                'errors' => []
            ];
            
            foreach ($contentIds as $contentId) {
                $result = $this->updateContentMetadata($contentType, $contentId, $metadata, $userId);
                
                if ($result['success']) {
                    $results['success']++;
                } else {
                    $results['failed']++;
                    $results['errors'][$contentId] = $result['error'];
                }
            }
            
            return [
                'success' => true,
                'results' => $results,
                'message' => "Updated {$results['success']} items, {$results['failed']} failed"
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Bulk metadata update failed', [
                'content_type' => $contentType,
                'content_count' => count($contentIds),
                'user_id' => $userId,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => 'Bulk update failed'
            ];
        }
    }
    
    /**
     * Get content categories
     * @param string $contentType Content type
     * @return array Categories
     */
    public function getContentCategories($contentType = null)
    {
        try {
            $whereClause = $contentType ? "WHERE content_type = ?" : "";
            $params = $contentType ? [$contentType] : [];
            
            $query = "SELECT * FROM db_content_categories {$whereClause} ORDER BY name ASC";
            $result = $this->db->doQuery($query, $params);
            
            $categories = [];
            while ($row = $this->db->doFetch($result)) {
                $categories[] = [
                    'id' => $row['id'],
                    'name' => $row['name'],
                    'slug' => $row['slug'],
                    'description' => $row['description'],
                    'content_type' => $row['content_type'],
                    'parent_id' => $row['parent_id'],
                    'sort_order' => $row['sort_order']
                ];
            }
            
            return [
                'success' => true,
                'categories' => $categories
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Create content category
     * @param array $categoryData Category data
     * @return array Creation result
     */
    public function createCategory($categoryData)
    {
        try {
            $validatedData = $this->validateCategoryData($categoryData);
            if (!$validatedData['valid']) {
                return [
                    'success' => false,
                    'error' => $validatedData['error']
                ];
            }
            
            $categoryId = $this->db->doInsert('db_content_categories', $validatedData['data']);
            
            if (!$categoryId) {
                throw new Exception('Failed to create category');
            }
            
            return [
                'success' => true,
                'category_id' => $categoryId,
                'message' => 'Category created successfully'
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Failed to create category', [
                'category_data' => $categoryData,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => 'Failed to create category'
            ];
        }
    }
    
    /**
     * Get popular tags
     * @param string $contentType Content type filter
     * @param int $limit Number of tags to return
     * @return array Popular tags
     */
    public function getPopularTags($contentType = null, $limit = 50)
    {
        try {
            $whereClause = $contentType ? "WHERE content_type = ?" : "";
            $params = $contentType ? [$contentType] : [];
            $params[] = $limit;
            
            $query = "SELECT tag_name, COUNT(*) as usage_count
                      FROM db_content_tags 
                      {$whereClause}
                      GROUP BY tag_name
                      ORDER BY usage_count DESC, tag_name ASC
                      LIMIT ?";
            
            $result = $this->db->doQuery($query, $params);
            
            $tags = [];
            while ($row = $this->db->doFetch($result)) {
                $tags[] = [
                    'name' => $row['tag_name'],
                    'usage_count' => (int)$row['usage_count']
                ];
            }
            
            return [
                'success' => true,
                'tags' => $tags
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Search content by metadata
     * @param array $searchParams Search parameters
     * @param int $limit Limit
     * @param int $offset Offset
     * @return array Search results
     */
    public function searchContent($searchParams, $limit = 20, $offset = 0)
    {
        try {
            $contentType = $searchParams['content_type'] ?? 'video';
            $table = $this->getContentTable($contentType);
            
            if (!$table) {
                return [
                    'success' => false,
                    'error' => 'Invalid content type'
                ];
            }
            
            $whereClause = "WHERE file_active = 1";
            $params = [];
            
            // Text search
            if (!empty($searchParams['query'])) {
                $whereClause .= " AND (file_title LIKE ? OR file_description LIKE ?)";
                $searchTerm = '%' . $searchParams['query'] . '%';
                $params[] = $searchTerm;
                $params[] = $searchTerm;
            }
            
            // Category filter
            if (!empty($searchParams['category'])) {
                $whereClause .= " AND file_category = ?";
                $params[] = $searchParams['category'];
            }
            
            // User filter
            if (!empty($searchParams['user_id'])) {
                $whereClause .= " AND usr_id = ?";
                $params[] = $searchParams['user_id'];
            }
            
            // Date range filter
            if (!empty($searchParams['date_from'])) {
                $whereClause .= " AND file_date >= ?";
                $params[] = $searchParams['date_from'];
            }
            
            if (!empty($searchParams['date_to'])) {
                $whereClause .= " AND file_date <= ?";
                $params[] = $searchParams['date_to'];
            }
            
            // Privacy filter
            if (!empty($searchParams['privacy'])) {
                $whereClause .= " AND privacy = ?";
                $params[] = $searchParams['privacy'];
            }
            
            // Sort order
            $sortOrder = $this->getSortOrder($searchParams['sort'] ?? 'newest');
            
            $query = "SELECT f.*, u.usr_user
                      FROM {$table} f
                      JOIN db_accountuser u ON f.usr_id = u.usr_id
                      {$whereClause}
                      ORDER BY {$sortOrder}
                      LIMIT ? OFFSET ?";
            
            $params[] = $limit;
            $params[] = $offset;
            
            $result = $this->db->doQuery($query, $params);
            
            $content = [];
            while ($row = $this->db->doFetch($result)) {
                $content[] = $this->formatContentData($row, $contentType);
            }
            
            // Get total count
            $countQuery = "SELECT COUNT(*) as total FROM {$table} f {$whereClause}";
            $countParams = array_slice($params, 0, -2); // Remove limit and offset
            $countResult = $this->db->doQuery($countQuery, $countParams);
            $totalCount = $this->db->doFetch($countResult)['total'];
            
            return [
                'success' => true,
                'content' => $content,
                'pagination' => [
                    'total' => $totalCount,
                    'limit' => $limit,
                    'offset' => $offset,
                    'pages' => ceil($totalCount / $limit)
                ]
            ];
            
        } catch (Exception $e) {
            $this->logger->error('Content search failed', [
                'search_params' => $searchParams,
                'error' => $e->getMessage()
            ]);
            
            return [
                'success' => false,
                'error' => 'Search failed'
            ];
        }
    }
    
    /**
     * Private helper methods
     */
    
    private function getContentTable($contentType)
    {
        $tables = [
            'video' => 'db_videofiles',
            'image' => 'db_imagefiles',
            'audio' => 'db_audiofiles',
            'document' => 'db_documentfiles'
        ];
        
        return $tables[$contentType] ?? null;
    }
    
    private function getContent($contentType, $contentId)
    {
        $table = $this->getContentTable($contentType);
        
        $query = "SELECT * FROM {$table} WHERE file_key = ?";
        $result = $this->db->doQuery($query, [$contentId]);
        
        return $this->db->doFetch($result);
    }
    
    private function validateMetadata($metadata)
    {
        $validatedData = [];
        $errors = [];
        
        // Title validation
        if (isset($metadata['title'])) {
            $title = trim($metadata['title']);
            if (empty($title)) {
                $errors[] = 'Title cannot be empty';
            } elseif (strlen($title) > 255) {
                $errors[] = 'Title too long (max 255 characters)';
            } else {
                $validatedData['file_title'] = $title;
            }
        }
        
        // Description validation
        if (isset($metadata['description'])) {
            $description = trim($metadata['description']);
            if (strlen($description) > 5000) {
                $errors[] = 'Description too long (max 5000 characters)';
            } else {
                $validatedData['file_description'] = $description;
            }
        }
        
        // Privacy validation
        if (isset($metadata['privacy'])) {
            $validPrivacy = ['public', 'unlisted', 'private'];
            if (!in_array($metadata['privacy'], $validPrivacy)) {
                $errors[] = 'Invalid privacy setting';
            } else {
                $validatedData['privacy'] = $metadata['privacy'];
            }
        }
        
        // Category validation
        if (isset($metadata['category'])) {
            $category = trim($metadata['category']);
            if (!empty($category)) {
                $validatedData['file_category'] = $category;
            }
        }
        
        return [
            'valid' => empty($errors),
            'data' => $validatedData,
            'error' => empty($errors) ? null : 'Validation failed',
            'details' => $errors
        ];
    }
    
    private function updateContentTags($contentType, $contentId, $tags)
    {
        try {
            // Remove existing tags
            $this->db->doQuery(
                "DELETE FROM db_content_tags WHERE content_type = ? AND content_id = ?",
                [$contentType, $contentId]
            );
            
            // Add new tags
            if (!empty($tags)) {
                $tagList = is_array($tags) ? $tags : explode(',', $tags);
                
                foreach ($tagList as $tag) {
                    $tag = trim($tag);
                    if (!empty($tag)) {
                        $tagData = [
                            'content_type' => $contentType,
                            'content_id' => $contentId,
                            'tag_name' => $tag,
                            'created_at' => date('Y-m-d H:i:s')
                        ];
                        
                        $this->db->doInsert('db_content_tags', $tagData);
                    }
                }
            }
            
        } catch (Exception $e) {
            $this->logger->error('Failed to update content tags', [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'error' => $e->getMessage()
            ]);
        }
    }
    
    private function updateContentCategories($contentType, $contentId, $categories)
    {
        try {
            // Remove existing category associations
            $this->db->doQuery(
                "DELETE FROM db_content_category_relations WHERE content_type = ? AND content_id = ?",
                [$contentType, $contentId]
            );
            
            // Add new category associations
            if (!empty($categories)) {
                $categoryList = is_array($categories) ? $categories : [$categories];
                
                foreach ($categoryList as $categoryId) {
                    if (!empty($categoryId)) {
                        $relationData = [
                            'content_type' => $contentType,
                            'content_id' => $contentId,
                            'category_id' => $categoryId,
                            'created_at' => date('Y-m-d H:i:s')
                        ];
                        
                        $this->db->doInsert('db_content_category_relations', $relationData);
                    }
                }
            }
            
        } catch (Exception $e) {
            $this->logger->error('Failed to update content categories', [
                'content_type' => $contentType,
                'content_id' => $contentId,
                'error' => $e->getMessage()
            ]);
        }
    }
    
    private function validateCategoryData($categoryData)
    {
        $validatedData = [];
        $errors = [];
        
        // Name validation
        if (empty($categoryData['name'])) {
            $errors[] = 'Category name is required';
        } else {
            $validatedData['name'] = trim($categoryData['name']);
            $validatedData['slug'] = $this->generateSlug($validatedData['name']);
        }
        
        // Content type validation
        $validTypes = ['video', 'image', 'audio', 'document', 'all'];
        if (empty($categoryData['content_type']) || !in_array($categoryData['content_type'], $validTypes)) {
            $errors[] = 'Valid content type is required';
        } else {
            $validatedData['content_type'] = $categoryData['content_type'];
        }
        
        // Optional fields
        $validatedData['description'] = trim($categoryData['description'] ?? '');
        $validatedData['parent_id'] = $categoryData['parent_id'] ?? null;
        $validatedData['sort_order'] = (int)($categoryData['sort_order'] ?? 0);
        $validatedData['created_at'] = date('Y-m-d H:i:s');
        
        return [
            'valid' => empty($errors),
            'data' => $validatedData,
            'error' => empty($errors) ? null : implode(', ', $errors)
        ];
    }
    
    private function generateSlug($name)
    {
        $slug = strtolower(trim($name));
        $slug = preg_replace('/[^a-z0-9-]/', '-', $slug);
        $slug = preg_replace('/-+/', '-', $slug);
        return trim($slug, '-');
    }
    
    private function getSortOrder($sort)
    {
        switch ($sort) {
            case 'newest':
                return 'f.file_date DESC';
            case 'oldest':
                return 'f.file_date ASC';
            case 'popular':
                return 'f.file_views DESC';
            case 'title':
                return 'f.file_title ASC';
            case 'rating':
                return 'f.file_likes DESC';
            default:
                return 'f.file_date DESC';
        }
    }
    
    private function formatContentData($row, $contentType)
    {
        return [
            'id' => $row['file_key'],
            'type' => $contentType,
            'title' => $row['file_title'],
            'description' => $row['file_description'] ?? '',
            'category' => $row['file_category'] ?? '',
            'privacy' => $row['privacy'] ?? 'public',
            'views' => (int)($row['file_views'] ?? 0),
            'likes' => (int)($row['file_likes'] ?? 0),
            'dislikes' => (int)($row['file_dislikes'] ?? 0),
            'comments' => (int)($row['file_comments_count'] ?? 0),
            'uploaded_at' => $row['file_date'],
            'updated_at' => $row['updated_at'] ?? $row['file_date'],
            'uploader' => [
                'id' => $row['usr_id'],
                'username' => $row['usr_user']
            ]
        ];
    }
    
    private function isAdmin($userId)
    {
        try {
            $query = "SELECT usr_role FROM db_accountuser WHERE usr_id = ?";
            $result = $this->db->doQuery($query, [$userId]);
            $user = $this->db->doFetch($result);
            
            return $user && in_array($user['usr_role'], ['admin', 'moderator']);
        } catch (Exception $e) {
            return false;
        }
    }
}