<?php
/**
 * Cast Conductor Proprietary License v5
 * SPDX-License-Identifier: LicenseRef-CastConductor-Proprietary-v5
 * Copyright (c) 2025 CastConductor.com. All Rights Reserved.
 */

/**
 * CastConductor Debug Logging System
 * 
 * Provides remote debug log collection from Roku devices.
 * Logs are stored in WordPress and can be viewed/exported by admins.
 * 
 * Features:
 * - Toggle debug mode on/off from WordPress admin
 * - Roku app POSTs logs to WordPress when debug mode is enabled
 * - Admin can view, copy, or download logs
 * - Auto-purge logs older than 24 hours
 */

if (!defined('ABSPATH')) {
    exit;
}

class CastConductor_Debug {
    
    /**
     * Option names
     */
    const OPTION_DEBUG_MODE = 'castconductor_debug_mode';
    const OPTION_DEBUG_LOGS = 'castconductor_debug_logs';
    const OPTION_LAST_PURGE = 'castconductor_debug_last_purge';
    
    /**
     * Log retention period (24 hours in seconds)
     */
    const LOG_RETENTION_SECONDS = 86400;
    
    /**
     * Maximum log entries to store
     */
    const MAX_LOG_ENTRIES = 5000;
    
    /**
     * Constructor
     */
    public function __construct() {
        add_action('rest_api_init', array($this, 'register_rest_routes'));
        add_action('admin_menu', array($this, 'add_admin_menu'), 20);
        add_action('admin_init', array($this, 'register_settings'));
        add_action('wp_ajax_castconductor_get_debug_logs', array($this, 'ajax_get_logs'));
        add_action('wp_ajax_castconductor_clear_debug_logs', array($this, 'ajax_clear_logs'));
    }
    
    /**
     * Register REST API routes
     */
    public function register_rest_routes() {
        // POST endpoint for Roku to send logs
        register_rest_route('castconductor/v5', '/debug/log', array(
            'methods' => 'POST',
            'callback' => array($this, 'receive_log'),
            'permission_callback' => '__return_true', // Public - Roku needs to POST without auth
        ));
        
        // GET endpoint for admin to retrieve logs (authenticated)
        register_rest_route('castconductor/v5', '/debug/logs', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_logs'),
            'permission_callback' => function() {
                return current_user_can('manage_options');
            },
        ));
        
