<?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
 */

/**
 * API Controller: Content Management Endpoints
 * 
 * Handles shoutouts, sponsors, promos content retrieval
 */

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

class CastConductor_Content_Controller extends WP_REST_Controller {

    /**
     * API namespace
     */
    protected $namespace = 'castconductor/v5';

    /**
     * Base route
     */
    protected $rest_base = 'content';

    /**
     * Constructor (reserved for future dependency injection)
     */
    public function __construct() {}

    /**
     * Transform visual_config from admin editor into Roku-ready format
     * 
     * Converts the layers array into a format that Roku can render directly:
     * - static-text layers become text layer configs
     * - static-image layers become image layer configs
     * - qr-image layers become image layer configs with the QR URL
     * 
     * All coordinates are already in 1280x720 space from the admin editor.
     * Roku just needs to iterate and render.
     * 
     * @param array $visual_config The visual configuration from post meta
     * @param array $post_data The post data for token fallback (title, content, etc.)
     * @return array Roku-ready block configuration
     */
    private function transform_visual_config_for_roku($visual_config, $post_data = array()) {
        if (empty($visual_config) || !is_array($visual_config)) {
            return null;
        }
        
        $layers = isset($visual_config['layers']) ? $visual_config['layers'] : array();
        $layout = isset($visual_config['layout']) ? $visual_config['layout'] : array(
            'width' => 1280,
            'height' => 240,
            'x' => 0,
            'y' => 480
        );
        
        if (empty($layers)) {
            return null;
        }
        
        // Transform each layer into Roku-ready format
        $roku_layers = array();
        foreach ($layers as $layer) {
            if (!is_array($layer)) continue;
            
            $kind = isset($layer['kind']) ? $layer['kind'] : '';
            $roku_layer = array(
                'id' => isset($layer['id']) ? $layer['id'] : uniqid('layer_'),
                'kind' => $kind,
                'visible' => isset($layer['visible']) ? (bool)$layer['visible'] : true,
                'locked' => isset($layer['locked']) ? (bool)$layer['locked'] : false,
            );
            
            // Position and size (all values in 1280x720 space)
            $roku_layer['x'] = isset($layer['x']) ? (int)$layer['x'] : 0;
            $roku_layer['y'] = isset($layer['y']) ? (int)$layer['y'] : 0;
            $roku_layer['width'] = isset($layer['width']) ? (int)$layer['width'] : 200;
            $roku_layer['height'] = isset($layer['height']) ? (int)$layer['height'] : 50;
            
            // Type-specific properties
            switch ($kind) {
                case 'static-text':
                case 'text':
                    // Text content - already resolved, no tokens needed
                    $roku_layer['text'] = isset($layer['text']) ? $layer['text'] : '';
                    $roku_layer['font_size'] = isset($layer['font_size']) ? (int)$layer['font_size'] : 24;
                    $roku_layer['font_weight'] = isset($layer['font_weight']) ? $layer['font_weight'] : '400';
                    $roku_layer['color'] = isset($layer['color']) ? $layer['color'] : '#ffffff';
                    $roku_layer['text_align'] = isset($layer['text_align']) ? $layer['text_align'] : 'left';
                    
                    // Text shadow
                    if (isset($layer['text_shadow']) && is_array($layer['text_shadow'])) {
                        $roku_layer['text_shadow'] = array(
                            'x' => isset($layer['text_shadow']['x']) ? (int)$layer['text_shadow']['x'] : 0,
                            'y' => isset($layer['text_shadow']['y']) ? (int)$layer['text_shadow']['y'] : 0,
                            'blur' => isset($layer['text_shadow']['blur']) ? (int)$layer['text_shadow']['blur'] : 0,
                            'color' => isset($layer['text_shadow']['color']) ? $layer['text_shadow']['color'] : 'rgba(0,0,0,0.5)',
                        );
                    }
                    
                    // Scrolling
                    $roku_layer['scrolling'] = isset($layer['scrolling']) ? (bool)$layer['scrolling'] : false;
                    $roku_layer['scroll_speed'] = isset($layer['scroll_speed']) ? (int)$layer['scroll_speed'] : 60;
                    break;
                    
                case 'static-image':
                case 'image':
                case 'qr-image':
                    // Image URL - already resolved, no tokens needed
                    $roku_layer['url'] = isset($layer['url']) ? $layer['url'] : '';
                    $roku_layer['fit'] = isset($layer['fit']) ? $layer['fit'] : 'contain';
                    $roku_layer['border_radius'] = isset($layer['border_radius']) ? (int)$layer['border_radius'] : 0;
                    break;
                    
                default:
                    // Copy any other properties as-is for future layer types
                    foreach ($layer as $key => $value) {
                        if (!isset($roku_layer[$key])) {
                            $roku_layer[$key] = $value;
                        }
                    }
            }
            
            $roku_layers[] = $roku_layer;
        }
        
        // Build the complete Roku-ready block config
        return array(
            'layout' => array(
                'width' => isset($layout['width']) ? (int)$layout['width'] : 1280,
                'height' => isset($layout['height']) ? (int)$layout['height'] : 240,
                'x' => isset($layout['x']) ? (int)$layout['x'] : 0,
                'y' => isset($layout['y']) ? (int)$layout['y'] : 480,
            ),
            'layers' => $roku_layers,
            'background' => isset($visual_config['background']) ? $visual_config['background'] : null,
            'overlay' => isset($visual_config['overlay']) ? $visual_config['overlay'] : null,
            // Flag indicating this is pre-resolved (no token replacement needed)
            'pre_resolved' => true,
        );
    }

