<?php
/**
 * Cast Conductor Proprietary License v5
 * SPDX-License-Identifier: LicenseRef-CastConductor-Proprietary-v5
 * 
 * Copyright (c) 2025 CastConductor.com. All Rights Reserved.
 * 
 * This file is part of Cast Conductor ("Software"). The Software and its source
 * code constitute proprietary, confidential, and trade secret information of
 * CastConductor.com ("Company"). Any access or use is governed strictly by the
 * Cast Conductor Proprietary License v5 ("License"). By installing, copying,
 * accessing, compiling, or otherwise using the Software you agree to be bound by
 * all terms of the License. If you do not agree, you must cease use immediately.
 * 
 * Key Terms (Summary – see full License for binding terms):
 *  1. No Redistribution: You may not publish, distribute, sublicense, rent,
 *     lease, transfer, sell, or otherwise make the Software (or any derivative)
 *     available to any third party without prior written consent of Company.
 *  2. No Modification: Modification, reverse engineering, decompilation, or
 *     disassembly is prohibited except to the limited extent expressly permitted
 *     by applicable law that cannot be contractually waived.
 *  3. Confidentiality: Treat all source code and related artifacts as Company
 *     Confidential Information. Maintain at least the same degree of care as for
 *     your own confidential materials, and not less than reasonable care.
 *  4. No Patent License: No express or implied patent rights are granted. Future
 *     patents (if any) are fully reserved.
 *  5. No Trademark License: Company names, marks, and logos may not be used
 *     without prior written permission.
 *  6. Limited Internal Use: Use is limited solely to internal evaluation and
 *     operation of licensed Cast Conductor deployments. Commercial hosting or
 *     resale as a service requires a separate written agreement.
 *  7. Telemetry & License Validation: The Software may periodically transmit a
 *     hashed installation identifier, domain (or site ID), plugin/app version,
 *     and a truncated (non-reversible) fragment of the license key solely to
 *     validate activation status and enforce licensing. This minimal "phone home"
 *     check contains no personal or content data. If optional telemetry is later
 *     introduced it will be limited to aggregate operational metrics (no PII),
 *     fully documented, and optionally disableable per published instructions.
 *  8. Third-Party Components: The Software may include open source components
 *     covered by their own licenses. See THIRD-PARTY-NOTICES.md. Those licenses
 *     govern their respective components; this License governs all remaining code.
 *  9. Export Compliance: You are responsible for compliance with all applicable
 *     export control and sanctions laws.
 * 10. Warranty Disclaimer: THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF
 *     ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO MERCHANTABILITY,
 *     FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT.
 * 11. Limitation of Liability: IN NO EVENT WILL COMPANY OR AUTHORS BE LIABLE FOR
 *     ANY INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL, EXEMPLARY, OR PUNITIVE
 *     DAMAGES, OR LOST PROFITS, EVEN IF ADVISED OF THE POSSIBILITY.
 * 12. Acceptance: Use of the Software constitutes acceptance of the License.
 * 13. Enforcement: Unauthorized reproduction or distribution may result in civil
 *     and criminal penalties and will be prosecuted to the maximum extent allowed
 *     by law.
 * 
 * Authoritative EULA: EULA-v5.1.md (repository root – private) and https://castconductor.com/eula
 * Precedence: If this summary conflicts with the EULA, the EULA governs.
 * Revision: Current EULA revision v5.1 (subject to update; check EULA for current enterprise thresholds).
 * 
 * Full License text available from: licensing@castconductor.com
 * Security reports: security@castconductor.com
 * Commercial inquiries: licensing@castconductor.com
 * 
 * END OF HEADER
 */

/**
 * CastConductor Live Data Integration Controller
 *
 * Provides real-time data integration with external APIs, live content synchronization,
 * caching strategies, and webhook handling for immediate content updates across all
 * connected Roku devices and platforms.
 *
 * @package CastConductor
 * @since 5.0.0
 */

class CastConductor_Live_Data_Integration_Controller {

    /**
     * Cache groups for different data types
     */
    const CACHE_GROUP_LIVE_DATA = 'cc_live_data';
    const CACHE_GROUP_API_RESPONSES = 'cc_api_responses';
    const CACHE_GROUP_WEBHOOKS = 'cc_webhooks';

    /**
     * Constructor
     */
    public function __construct() {
        add_action('rest_api_init', array($this, 'register_routes'));
        add_action('wp_loaded', array($this, 'setup_live_data_handlers'));
        add_action('castconductor_live_data_sync', array($this, 'perform_live_data_sync'));
        add_action('castconductor_cache_cleanup', array($this, 'perform_cache_cleanup'));
        
        // Webhook handling
        add_action('wp_ajax_nopriv_castconductor_webhook', array($this, 'handle_webhook'));
        add_action('wp_ajax_castconductor_webhook', array($this, 'handle_webhook'));
    }