        // DELETE endpoint for admin to clear logs (authenticated)
        register_rest_route('castconductor/v5', '/debug/logs', array(
            'methods' => 'DELETE',
            'callback' => array($this, 'clear_logs'),
            'permission_callback' => function() {
                return current_user_can('manage_options');
            },
        ));
    }
    
    /**
     * Add admin menu page
     */
    public function add_admin_menu() {
        add_submenu_page(
            'castconductor',
            __('Debug Logs', 'castconductor'),
            __('Debug Logs', 'castconductor'),
            'manage_options',
            'castconductor-debug',
            array($this, 'render_admin_page')
        );
    }
    
    /**
     * Register settings
     */
    public function register_settings() {
        register_setting('castconductor_debug', self::OPTION_DEBUG_MODE, array(
            'type' => 'boolean',
            'sanitize_callback' => 'rest_sanitize_boolean',
            'default' => false,
        ));
    }
    
    /**
     * Check if debug mode is enabled
     */
    public static function is_debug_enabled() {
        return (bool) get_option(self::OPTION_DEBUG_MODE, false);
    }
    
    /**
     * Receive log entries from Roku device
     */
    public function receive_log($request) {
        // Check if debug mode is enabled
        if (!self::is_debug_enabled()) {
            return new WP_REST_Response(array(
                'success' => false,
                'message' => 'Debug mode is disabled',
            ), 403);
        }
        
        // Get log data from request
        $body = $request->get_json_params();
        
        if (empty($body)) {
            return new WP_REST_Response(array(
                'success' => false,
                'message' => 'No log data received',
            ), 400);
        }
        
        // Purge old logs periodically
        $this->maybe_purge_old_logs();
        
        // Get existing logs
        $logs = get_option(self::OPTION_DEBUG_LOGS, array());
        if (!is_array($logs)) {
            $logs = array();
        }
        
        // Handle batch logs (array of entries)
        $entries = isset($body['entries']) ? $body['entries'] : array($body);
        $device_id = isset($body['device_id']) ? sanitize_text_field($body['device_id']) : 'unknown';
        
        foreach ($entries as $entry) {
            $log_entry = array(
                'timestamp' => current_time('c'),
                'unix_time' => time(),
                'device_id' => $device_id,
                'level' => isset($entry['level']) ? sanitize_text_field($entry['level']) : 'INFO',
                'component' => isset($entry['component']) ? sanitize_text_field($entry['component']) : 'Roku',
                'message' => isset($entry['message']) ? sanitize_text_field($entry['message']) : '',
            );
            
            $logs[] = $log_entry;
        }
        
        // Trim to max entries (keep newest)
        if (count($logs) > self::MAX_LOG_ENTRIES) {
            $logs = array_slice($logs, -self::MAX_LOG_ENTRIES);
        }
        
        // Save logs
        update_option(self::OPTION_DEBUG_LOGS, $logs, false); // Don't autoload
        
        return new WP_REST_Response(array(
            'success' => true,
            'message' => 'Log received',
            'entries_stored' => count($entries),
        ), 200);
    }
    
    /**
     * Get logs (REST API)
     */
    public function get_logs($request) {
        $logs = get_option(self::OPTION_DEBUG_LOGS, array());
        
        // Get optional filters
        $since = $request->get_param('since'); // Unix timestamp
        $component = $request->get_param('component');
        $level = $request->get_param('level');
        $limit = (int) $request->get_param('limit') ?: 500;
        
        // Filter logs
        if ($since || $component || $level) {
            $logs = array_filter($logs, function($log) use ($since, $component, $level) {
                if ($since && $log['unix_time'] < $since) return false;
                if ($component && $log['component'] !== $component) return false;
                if ($level && $log['level'] !== $level) return false;
                return true;
            });
        }
        
        // Limit results (newest first)
        $logs = array_slice(array_reverse($logs), 0, $limit);
        
        return new WP_REST_Response(array(
            'success' => true,
            'debug_enabled' => self::is_debug_enabled(),
            'total_entries' => count(get_option(self::OPTION_DEBUG_LOGS, array())),
            'returned_entries' => count($logs),
            'logs' => $logs,
        ), 200);
    }
    
    /**
     * Clear logs (REST API)
     */
    public function clear_logs($request) {
        delete_option(self::OPTION_DEBUG_LOGS);
        
        return new WP_REST_Response(array(
            'success' => true,
            'message' => 'Debug logs cleared',
        ), 200);
    }
    
    /**
     * AJAX handler: Get logs
     */
    public function ajax_get_logs() {
        check_ajax_referer('castconductor_debug_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error('Unauthorized');
            return;
        }
        
        $logs = get_option(self::OPTION_DEBUG_LOGS, array());
        $logs = array_reverse($logs); // Newest first
        
        wp_send_json_success(array(
            'debug_enabled' => self::is_debug_enabled(),
            'total_entries' => count($logs),
            'logs' => array_slice($logs, 0, 500),
        ));
    }
    
    /**
     * AJAX handler: Clear logs
     */
    public function ajax_clear_logs() {
        check_ajax_referer('castconductor_debug_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error('Unauthorized');
            return;
        }
        
        delete_option(self::OPTION_DEBUG_LOGS);
        wp_send_json_success(array('message' => 'Logs cleared'));
    }
    
    /**
     * Purge logs older than retention period
     */
    private function maybe_purge_old_logs() {
        $last_purge = (int) get_option(self::OPTION_LAST_PURGE, 0);
        
        // Only purge every hour
        if (time() - $last_purge < 3600) {
            return;
        }
        
        $logs = get_option(self::OPTION_DEBUG_LOGS, array());
        if (empty($logs)) {
            return;
        }
        
        $cutoff = time() - self::LOG_RETENTION_SECONDS;
        $logs = array_filter($logs, function($log) use ($cutoff) {
            return isset($log['unix_time']) && $log['unix_time'] >= $cutoff;
        });
        
        update_option(self::OPTION_DEBUG_LOGS, array_values($logs), false);
        update_option(self::OPTION_LAST_PURGE, time());
    }
    
    /**
     * Format logs as plain text for export
     */
    public static function format_logs_as_text($logs) {
        $output = "CastConductor Debug Log Export\n";
        $output .= "Generated: " . current_time('c') . "\n";
        $output .= "Site: " . home_url() . "\n";
        $output .= str_repeat("=", 80) . "\n\n";
        
        foreach ($logs as $log) {
            $output .= sprintf(
                "[%s] [%s] [%s] %s\n",
                $log['timestamp'],
                strtoupper($log['level']),
                $log['component'],
                $log['message']
            );
        }
        
        return $output;
    }
    
    /**
     * Render admin page
     */
    public function render_admin_page() {
        $debug_enabled = self::is_debug_enabled();
        $logs = get_option(self::OPTION_DEBUG_LOGS, array());
        $log_count = count($logs);
        ?>
        <div class="wrap">
            <h1><?php _e('CastConductor Debug Logs', 'castconductor'); ?></h1>
            
            <div class="cc-debug-controls" style="background: #fff; padding: 20px; border: 1px solid #ccd0d4; margin-bottom: 20px;">
                <form method="post" action="options.php" style="display: inline;">
                    <?php settings_fields('castconductor_debug'); ?>
                    <label style="font-size: 16px; font-weight: 600;">
                        <input type="checkbox" 
                               name="<?php echo esc_attr(self::OPTION_DEBUG_MODE); ?>" 
                               value="1" 
                               <?php checked($debug_enabled); ?>
                               onchange="this.form.submit();" />
                        <?php _e('Enable Debug Logging', 'castconductor'); ?>
                    </label>
                    <?php submit_button(__('Save', 'castconductor'), 'secondary', 'submit', false, array('style' => 'margin-left: 10px;')); ?>
                </form>
                
                <p class="description" style="margin-top: 10px;">
                    <?php if ($debug_enabled): ?>
                        <span style="color: #46b450;">●</span>
                        <?php _e('Debug mode is <strong>ENABLED</strong>. Your Roku app will send logs to WordPress.', 'castconductor'); ?>
                    <?php else: ?>
                        <span style="color: #dc3232;">●</span>
                        <?php _e('Debug mode is <strong>DISABLED</strong>. Enable to collect logs from your Roku app.', 'castconductor'); ?>
                    <?php endif; ?>
                </p>
            </div>
            
            <div class="cc-debug-actions" style="margin-bottom: 20px;">
                <button type="button" class="button" id="cc-refresh-logs">
                    🔄 <?php _e('Refresh Logs', 'castconductor'); ?>
                </button>
                <button type="button" class="button" id="cc-copy-logs">
                    📋 <?php _e('Copy to Clipboard', 'castconductor'); ?>
                </button>
                <button type="button" class="button" id="cc-download-logs">
                    📥 <?php _e('Download Log File', 'castconductor'); ?>
                </button>
                <button type="button" class="button" id="cc-clear-logs" style="color: #dc3232;">
                    🗑️ <?php _e('Clear Logs', 'castconductor'); ?>
                </button>
                <span class="cc-log-count" style="margin-left: 20px; color: #666;">
                    <?php printf(__('%d log entries', 'castconductor'), $log_count); ?>
                </span>
            </div>
            
            <div class="cc-debug-log-viewer" style="background: #1e1e1e; color: #d4d4d4; padding: 15px; font-family: 'Consolas', 'Monaco', monospace; font-size: 12px; line-height: 1.5; max-height: 600px; overflow-y: auto; border-radius: 4px;">
                <div id="cc-log-content">
                    <?php if (empty($logs)): ?>
                        <div style="color: #888; text-align: center; padding: 40px;">
                            <?php _e('No debug logs yet. Enable debug mode and interact with your Roku app to generate logs.', 'castconductor'); ?>
                        </div>
                    <?php else: ?>
                        <?php 
                        $logs = array_reverse($logs); // Newest first
                        foreach (array_slice($logs, 0, 500) as $log): 
                            $level_color = '#d4d4d4';
                            if ($log['level'] === 'ERROR') $level_color = '#f44336';
                            elseif ($log['level'] === 'WARN') $level_color = '#ff9800';
                            elseif ($log['level'] === 'INFO') $level_color = '#4fc3f7';
                            elseif ($log['level'] === 'DEBUG') $level_color = '#888';
                        ?>
                        <div class="cc-log-entry" style="margin-bottom: 2px;">
                            <span style="color: #888;">[<?php echo esc_html($log['timestamp']); ?>]</span>
                            <span style="color: <?php echo $level_color; ?>;">[<?php echo esc_html(strtoupper($log['level'])); ?>]</span>
                            <span style="color: #9cdcfe;">[<?php echo esc_html($log['component']); ?>]</span>
                            <span><?php echo esc_html($log['message']); ?></span>
                        </div>
                        <?php endforeach; ?>
                    <?php endif; ?>
                </div>
            </div>
            
            <div class="cc-debug-help" style="margin-top: 20px; padding: 15px; background: #f0f0f1; border-left: 4px solid #2271b1;">
                <h3 style="margin-top: 0;"><?php _e('💡 How to Use Debug Logs', 'castconductor'); ?></h3>
                <ol>
                    <li><?php _e('Enable Debug Logging above', 'castconductor'); ?></li>
                    <li><?php _e('Launch your Roku channel - logs will automatically stream to this page', 'castconductor'); ?></li>
                    <li><?php _e('Click "Refresh Logs" to see new entries', 'castconductor'); ?></li>
                    <li><?php _e('Use "Copy to Clipboard" or "Download Log File" to share logs with support', 'castconductor'); ?></li>
                </ol>
                <p><strong><?php _e('Note:', 'castconductor'); ?></strong> <?php _e('Logs are automatically deleted after 24 hours. Debug mode may slightly impact Roku app performance.', 'castconductor'); ?></p>
            </div>
        </div>
        
        <script>
        jQuery(document).ready(function($) {
            var nonce = '<?php echo wp_create_nonce('castconductor_debug_nonce'); ?>';
            
            // Refresh logs
            $('#cc-refresh-logs').on('click', function() {
                var $btn = $(this);
                $btn.prop('disabled', true).text('Refreshing...');
                
                $.post(ajaxurl, {
                    action: 'castconductor_get_debug_logs',
                    nonce: nonce
                }, function(response) {
                    if (response.success) {
                        location.reload();
                    }
                    $btn.prop('disabled', false).html('🔄 Refresh Logs');
                });
            });
            
            // Copy to clipboard
            $('#cc-copy-logs').on('click', function() {
                var logText = '';
                $('#cc-log-content .cc-log-entry').each(function() {
                    logText += $(this).text().trim() + '\n';
                });
                
                if (!logText) {
                    logText = 'No debug logs available.';
                }
                
                navigator.clipboard.writeText(logText).then(function() {
                    alert('<?php _e('Logs copied to clipboard!', 'castconductor'); ?>');
                }).catch(function() {
                    // Fallback for older browsers
                    var $temp = $('<textarea>');
                    $('body').append($temp);
                    $temp.val(logText).select();
                    document.execCommand('copy');
                    $temp.remove();
                    alert('<?php _e('Logs copied to clipboard!', 'castconductor'); ?>');
                });
            });
            
            // Download log file
            $('#cc-download-logs').on('click', function() {
                var logText = 'CastConductor Debug Log Export\n';
                logText += 'Generated: ' + new Date().toISOString() + '\n';
                logText += 'Site: <?php echo esc_js(home_url()); ?>\n';
                logText += '================================================================================\n\n';
                
                $('#cc-log-content .cc-log-entry').each(function() {
                    logText += $(this).text().trim() + '\n';
                });
                
                var blob = new Blob([logText], {type: 'text/plain'});
                var url = window.URL.createObjectURL(blob);
                var a = document.createElement('a');
                a.href = url;
                a.download = 'castconductor-debug-' + new Date().toISOString().slice(0,10) + '.txt';
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                window.URL.revokeObjectURL(url);
            });
            
            // Clear logs
            $('#cc-clear-logs').on('click', function() {
                if (!confirm('<?php _e('Are you sure you want to clear all debug logs?', 'castconductor'); ?>')) {
                    return;
                }
                
                $.post(ajaxurl, {
                    action: 'castconductor_clear_debug_logs',
                    nonce: nonce
                }, function(response) {
                    if (response.success) {
                        location.reload();
                    }
                });
            });
        });
        </script>
        <?php
    }
}

// Initialize
new CastConductor_Debug();