    /**
     * Register REST API routes
     */
    public function register_routes() {
        // Shoutouts endpoints
        register_rest_route('castconductor/v5', '/content/shoutouts/active', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_active_shoutouts'),
            'permission_callback' => '__return_true',
        ));
        
        // Sponsors endpoints
        register_rest_route('castconductor/v5', '/content/sponsors/active', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_active_sponsors'),
            'permission_callback' => '__return_true',
        ));
        
        // Promos endpoints
        register_rest_route('castconductor/v5', '/content/promos/active', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_active_promos'),
            'permission_callback' => '__return_true',
        ));
    }
    
    /**
     * Get active shoutouts
     */
    public function get_active_shoutouts($request) {
        $args = array(
            'post_type' => 'cc_shoutout',
            'post_status' => 'publish',
            'posts_per_page' => $request->get_param('limit') ?: 10,
            'orderby' => 'date',
            'order' => 'DESC'
        );
        
        $shoutouts = get_posts($args);
        $formatted_shoutouts = array();
        
        foreach ($shoutouts as $shoutout) {
            $name = get_post_meta($shoutout->ID, 'cc_shoutout_name', true);
            $location = get_post_meta($shoutout->ID, 'cc_shoutout_location', true);
            $featured_image_url = get_the_post_thumbnail_url($shoutout->ID, 'full');
            
            // Get visual config from post meta if it exists
            $visual_config_raw = get_post_meta($shoutout->ID, '_cc_visual_config', true);
            $visual_config = null;
            if ($visual_config_raw) {
                $visual_config = is_array($visual_config_raw) ? $visual_config_raw : json_decode($visual_config_raw, true);
            }
            
            // Apply fallback artwork if no featured image
            $artwork_url = $featured_image_url;
            if (!$artwork_url) {
                // Try to get the fallback artwork from options (set during activation wizard)
                $attachment_id = get_option('castconductor_default_shoutout_fallback_artwork');
                if ($attachment_id) {
                    $fallback_url = wp_get_attachment_url($attachment_id);
                    if ($fallback_url) {
                        $artwork_url = $fallback_url;
                    }
                }
                
                // Final fallback to default branding image if option not set
                if (!$artwork_url) {
                    $artwork_url = plugins_url('assets/images/branding-square.png', CASTCONDUCTOR_PLUGIN_DIR . 'castconductor-v5.php');
                }
            }
            
            $formatted_shoutouts[] = array(
                'id' => $shoutout->ID,
                'message' => $shoutout->post_content,
                'name' => $name,
                'location' => $location,
                'formatted_display' => $name . ' from ' . $location . ' says: ' . $shoutout->post_content,
                'timestamp' => $shoutout->post_date,
                'approved' => get_post_meta($shoutout->ID, 'cc_shoutout_approved', true),
                'featured_media_url' => $featured_image_url ? $featured_image_url : '',
                'artwork_url' => $artwork_url,
                'visual_config' => $visual_config,
                // Roku-ready block config (pre-resolved layers, no token replacement needed)
                'roku_block_config' => $this->transform_visual_config_for_roku($visual_config, array(
                    'title' => $name,
                    'content' => $shoutout->post_content,
                    'featured_image' => $artwork_url,
                )),
            );
        }
        
        return new WP_REST_Response(array(
            'success' => true,
            'data' => $formatted_shoutouts,
            'count' => count($formatted_shoutouts),
            'timestamp' => current_time('c')
        ), 200);
    }
    
    /**
     * Get active sponsors
     */
    public function get_active_sponsors($request) {
        $args = array(
            'post_type' => 'cc_sponsor',
            'post_status' => 'publish',
            'posts_per_page' => $request->get_param('limit') ?: 5,
            'orderby' => 'date',
            'order' => 'DESC'
        );
        
        $sponsors = get_posts($args);
        $formatted_sponsors = array();
        
        foreach ($sponsors as $sponsor) {
            $featured_image_url = get_the_post_thumbnail_url($sponsor->ID, 'full');
            
            // Get visual config from post meta if it exists
            $visual_config_raw = get_post_meta($sponsor->ID, '_cc_visual_config', true);
            $visual_config = null;
            if ($visual_config_raw) {
                $visual_config = is_array($visual_config_raw) ? $visual_config_raw : json_decode($visual_config_raw, true);
            }
            
            $formatted_sponsors[] = array(
                'id' => $sponsor->ID,
                'title' => $sponsor->post_title,
                'content' => $sponsor->post_content,
                'featured_media_url' => $featured_image_url,
                'frequency_weight' => 10, // Default weight per ENDPOINTS.md
                'visual_config' => $visual_config,
                // Roku-ready block config (pre-resolved layers, no token replacement needed)
                'roku_block_config' => $this->transform_visual_config_for_roku($visual_config, array(
                    'title' => $sponsor->post_title,
                    'content' => $sponsor->post_content,
                    'featured_image' => $featured_image_url,
                )),
            );
        }
        
        return new WP_REST_Response(array(
            'success' => true,
            'data' => $formatted_sponsors,
            'count' => count($formatted_sponsors),
            'timestamp' => current_time('c')
        ), 200);
    }
    
    /**
     * Get active promos
     */
    public function get_active_promos($request) {
        $args = array(
            'post_type' => 'cc_promo',
            'post_status' => 'publish',
            'posts_per_page' => $request->get_param('limit') ?: 5,
            'orderby' => 'date',
            'order' => 'DESC'
        );
        
        $promos = get_posts($args);
        $formatted_promos = array();
        
        foreach ($promos as $promo) {
            $featured_image_url = get_the_post_thumbnail_url($promo->ID, 'full');
            
            // Get visual config from post meta if it exists
            $visual_config_raw = get_post_meta($promo->ID, '_cc_visual_config', true);
            $visual_config = null;
            if ($visual_config_raw) {
                $visual_config = is_array($visual_config_raw) ? $visual_config_raw : json_decode($visual_config_raw, true);
            }
            
            $formatted_promos[] = array(
                'id' => $promo->ID,
                'title' => $promo->post_title,
                'content' => $promo->post_content,
                'featured_media_url' => $featured_image_url,
                'frequency_weight' => 10, // Default weight per ENDPOINTS.md
                'visual_config' => $visual_config,
                // Roku-ready block config (pre-resolved layers, no token replacement needed)
                'roku_block_config' => $this->transform_visual_config_for_roku($visual_config, array(
                    'title' => $promo->post_title,
                    'content' => $promo->post_content,
                    'featured_image' => $featured_image_url,
                )),
            );
        }
        
        return new WP_REST_Response(array(
            'success' => true,
            'data' => $formatted_promos,
            'count' => count($formatted_promos),
            'timestamp' => current_time('c')
        ), 200);
    }
}
