<?php
/**
 * Name: Block Video Uploads
 * Description: Prevent users from uploading video files to media library to save storage space, reduce bandwidth usage, and enforce media policies for hosting efficiency
 * Category: Media
 * Icon: -
 * UseCases: [
 *   {
 *     "title": "Bandwidth Management",
 *     "description": "Prevent users from uploading large video files to shared hosting with limited bandwidth, forcing them to use YouTube or Vimeo instead."
 *   },
 *   {
 *     "title": "Storage Space Control",
 *     "description": "Block video uploads on sites nearing storage limits to preserve space for essential images and documents."
 *   },
 *   {
 *     "title": "Performance Protection",
 *     "description": "Prevent page load slowdowns from self-hosted videos by requiring all videos be embedded from external platforms."
 *   }
 * ]
 * Added: 2025-06-30
 * Tags: video, uploads, media, storage, bandwidth
 * WhereToFind: {
 *   "location": "Media Library Upload",
 *   "url": "upload.php",
 *   "instructions": "Try uploading video file - will be blocked with error message",
 *   "newTab": false
 * }
 */

// Prevent direct access
if (!defined('ABSPATH')) exit;

class SwitchboardBlockVideoUploads {
    
    public function __construct() {
        // Only use wp_handle_upload_prefilter for blocking
        // This allows us to show custom error messages
        add_filter('wp_handle_upload_prefilter', [$this, 'block_video_upload']);
    }

    /**
     * Register data locations for cleanup system
     *
     * @return array Data storage locations
     */
    public function register_data_locations() {
        return [
            'options' => [
                'switchboard_block-video-uploads_settings',
            ],
            'option_patterns' => [],
            'tables' => [],
            'post_meta' => [],
            'user_meta' => [],
        ];
    }

    /**
     * Render settings panel for Block Video Uploads
     * 
     * Displays settings interface for controlling video upload permissions with:
     * - Checkbox to block video uploads for administrators (default behavior fallback)
     * - Tag-based role selector for granular control over which user roles are blocked
     * - Custom error message input field for user-facing blocking notifications
     * - Clear explanatory text about settings precedence and behavior
     * 
     * The interface uses a custom tag selector UI pattern where users can click role names
     * to add them to the blocked list, and click the × to remove them. Selected roles are
     * stored as comma-separated values in a hidden input field. The blocking logic supports
     * two modes: (1) If specific roles are selected, ONLY those roles are blocked regardless
     * of admin checkbox, (2) If no roles are selected, the admin checkbox determines whether
     * admins are blocked or only non-admins. The error message field allows customization of
     * the rejection message shown to users when they attempt to upload video files. This module
     * is useful for saving hosting storage/bandwidth, enforcing media policies, or requiring
     * video embeds from external platforms like YouTube/Vimeo instead of self-hosting.
     * 
     * @param array $settings Current module settings with 'block_admins', 'blocked_roles', 'error_message' keys
     * @return void Outputs HTML directly
     */
    public function render_settings($settings = []) {
        $block_admins = isset($settings['block_admins']) ? $settings['block_admins'] : 'no';
        $blocked_roles = isset($settings['blocked_roles']) ? $settings['blocked_roles'] : '';
        $error_message = isset($settings['error_message']) ? $settings['error_message'] : 'Video uploads are not allowed.';
        
        $selected_roles = !empty($blocked_roles) ? array_map('trim', explode(',', $blocked_roles)) : [];
        $all_roles = wp_roles()->get_names();
        
        $html = '
            <input type="hidden" name="module" value="block-video-uploads">

            <div class="sb-module-option-item sb-module-toggle-item" style="margin-bottom: 24px;">
                <div class="sb-module-option-content">
                    <div class="sb-module-toggle-header">
                        <strong class="sb-module-option-title">' . esc_html__('Block video uploads for administrators too', 'wpswitchboard') . '</strong>
                        <label class="sb-module-toggle">
                            <input type="checkbox" name="setting_block_admins" value="yes" ' . checked($block_admins, 'yes', false) . '>
                            <span class="sb-module-toggle-slider"></span>
                        </label>
                    </div>
                    <p class="sb-module-option-text">' . esc_html__('Only used when no roles are selected below. Check this to block everyone including admins.', 'wpswitchboard') . '</p>
                </div>
            </div>

            <div class="sb-sp-group" style="margin-bottom: 24px;">
                <label for="setting_blocked_roles" class="sb-sp-label">' . esc_html__('Block for These Roles (Optional)', 'wpswitchboard') . '</label>
                <input type="hidden" name="setting_blocked_roles" id="setting_blocked_roles" value="' . esc_attr($blocked_roles) . '">
                <div class="switchboard-tag-selector" data-input-id="setting_blocked_roles">
                    <div class="switchboard-selected-tags" id="selected-roles">';
        
        foreach ($selected_roles as $role_slug) {
            if (isset($all_roles[$role_slug])) {
                $html .= '<span class="switchboard-tag" data-value="' . esc_attr($role_slug) . '">' . esc_html($all_roles[$role_slug]) . ' <span class="remove-tag">×</span></span>';
            }
        }
        
        $html .= '</div>
                    <div class="switchboard-available-tags">';
        
        foreach ($all_roles as $role_slug => $role_name) {
            $is_selected = in_array($role_slug, $selected_roles) ? 'selected' : '';
            $html .= '<span class="switchboard-tag-option ' . $is_selected . '" data-value="' . esc_attr($role_slug) . '">' . esc_html($role_name) . '</span>';
        }
        
        $html .= '</div>
                </div>
                <p class="sb-sp-description">' . esc_html__('If roles are selected, ONLY those roles will be blocked (including administrators if you select that role). Leave empty to use the checkbox above instead.', 'wpswitchboard') . '</p>
            </div>

            <div class="sb-sp-group sb-sp-field-horizontal" style="margin-bottom: 24px;">
                <div class="sb-sp-field-horizontal-left">
                    <label for="setting_error_message" class="sb-sp-label">' . esc_html__('Error Message', 'wpswitchboard') . '</label>
                    <p class="sb-sp-description">' . esc_html__('Message shown when video upload is blocked', 'wpswitchboard') . '</p>
                </div>
                <input type="text" name="setting_error_message" id="setting_error_message" class="sb-sp-input" value="' . esc_attr($error_message) . '">
            </div>

            <div class="sb-sp-info-box sb-sp-info-box-info">
                <h4 class="sb-sp-heading-sm">' . esc_html__('How It Works', 'wpswitchboard') . '</h4>
                <ul class="sb-sp-list">
                    <li class="sb-sp-list-item">' . esc_html__('Video files are blocked based on file extension and MIME type', 'wpswitchboard') . '</li>
                    <li class="sb-sp-list-item">' . esc_html__('Supported formats: MP4, MOV, AVI, WMV, FLV, WebM, MKV, and more', 'wpswitchboard') . '</li>
                    <li class="sb-sp-list-item">' . esc_html__('Users will see your custom error message when upload is blocked', 'wpswitchboard') . '</li>
                </ul>
            </div>

            <div class="sb-sp-info-box sb-sp-info-box-tip">
                <h4 class="sb-sp-heading-sm">' . esc_html__('Best Practices', 'wpswitchboard') . '</h4>
                <ul class="sb-sp-list">
                    <li class="sb-sp-list-item"><strong>' . esc_html__('Use External Platforms:', 'wpswitchboard') . '</strong> ' . esc_html__('Encourage users to upload videos to YouTube, Vimeo, or other platforms and embed them', 'wpswitchboard') . '</li>
                    <li class="sb-sp-list-item"><strong>' . esc_html__('Save Storage:', 'wpswitchboard') . '</strong> ' . esc_html__('Video files can be very large and consume significant hosting storage space', 'wpswitchboard') . '</li>
                    <li class="sb-sp-list-item"><strong>' . esc_html__('Bandwidth Protection:', 'wpswitchboard') . '</strong> ' . esc_html__('Self-hosted videos can consume large amounts of bandwidth, affecting site performance', 'wpswitchboard') . '</li>
                </ul>
            </div>
        ';
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- HTML is built safely with proper escaping throughout
        echo $html;
    }