    /**
     * Register REST API routes
     */
    public function register_routes() {
    $namespace = 'castconductor/v5';

        // Live data sync
        register_rest_route($namespace, '/live-data/sync', array(
            'methods' => 'POST',
            'callback' => array($this, 'trigger_live_sync'),
            'permission_callback' => array($this, 'check_admin_permissions'),
            'args' => array(
                'force_refresh' => array(
                    'required' => false,
                    'type' => 'boolean',
                    'default' => false,
                    'description' => 'Force refresh all cached data'
                ),
                'sync_sources' => array(
                    'required' => false,
                    'type' => 'array',
                    'description' => 'Specific data sources to sync'
                )
            )
        ));

        // Get live data status
        register_rest_route($namespace, '/live-data/status', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_live_data_status'),
            'permission_callback' => array($this, 'check_admin_permissions')
        ));

        // Live data sources management
        register_rest_route($namespace, '/live-data/sources', array(
            'methods' => array('GET', 'POST'),
            'callback' => array($this, 'manage_data_sources'),
            'permission_callback' => array($this, 'check_admin_permissions')
        ));

        // Individual data source
        register_rest_route($namespace, '/live-data/sources/(?P<source_id>[a-zA-Z0-9_-]+)', array(
            'methods' => array('GET', 'PUT', 'DELETE'),
            'callback' => array($this, 'manage_individual_source'),
            'permission_callback' => array($this, 'check_admin_permissions')
        ));

        // Test data source connection
        register_rest_route($namespace, '/live-data/sources/(?P<source_id>[a-zA-Z0-9_-]+)/test', array(
            'methods' => 'POST',
            'callback' => array($this, 'test_data_source'),
            'permission_callback' => array($this, 'check_admin_permissions')
        ));

        // Webhook endpoints
        register_rest_route($namespace, '/live-data/webhooks', array(
            'methods' => array('GET', 'POST'),
            'callback' => array($this, 'manage_webhooks'),
            'permission_callback' => array($this, 'check_admin_permissions')
        ));

        // Individual webhook
        register_rest_route($namespace, '/live-data/webhooks/(?P<webhook_id>[a-zA-Z0-9_-]+)', array(
            'methods' => array('GET', 'PUT', 'DELETE'),
            'callback' => array($this, 'manage_individual_webhook'),
            'permission_callback' => array($this, 'check_admin_permissions')
        ));

        // Public webhook receiver (no auth required)
        register_rest_route($namespace, '/live-data/webhook/(?P<webhook_token>[a-zA-Z0-9_-]+)', array(
            'methods' => array('POST', 'GET'),
            'callback' => array($this, 'receive_webhook'),
            'permission_callback' => '__return_true'
        ));

        // Cache management
        register_rest_route($namespace, '/live-data/cache', array(
            'methods' => array('GET', 'DELETE'),
            'callback' => array($this, 'manage_cache'),
            'permission_callback' => array($this, 'check_admin_permissions')
        ));

        // Live data analytics
        register_rest_route($namespace, '/live-data/analytics', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_live_data_analytics'),
            'permission_callback' => array($this, 'check_admin_permissions')
        ));

        // Integration settings
        register_rest_route($namespace, '/live-data/settings', array(
            'methods' => array('GET', 'POST'),
            'callback' => array($this, 'integration_settings'),
            'permission_callback' => array($this, 'check_admin_permissions')
        ));

        // Real-time content endpoint for Roku
        register_rest_route($namespace, '/live-data/content', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_live_content'),
            'permission_callback' => '__return_true',
            'args' => array(
                'container_id' => array(
                    'required' => false,
                    'type' => 'string',
                    'description' => 'Specific container ID to get content for'
                ),
                'content_types' => array(
                    'required' => false,
                    'type' => 'array',
                    'description' => 'Filter by content types'
                ),
                'fresh' => array(
                    'required' => false,
                    'type' => 'boolean',
                    'default' => false,
                    'description' => 'Get fresh data bypassing cache'
                )
            )
        ));
    }

    /**
     * Trigger live data synchronization
     */
    public function trigger_live_sync($request) {
        try {
            $params = $request->get_params();
            $force_refresh = $params['force_refresh'] ?? false;
            $sync_sources = $params['sync_sources'] ?? array();

            $sync_results = array();
            $sources = $this->get_active_data_sources();

            foreach ($sources as $source_id => $source_config) {
                // Skip if specific sources requested and this isn't one of them
                if (!empty($sync_sources) && !in_array($source_id, $sync_sources)) {
                    continue;
                }

                $result = $this->sync_data_source($source_id, $source_config, $force_refresh);
                $sync_results[$source_id] = $result;
            }

            // Update last sync timestamp
            update_option('castconductor_last_live_sync', current_time('mysql'));

            // Log sync activity
            $this->log_sync_activity('manual_sync', $sync_results);

            return rest_ensure_response(array(
                'success' => true,
                'sync_results' => $sync_results,
                'synced_at' => current_time('mysql'),
                'message' => 'Live data synchronization completed'
            ));

        } catch (Exception $e) {
            return new WP_Error('sync_failed', $e->getMessage(), array('status' => 500));
        }
    }

    /**
     * Get live data status
     */
    public function get_live_data_status($request) {
        try {
            $sources = $this->get_active_data_sources();
            $status_info = array();

            foreach ($sources as $source_id => $source_config) {
                $last_sync = get_option("castconductor_source_last_sync_{$source_id}");
                $last_error = get_option("castconductor_source_last_error_{$source_id}");
                $sync_count = get_option("castconductor_source_sync_count_{$source_id}", 0);

                $status_info[$source_id] = array(
                    'name' => $source_config['name'],
                    'type' => $source_config['type'],
                    'status' => $this->get_source_health_status($source_id),
                    'last_sync' => $last_sync,
                    'last_error' => $last_error,
                    'sync_count' => intval($sync_count),
                    'cache_status' => $this->get_cache_status($source_id),
                    'next_sync' => $this->get_next_sync_time($source_id, $source_config)
                );
            }

            // Overall system status
            $system_status = array(
                'total_sources' => count($sources),
                'active_sources' => count(array_filter($sources, function($s) { return $s['enabled']; })),
                'last_global_sync' => get_option('castconductor_last_live_sync'),
                'cache_size' => $this->get_total_cache_size(),
                'webhook_count' => $this->get_webhook_count(),
                'error_count' => $this->get_recent_error_count()
            );

            return rest_ensure_response(array(
                'success' => true,
                'system_status' => $system_status,
                'sources' => $status_info
            ));

        } catch (Exception $e) {
            return new WP_Error('status_failed', $e->getMessage(), array('status' => 500));
        }
    }

    /**
     * Manage data sources
     */
    public function manage_data_sources($request) {
        try {
            if ($request->get_method() === 'POST') {
                // Create new data source
                $params = $request->get_json_params();
                $source_id = $this->create_data_source($params);

                return rest_ensure_response(array(
                    'success' => true,
                    'source_id' => $source_id,
                    'message' => 'Data source created successfully'
                ));
            } else {
                // Get all data sources
                $sources = $this->get_all_data_sources();

                return rest_ensure_response(array(
                    'success' => true,
                    'sources' => $sources
                ));
            }

        } catch (Exception $e) {
            return new WP_Error('sources_failed', $e->getMessage(), array('status' => 500));
        }
    }

    /**
     * Manage individual data source
     */
    public function manage_individual_source($request) {
        try {
            $source_id = $request->get_param('source_id');
            $method = $request->get_method();

            switch ($method) {
                case 'GET':
                    $source = $this->get_data_source($source_id);
                    if (!$source) {
                        return new WP_Error('source_not_found', 'Data source not found', array('status' => 404));
                    }
                    return rest_ensure_response(array('success' => true, 'source' => $source));

                case 'PUT':
                    $params = $request->get_json_params();
                    $this->update_data_source($source_id, $params);
                    return rest_ensure_response(array('success' => true, 'message' => 'Data source updated'));

                case 'DELETE':
                    $this->delete_data_source($source_id);
                    return rest_ensure_response(array('success' => true, 'message' => 'Data source deleted'));

                default:
                    return new WP_Error('method_not_allowed', 'Method not allowed', array('status' => 405));
            }

        } catch (Exception $e) {
            return new WP_Error('source_operation_failed', $e->getMessage(), array('status' => 500));
        }
    }

    /**
     * Test data source connection
     */
    public function test_data_source($request) {
        try {
            $source_id = $request->get_param('source_id');
            $source = $this->get_data_source($source_id);

            if (!$source) {
                return new WP_Error('source_not_found', 'Data source not found', array('status' => 404));
            }

            $test_result = $this->perform_source_test($source);

            return rest_ensure_response(array(
                'success' => true,
                'test_result' => $test_result
            ));

        } catch (Exception $e) {
            return new WP_Error('test_failed', $e->getMessage(), array('status' => 500));
        }
    }

    /**
     * Get live content for Roku and other consumers
     */
    public function get_live_content($request) {
        try {
            $params = $request->get_params();
            $container_id = $params['container_id'] ?? null;
            $content_types = $params['content_types'] ?? array();
            $fresh = $params['fresh'] ?? false;

            // Build cache key
            $cache_key = 'live_content_' . md5(serialize(array(
                'container_id' => $container_id,
                'content_types' => $content_types
            )));

            // Try to get from cache first (unless fresh data requested)
            if (!$fresh) {
                $cached_content = wp_cache_get($cache_key, self::CACHE_GROUP_LIVE_DATA);
                if ($cached_content !== false) {
                    $cached_content['cached'] = true;
                    $cached_content['cache_time'] = wp_cache_get($cache_key . '_time', self::CACHE_GROUP_LIVE_DATA);
                    return rest_ensure_response($cached_content);
                }
            }

            // Get live content from database and external sources
            $content = $this->compile_live_content($container_id, $content_types);

            // Add metadata
            $response_data = array(
                'success' => true,
                'content' => $content,
                'generated_at' => current_time('mysql'),
                'cache_ttl' => $this->get_content_cache_ttl(),
                'sources_count' => count($this->get_active_data_sources()),
                'cached' => false
            );

            // Cache the response
            wp_cache_set($cache_key, $response_data, self::CACHE_GROUP_LIVE_DATA, $this->get_content_cache_ttl());
            wp_cache_set($cache_key . '_time', current_time('mysql'), self::CACHE_GROUP_LIVE_DATA, $this->get_content_cache_ttl());

            return rest_ensure_response($response_data);

        } catch (Exception $e) {
            return new WP_Error('content_failed', $e->getMessage(), array('status' => 500));
        }
    }

    /**
     * Receive webhook
     */
    public function receive_webhook($request) {
        try {
            $webhook_token = $request->get_param('webhook_token');
            $webhook = $this->get_webhook_by_token($webhook_token);

            if (!$webhook) {
                return new WP_Error('invalid_webhook', 'Invalid webhook token', array('status' => 404));
            }

            // Verify webhook signature if configured
            if (!empty($webhook['secret'])) {
                $signature = $request->get_header('X-Signature-256') ?: $request->get_header('X-Hub-Signature-256');
                if (!$this->verify_webhook_signature($request->get_body(), $webhook['secret'], $signature)) {
                    return new WP_Error('invalid_signature', 'Invalid webhook signature', array('status' => 401));
                }
            }

            // Process webhook data
            $webhook_data = $request->get_json_params() ?: $request->get_params();
            $result = $this->process_webhook_data($webhook, $webhook_data);

            // Log webhook activity
            $this->log_webhook_activity($webhook['id'], $webhook_data, $result);

            // Trigger immediate content sync if configured
            if (!empty($webhook['trigger_sync'])) {
                wp_schedule_single_event(time() + 5, 'castconductor_live_data_sync');
            }

            return rest_ensure_response(array(
                'success' => true,
                'webhook_id' => $webhook['id'],
                'processed' => $result,
                'message' => 'Webhook processed successfully'
            ));

        } catch (Exception $e) {
            return new WP_Error('webhook_failed', $e->getMessage(), array('status' => 500));
        }
    }

    /**
     * Cache management
     */
    public function manage_cache($request) {
        try {
            if ($request->get_method() === 'DELETE') {
                // Clear all live data cache
                $this->clear_all_cache();
                
                return rest_ensure_response(array(
                    'success' => true,
                    'message' => 'All live data cache cleared'
                ));
            } else {
                // Get cache statistics
                $cache_stats = $this->get_cache_statistics();
                
                return rest_ensure_response(array(
                    'success' => true,
                    'cache_stats' => $cache_stats
                ));
            }

        } catch (Exception $e) {
            return new WP_Error('cache_failed', $e->getMessage(), array('status' => 500));
        }
    }

    /**
     * Helper methods
     */

    /**
     * Check admin permissions
     * Allows: Administrators and Editors (edit_posts)
     */
    public function check_admin_permissions($request) {
        return current_user_can('manage_options') || current_user_can('edit_posts');
    }

    /**
     * Setup live data handlers
     */
    public function setup_live_data_handlers() {
        // Schedule regular sync if not already scheduled
        if (!wp_next_scheduled('castconductor_live_data_sync')) {
            $settings = get_option('castconductor_live_data_settings', array());
            $sync_interval = $settings['sync_interval'] ?? 'hourly';
            wp_schedule_event(time(), $sync_interval, 'castconductor_live_data_sync');
        }

        // Schedule cache cleanup
        if (!wp_next_scheduled('castconductor_cache_cleanup')) {
            wp_schedule_event(time() + 3600, 'daily', 'castconductor_cache_cleanup');
        }
    }

    /**
     * Get active data sources
     */
    private function get_active_data_sources() {
        $sources = get_option('castconductor_live_data_sources', array());
        return array_filter($sources, function($source) {
            return !empty($source['enabled']);
        });
    }

    /**
     * Sync individual data source
     */
    private function sync_data_source($source_id, $source_config, $force_refresh = false) {
        try {
            $start_time = microtime(true);
            
            // Check if we need to sync based on cache TTL
            if (!$force_refresh && !$this->should_sync_source($source_id, $source_config)) {
                return array(
                    'status' => 'skipped',
                    'reason' => 'Cache still valid',
                    'duration' => 0
                );
            }

            // Perform the actual sync based on source type
            $data = $this->fetch_source_data($source_config);
            
            if ($data === false) {
                throw new Exception('Failed to fetch data from source');
            }

            // Process and cache the data
            $processed_data = $this->process_source_data($source_id, $data, $source_config);
            $this->cache_source_data($source_id, $processed_data);

            // Update sync metadata
            $sync_duration = microtime(true) - $start_time;
            update_option("castconductor_source_last_sync_{$source_id}", current_time('mysql'));
            update_option("castconductor_source_sync_duration_{$source_id}", $sync_duration);
            update_option("castconductor_source_last_error_{$source_id}", '');
            
            $sync_count = get_option("castconductor_source_sync_count_{$source_id}", 0);
            update_option("castconductor_source_sync_count_{$source_id}", $sync_count + 1);

            return array(
                'status' => 'success',
                'records' => is_array($processed_data) ? count($processed_data) : 1,
                'duration' => round($sync_duration, 3)
            );

        } catch (Exception $e) {
            // Log error
            update_option("castconductor_source_last_error_{$source_id}", $e->getMessage());
            
            return array(
                'status' => 'error',
                'error' => $e->getMessage(),
                'duration' => isset($sync_duration) ? round($sync_duration, 3) : 0
            );
        }
    }

    /**
     * Fetch data from external source
     */
    private function fetch_source_data($source_config) {
        $type = $source_config['type'];
        $config = $source_config['config'];

        switch ($type) {
            case 'rest_api':
                return $this->fetch_rest_api_data($config);
            
            case 'rss_feed':
                return $this->fetch_rss_feed_data($config);
            
            case 'database':
                return $this->fetch_database_data($config);
            
            case 'file':
                return $this->fetch_file_data($config);
            
            default:
                throw new Exception("Unsupported source type: {$type}");
        }
    }

    /**
     * Fetch REST API data
     */
    private function fetch_rest_api_data($config) {
        $url = $config['url'];
        $headers = $config['headers'] ?? array();
        $timeout = $config['timeout'] ?? 30;

        $args = array(
            'timeout' => $timeout,
            'headers' => $headers
        );

        // Add authentication if configured
        if (!empty($config['auth_type'])) {
            switch ($config['auth_type']) {
                case 'bearer':
                    $args['headers']['Authorization'] = 'Bearer ' . $config['auth_token'];
                    break;
                case 'basic':
                    $args['headers']['Authorization'] = 'Basic ' . base64_encode($config['username'] . ':' . $config['password']);
                    break;
                case 'api_key':
                    $args['headers'][$config['api_key_header']] = $config['api_key'];
                    break;
            }
        }

        $response = wp_remote_get($url, $args);

        if (is_wp_error($response)) {
            throw new Exception('API request failed: ' . $response->get_error_message());
        }

        $status_code = wp_remote_retrieve_response_code($response);
        if ($status_code !== 200) {
            throw new Exception("API returned status code: {$status_code}");
        }

        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new Exception('Invalid JSON response from API');
        }

        return $data;
    }

    /**
     * Fetch RSS feed data
     */
    private function fetch_rss_feed_data($config) {
        $url = $config['url'];
        $limit = $config['limit'] ?? 10;

        $rss = fetch_feed($url);

        if (is_wp_error($rss)) {
            throw new Exception('RSS feed error: ' . $rss->get_error_message());
        }

        $items = $rss->get_items(0, $limit);
        $data = array();

        foreach ($items as $item) {
            $data[] = array(
                'title' => $item->get_title(),
                'link' => $item->get_link(),
                'description' => $item->get_description(),
                'date' => $item->get_date('c'),
                'author' => $item->get_author() ? $item->get_author()->get_name() : null
            );
        }

        return $data;
    }

    /**
     * Fetch database data
     */
    private function fetch_database_data($config) {
        global $wpdb;

        $query = $config['query'];
        $max_results = $config['max_results'] ?? 100;

        // Basic SQL injection protection
        if (preg_match('/\b(INSERT|UPDATE|DELETE|DROP|CREATE|ALTER)\b/i', $query)) {
            throw new Exception('Only SELECT queries are allowed');
        }

        // Add LIMIT if not present
        if (!preg_match('/\bLIMIT\b/i', $query)) {
            $query .= " LIMIT {$max_results}";
        }

        $results = $wpdb->get_results($query, ARRAY_A);

        if ($wpdb->last_error) {
            throw new Exception('Database query error: ' . $wpdb->last_error);
        }

        return $results;
    }

    /**
     * Fetch file data
     */
    private function fetch_file_data($config) {
        $file_path = $config['file_path'];
        $format = $config['format'] ?? 'json';

        if (!file_exists($file_path)) {
            throw new Exception('File not found: ' . $file_path);
        }

        $content = file_get_contents($file_path);

        switch ($format) {
            case 'json':
                $data = json_decode($content, true);
                if (json_last_error() !== JSON_ERROR_NONE) {
                    throw new Exception('Invalid JSON in file');
                }
                return $data;

            case 'csv':
                $lines = explode("\n", $content);
                $header = str_getcsv(array_shift($lines));
                $data = array();
                foreach ($lines as $line) {
                    if (trim($line)) {
                        $data[] = array_combine($header, str_getcsv($line));
                    }
                }
                return $data;

            case 'xml':
                $xml = simplexml_load_string($content);
                if (!$xml) {
                    throw new Exception('Invalid XML in file');
                }
                return json_decode(json_encode($xml), true);

            default:
                return $content;
        }
    }

    /**
     * Process source data
     */
    private function process_source_data($source_id, $data, $source_config) {
        // Apply data transformations if configured
        $transformations = $source_config['transformations'] ?? array();

        foreach ($transformations as $transformation) {
            $data = $this->apply_transformation($data, $transformation);
        }

        // Apply data mapping to CastConductor content blocks
        if (!empty($source_config['content_mapping'])) {
            $data = $this->map_to_content_blocks($data, $source_config['content_mapping']);
        }

        return $data;
    }

    /**
     * Apply data transformation
     */
    private function apply_transformation($data, $transformation) {
        $type = $transformation['type'];

        switch ($type) {
            case 'filter':
                return $this->filter_data($data, $transformation['criteria']);
            
            case 'sort':
                return $this->sort_data($data, $transformation['field'], $transformation['order']);
            
            case 'limit':
                return array_slice($data, 0, $transformation['count']);
            
            case 'map_fields':
                return $this->map_fields($data, $transformation['mapping']);
            
            default:
                return $data;
        }
    }

    /**
     * Compile live content from all sources
     */
    private function compile_live_content($container_id = null, $content_types = array()) {
        $content = array();

        // Get content from database
        $db_content = $this->get_database_content($container_id, $content_types);
        $content = array_merge($content, $db_content);

        // Get content from cached live sources
        $live_content = $this->get_cached_live_content($content_types);
        $content = array_merge($content, $live_content);

        // Sort by priority and timestamp
        usort($content, function($a, $b) {
            $priority_diff = ($b['priority'] ?? 0) - ($a['priority'] ?? 0);
            if ($priority_diff !== 0) {
                return $priority_diff;
            }
            return strtotime($b['updated_at'] ?? '0') - strtotime($a['updated_at'] ?? '0');
        });

        return $content;
    }

    /**
     * Get database content
     */
    private function get_database_content($container_id, $content_types) {
        global $wpdb;

        $table_name = $wpdb->prefix . 'castconductor_content_blocks';
        $where_conditions = array("is_active = 1");
        $params = array();

        if ($container_id) {
            $where_conditions[] = "JSON_EXTRACT(metadata, '$.container_id') = %s";
            $params[] = $container_id;
        }

        if (!empty($content_types)) {
            $placeholders = implode(',', array_fill(0, count($content_types), '%s'));
            $where_conditions[] = "type IN ({$placeholders})";
            $params = array_merge($params, $content_types);
        }

        $where_clause = implode(' AND ', $where_conditions);
        
        $query = "SELECT * FROM {$table_name} WHERE {$where_clause} ORDER BY updated_at DESC";
        
        if (!empty($params)) {
            $query = $wpdb->prepare($query, $params);
        }

        $results = $wpdb->get_results($query, ARRAY_A);

        // Decode JSON content
        foreach ($results as &$result) {
            $result['content'] = json_decode($result['content'], true);
            $result['metadata'] = json_decode($result['metadata'], true);
        }

        return $results;
    }

    /**
     * Get cached live content
     */
    private function get_cached_live_content($content_types) {
        $sources = $this->get_active_data_sources();
        $live_content = array();

        foreach ($sources as $source_id => $source_config) {
            $cached_data = wp_cache_get("source_data_{$source_id}", self::CACHE_GROUP_LIVE_DATA);
            
            if ($cached_data !== false) {
                // Filter by content types if specified
                if (!empty($content_types) && !empty($source_config['content_types'])) {
                    $matching_types = array_intersect($content_types, $source_config['content_types']);
                    if (empty($matching_types)) {
                        continue;
                    }
                }

                $live_content = array_merge($live_content, $cached_data);
            }
        }

        return $live_content;
    }

    /**
     * Cache source data
     */
    private function cache_source_data($source_id, $data) {
        $cache_ttl = $this->get_source_cache_ttl($source_id);
        wp_cache_set("source_data_{$source_id}", $data, self::CACHE_GROUP_LIVE_DATA, $cache_ttl);
    }

    /**
     * Should sync source
     */
    private function should_sync_source($source_id, $source_config) {
        $cache_ttl = $this->get_source_cache_ttl($source_id);
        $last_sync = get_option("castconductor_source_last_sync_{$source_id}");

        if (!$last_sync) {
            return true;
        }

        $time_since_sync = time() - strtotime($last_sync);
        return $time_since_sync >= $cache_ttl;
    }

    /**
     * Get source cache TTL
     */
    private function get_source_cache_ttl($source_id) {
        $source = $this->get_data_source($source_id);
        return $source['cache_ttl'] ?? 3600; // Default 1 hour
    }

    /**
     * Get content cache TTL
     */
    private function get_content_cache_ttl() {
        $settings = get_option('castconductor_live_data_settings', array());
        return $settings['content_cache_ttl'] ?? 300; // Default 5 minutes
    }

    /**
     * Perform live data sync (scheduled task)
     */
    public function perform_live_data_sync() {
        $sources = $this->get_active_data_sources();
        $sync_results = array();

        foreach ($sources as $source_id => $source_config) {
            $result = $this->sync_data_source($source_id, $source_config, false);
            $sync_results[$source_id] = $result;
        }

        // Update last sync timestamp
        update_option('castconductor_last_live_sync', current_time('mysql'));

        // Log sync activity
        $this->log_sync_activity('scheduled_sync', $sync_results);

        // Clean up old cache entries
        $this->cleanup_expired_cache();
    }

    /**
     * Perform cache cleanup
     */
    public function perform_cache_cleanup() {
        $this->cleanup_expired_cache();
        $this->cleanup_old_logs();
    }

    /**
     * Log sync activity
     */
    private function log_sync_activity($type, $results) {
        $log_entry = array(
            'type' => $type,
            'timestamp' => current_time('mysql'),
            'results' => $results,
            'success_count' => count(array_filter($results, function($r) { return $r['status'] === 'success'; })),
            'error_count' => count(array_filter($results, function($r) { return $r['status'] === 'error'; }))
        );

        $log = get_option('castconductor_live_data_log', array());
        array_unshift($log, $log_entry);

        // Keep only last 100 entries
        $log = array_slice($log, 0, 100);
        
        update_option('castconductor_live_data_log', $log);
    }

    /**
     * Additional helper methods for complete functionality
     */

    private function get_all_data_sources() {
        return get_option('castconductor_live_data_sources', array());
    }

    private function get_data_source($source_id) {
        $sources = $this->get_all_data_sources();
        return $sources[$source_id] ?? false;
    }

    private function create_data_source($params) {
        $source_id = 'source_' . wp_generate_password(8, false);
        $sources = $this->get_all_data_sources();
        
        $sources[$source_id] = array_merge($params, array(
            'id' => $source_id,
            'created_at' => current_time('mysql'),
            'enabled' => true
        ));
        
        update_option('castconductor_live_data_sources', $sources);
        return $source_id;
    }

    private function update_data_source($source_id, $params) {
        $sources = $this->get_all_data_sources();
        if (!isset($sources[$source_id])) {
            throw new Exception('Data source not found');
        }
        
        $sources[$source_id] = array_merge($sources[$source_id], $params);
        $sources[$source_id]['updated_at'] = current_time('mysql');
        
        update_option('castconductor_live_data_sources', $sources);
    }

    private function delete_data_source($source_id) {
        $sources = $this->get_all_data_sources();
        if (!isset($sources[$source_id])) {
            throw new Exception('Data source not found');
        }
        
        unset($sources[$source_id]);
        update_option('castconductor_live_data_sources', $sources);
        
        // Clean up source-specific cache and options
        wp_cache_delete("source_data_{$source_id}", self::CACHE_GROUP_LIVE_DATA);
        delete_option("castconductor_source_last_sync_{$source_id}");
        delete_option("castconductor_source_last_error_{$source_id}");
        delete_option("castconductor_source_sync_count_{$source_id}");
        delete_option("castconductor_source_sync_duration_{$source_id}");
    }

    private function get_source_health_status($source_id) {
        $last_error = get_option("castconductor_source_last_error_{$source_id}");
        $last_sync = get_option("castconductor_source_last_sync_{$source_id}");
        
        if (!empty($last_error)) {
            return 'error';
        }
        
        if (!$last_sync) {
            return 'pending';
        }
        
        $source = $this->get_data_source($source_id);
        $cache_ttl = $source['cache_ttl'] ?? 3600;
        $time_since_sync = time() - strtotime($last_sync);
        
        if ($time_since_sync > $cache_ttl * 2) {
            return 'stale';
        }
        
        return 'healthy';
    }

    private function get_cache_status($source_id) {
        $cached_data = wp_cache_get("source_data_{$source_id}", self::CACHE_GROUP_LIVE_DATA);
        return $cached_data !== false ? 'cached' : 'empty';
    }

    private function get_next_sync_time($source_id, $source_config) {
        $last_sync = get_option("castconductor_source_last_sync_{$source_id}");
        if (!$last_sync) {
            return 'Pending';
        }
        
        $cache_ttl = $source_config['cache_ttl'] ?? 3600;
        $next_sync = strtotime($last_sync) + $cache_ttl;
        
        return date('Y-m-d H:i:s', $next_sync);
    }

    private function get_total_cache_size() {
        // This is a simplified implementation
        // In practice, you'd want to calculate actual cache size
        $sources = $this->get_active_data_sources();
        $cached_sources = 0;
        
        foreach ($sources as $source_id => $source_config) {
            if (wp_cache_get("source_data_{$source_id}", self::CACHE_GROUP_LIVE_DATA) !== false) {
                $cached_sources++;
            }
        }
        
        return $cached_sources . ' sources cached';
    }

    private function get_webhook_count() {
        $webhooks = get_option('castconductor_live_data_webhooks', array());
        return count($webhooks);
    }

    private function get_recent_error_count() {
        $log = get_option('castconductor_live_data_log', array());
        $recent_entries = array_slice($log, 0, 10);
        
        return array_sum(array_column($recent_entries, 'error_count'));
    }

    private function clear_all_cache() {
        wp_cache_flush_group(self::CACHE_GROUP_LIVE_DATA);
        wp_cache_flush_group(self::CACHE_GROUP_API_RESPONSES);
        wp_cache_flush_group(self::CACHE_GROUP_WEBHOOKS);
    }

    private function get_cache_statistics() {
        $sources = $this->get_active_data_sources();
        $stats = array(
            'total_sources' => count($sources),
            'cached_sources' => 0,
            'cache_hits' => get_option('castconductor_cache_hits', 0),
            'cache_misses' => get_option('castconductor_cache_misses', 0)
        );
        
        foreach ($sources as $source_id => $source_config) {
            if (wp_cache_get("source_data_{$source_id}", self::CACHE_GROUP_LIVE_DATA) !== false) {
                $stats['cached_sources']++;
            }
        }
        
        return $stats;
    }

    private function cleanup_expired_cache() {
        // WordPress handles cache expiration automatically for object cache
        // This is a placeholder for custom cleanup logic if needed
    }

    private function cleanup_old_logs() {
        $log = get_option('castconductor_live_data_log', array());
        $webhook_log = get_option('castconductor_webhook_log', array());
        
        // Keep only last 100 entries for each log
        if (count($log) > 100) {
            update_option('castconductor_live_data_log', array_slice($log, 0, 100));
        }
        
        if (count($webhook_log) > 100) {
            update_option('castconductor_webhook_log', array_slice($webhook_log, 0, 100));
        }
    }

    // Additional methods for webhook handling, data transformations, etc.
    // would be implemented here for a complete system
}