    private function get_settings() {
        return get_option('switchboard_block-video-uploads_settings', []);
    }
    
    private function should_block() {
        $settings = $this->get_settings();
        $block_admins = isset($settings['block_admins']) ? $settings['block_admins'] : 'no';
        $blocked_roles = isset($settings['blocked_roles']) ? $settings['blocked_roles'] : '';

        $user = wp_get_current_user();

        // Check if specific roles are selected
        if (!empty($blocked_roles) && is_string($blocked_roles)) {
            $roles = array_map('trim', explode(',', $blocked_roles));

            // Check if user has any of the blocked roles
            if (is_array($user->roles)) {
                foreach ($roles as $role) {
                    if (in_array($role, $user->roles)) {
                        return true; // Block this user - they have a blocked role
                    }
                }
            }

            // User doesn't have any blocked roles, don't block
            return false;
        }

        // No specific roles selected - use default behavior
        // If "block admins too" is checked, block everyone
        if ($block_admins === 'yes') {
            return true;
        }

        // If "block admins too" is unchecked, block only non-admins
        if (current_user_can('manage_options')) {
            return false; // Don't block admins
        }

        return true; // Block everyone else
    }

    public function block_video_upload($file) {
        if (!$this->should_block()) {
            return $file;
        }
        
        // Check file extension
        $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        $video_extensions = ['mp4', 'm4v', 'mov', 'qt', 'avi', 'wmv', 'flv', 'webm', 'mkv', 'mpeg', 'mpg', 'mpe', '3gp', '3gpp', '3g2', '3gp2', 'ogv'];
        
        if (in_array($ext, $video_extensions)) {
            $settings = $this->get_settings();
            $message = isset($settings['error_message']) ? $settings['error_message'] : 'Video uploads are not allowed.';
            $file['error'] = $message;
            return $file;
        }
        
        // Also check MIME type as backup
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        if ($finfo === false) {
            return $file;
        }
        $mime = finfo_file($finfo, $file['tmp_name']);
        finfo_close($finfo);
        
        if (strpos($mime, 'video/') === 0) {
            $settings = $this->get_settings();
            $message = isset($settings['error_message']) ? $settings['error_message'] : 'Video uploads are not allowed.';
            $file['error'] = $message;
        }
        
        return $file;
    }
}

// Initialize and register with data system
$switchboard_instance = new SwitchboardBlockVideoUploads();
Switchboard_Data_Registry::get_instance()->auto_register($switchboard_instance, __FILE__);
