<?php
/**
 * Cast Conductor Proprietary License v5
 * SPDX-License-Identifier: LicenseRef-CastConductor-Proprietary-v5
 * 
 * Copyright (c) 2025 CastConductor.com. All Rights Reserved.
 * See LICENSE file or https://castconductor.com/eula for full terms.
 */

/**
 * Deep Link Controller - REST API for deep linking and Roku Feed export
 * 
 * Provides endpoints for:
 * - Resolving content IDs to playable media
 * - Exporting Roku Search/Direct Publisher feed
 * - Content ID generation and management
 * 
 * @since 5.6.9
 */

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

class CastConductor_Deep_Link_Controller extends WP_REST_Controller {
    
    /**
     * Namespace for REST routes
     */
    protected $namespace = 'castconductor/v5';
    
    /**
     * Base for REST routes
     */
    protected $rest_base = 'deep-link';
    
    /**
     * Register REST routes
     */
    public function register_routes() {
        // Resolve content ID to playable content (public - for Roku app)
        register_rest_route($this->namespace, '/' . $this->rest_base . '/resolve', array(
            array(
                'methods' => WP_REST_Server::READABLE,
                'callback' => array($this, 'resolve_content'),
                'permission_callback' => '__return_true', // Public endpoint for Roku
                'args' => array(
                    'content_id' => array(
                        'required' => true,
                        'type' => 'string',
                        'description' => 'Content ID to resolve (format: type:id)',
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'content_type' => array(
                        'required' => false,
                        'type' => 'string',
                        'default' => 'auto',
                        'description' => 'Content type hint',
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
            ),
        ));
        
        // Export Roku Feed (JSON format for Roku Direct Publisher)
        register_rest_route($this->namespace, '/' . $this->rest_base . '/roku-feed', array(
            array(
                'methods' => WP_REST_Server::READABLE,
                'callback' => array($this, 'export_roku_feed'),
                'permission_callback' => '__return_true', // Public endpoint for Roku crawler
                'args' => array(
                    'include_live' => array(
                        'required' => false,
                        'type' => 'boolean',
                        'default' => true,
                    ),
                    'include_videos' => array(
                        'required' => false,
                        'type' => 'boolean',
                        'default' => true,
                    ),
                    'max_items' => array(
                        'required' => false,
                        'type' => 'integer',
                        'default' => 100,
                        'minimum' => 1,
                        'maximum' => 500,
                    ),
                ),
            ),
        ));
        
        // Generate content ID for a content block (admin only)
        register_rest_route($this->namespace, '/' . $this->rest_base . '/generate-id', array(
            array(
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => array($this, 'generate_content_id'),
                'permission_callback' => array($this, 'admin_permission_check'),
                'args' => array(
                    'scene_id' => array(
                        'required' => true,
                        'type' => 'integer',
                    ),
                    'block_id' => array(
                        'required' => false,
                        'type' => 'integer',
                    ),
                    'layer_index' => array(
                        'required' => false,
                        'type' => 'integer',
                    ),
                    'content_type' => array(
                        'required' => false,
                        'type' => 'string',
                        'default' => 'video',
                    ),
                ),
            ),
        ));
    }
    
    /**
     * Check if user has admin permissions
     * Allows: Administrators and Editors (edit_posts)
     */
    public function admin_permission_check($request) {
        return current_user_can('manage_options') || current_user_can('edit_posts');
    }
    
    /**
     * Resolve content ID to playable media
     */
    public function resolve_content($request) {
        $content_id = $request->get_param('content_id');
        $content_type_hint = $request->get_param('content_type');
        
        // Parse content ID format: type:id
        $parts = explode(':', $content_id, 2);
        if (count($parts) === 2) {
            $type = $parts[0];
            $id = $parts[1];
        } else {
            // No colon - treat as raw ID
            $type = $content_type_hint !== 'auto' ? $content_type_hint : 'video';
            $id = $content_id;
        }
        
        // Route based on content type
        switch ($type) {
            case 'live':
                return $this->resolve_live_stream($id);
                
            case 'video':
                return $this->resolve_video_content($id);
                
            case 'podcast':
            case 'audio':
                return $this->resolve_audio_content($id);
                
            case 'series':
                return $this->resolve_series($id);
                
            case 'episode':
                return $this->resolve_episode($id);
                
            case 'scene':
                return $this->resolve_scene($id);
                
            case 'block':
                return $this->resolve_content_block($id);
                
            default:
                // Try to find content by ID
                return $this->resolve_generic($id);
        }
    }
    
    /**
     * Resolve live stream content
     */
    private function resolve_live_stream($id) {
        // Get stream settings
        $settings = get_option('castconductor_v5_settings', array());
        $stream_url = isset($settings['audio_stream_url']) ? $settings['audio_stream_url'] : '';
        $video_url = isset($settings['video_url']) ? $settings['video_url'] : '';
        $streaming_mode = isset($settings['streaming_mode']) ? $settings['streaming_mode'] : 'audio';
        
        if ($streaming_mode === 'video' && !empty($video_url)) {
            $media_url = $video_url;
            $media_type = 'video';
            $stream_format = $this->detect_stream_format($video_url);
        } else {
            $media_url = $stream_url;
            $media_type = 'audio';
            $stream_format = $this->detect_stream_format($stream_url);
        }
        
        if (empty($media_url)) {
            return new WP_Error('no_stream', 'No live stream configured', array('status' => 404));
        }
        
        $channel_name = isset($settings['channel_name']) ? $settings['channel_name'] : 'Live Stream';
        
        return rest_ensure_response(array(
            'id' => 'live:' . $id,
            'title' => $channel_name,
            'description' => 'Live streaming content',
            'media_url' => $media_url,
            'media_type' => $media_type,
            'stream_format' => $stream_format,
            'thumbnail' => isset($settings['logo_url']) ? $settings['logo_url'] : '',
            'duration' => 0, // Live content has no duration
        ));
    }
    
    /**
     * Resolve video content (from content block video layer)
     */
    private function resolve_video_content($id) {
        // Check if ID is a post ID (scene or content block)
        $post = get_post(intval($id));
        
        if (!$post) {
            return new WP_Error('not_found', 'Video content not found', array('status' => 404));
        }
        
        // Get content block canvas data
        $canvas_data = get_post_meta($post->ID, '_canvas_data', true);
        
        if (!empty($canvas_data)) {
            $canvas = maybe_unserialize($canvas_data);
            if (is_array($canvas) && isset($canvas['layers'])) {
                // Find first video layer
                foreach ($canvas['layers'] as $layer) {
                    if (isset($layer['kind']) && $layer['kind'] === 'video-layer') {
                        return rest_ensure_response(array(
                            'id' => 'video:' . $id,
                            'title' => $post->post_title,
                            'description' => $post->post_excerpt,
                            'media_url' => isset($layer['url']) ? $layer['url'] : '',
                            'media_type' => 'video',
                            'stream_format' => $this->detect_stream_format($layer['url'] ?? ''),
                            'thumbnail' => isset($layer['poster']) ? $layer['poster'] : '',
                            'duration' => 0,
                        ));
                    }
                }
            }
        }
        
        // Check for scene background video
        $bg_type = get_post_meta($post->ID, '_scene_background_type', true);
        if ($bg_type === 'video') {
            $video_url = get_post_meta($post->ID, '_scene_video_url', true);
            if (!empty($video_url)) {
                return rest_ensure_response(array(
                    'id' => 'video:' . $id,
                    'title' => $post->post_title,
                    'description' => $post->post_excerpt,
                    'media_url' => $video_url,
                    'media_type' => 'video',
                    'stream_format' => $this->detect_stream_format($video_url),
                    'thumbnail' => get_the_post_thumbnail_url($post->ID, 'large'),
                    'duration' => 0,
                ));
            }
        }
        
        return new WP_Error('no_video', 'No video content found in this item', array('status' => 404));
    }
    
    /**
     * Resolve audio/podcast content
     */
    private function resolve_audio_content($id) {
        $post = get_post(intval($id));
        
        if (!$post) {
            return new WP_Error('not_found', 'Audio content not found', array('status' => 404));
        }
        
        // Look for audio in post meta or content
        $audio_url = get_post_meta($post->ID, '_audio_url', true);
        
        if (empty($audio_url)) {
            // Check canvas data for audio layer
            $canvas_data = get_post_meta($post->ID, '_canvas_data', true);
            if (!empty($canvas_data)) {
                $canvas = maybe_unserialize($canvas_data);
                if (is_array($canvas) && isset($canvas['layers'])) {
                    foreach ($canvas['layers'] as $layer) {
                        if (isset($layer['kind']) && $layer['kind'] === 'audio-layer') {
                            $audio_url = isset($layer['url']) ? $layer['url'] : '';
                            break;
                        }
                    }
                }
            }
        }
        
        if (empty($audio_url)) {
            return new WP_Error('no_audio', 'No audio content found', array('status' => 404));
        }
        
        return rest_ensure_response(array(
            'id' => 'audio:' . $id,
            'title' => $post->post_title,
            'description' => $post->post_excerpt,
            'media_url' => $audio_url,
            'media_type' => 'audio',
            'stream_format' => $this->detect_stream_format($audio_url),
            'thumbnail' => get_the_post_thumbnail_url($post->ID, 'large'),
            'duration' => intval(get_post_meta($post->ID, '_audio_duration', true)),
        ));
    }
    
    /**
     * Resolve series (returns series info for episode listing)
     */
    private function resolve_series($id) {
        // Check if ID is a slug or post ID
        $series = is_numeric($id) ? get_post(intval($id)) : get_page_by_path($id, OBJECT, 'cc_series');
        
        if (!$series) {
            return new WP_Error('not_found', 'Series not found', array('status' => 404));
        }
        
        return rest_ensure_response(array(
            'id' => 'series:' . $series->ID,
            'title' => $series->post_title,
            'description' => $series->post_excerpt,
            'media_url' => '', // Series don't have direct playback
            'media_type' => 'series',
            'stream_format' => '',
            'thumbnail' => get_the_post_thumbnail_url($series->ID, 'large'),
            'duration' => 0,
            'series_id' => strval($series->ID),
        ));
    }
    
    /**
     * Resolve episode
     */
    private function resolve_episode($id) {
        $post = get_post(intval($id));
        
        if (!$post) {
            return new WP_Error('not_found', 'Episode not found', array('status' => 404));
        }
        
        // Get episode media URL
        $media_url = get_post_meta($post->ID, '_episode_media_url', true);
        $media_type = get_post_meta($post->ID, '_episode_media_type', true) ?: 'video';
        
        return rest_ensure_response(array(
            'id' => 'episode:' . $id,
            'title' => $post->post_title,
            'description' => $post->post_excerpt,
            'media_url' => $media_url,
            'media_type' => $media_type,
            'stream_format' => $this->detect_stream_format($media_url),
            'thumbnail' => get_the_post_thumbnail_url($post->ID, 'large'),
            'duration' => intval(get_post_meta($post->ID, '_episode_duration', true)),
            'series_id' => get_post_meta($post->ID, '_episode_series_id', true),
            'episode_number' => intval(get_post_meta($post->ID, '_episode_number', true)),
        ));
    }
    
    /**
     * Resolve scene
     */
    private function resolve_scene($id) {
        $post = get_post(intval($id));
        
        if (!$post) {
            return new WP_Error('not_found', 'Scene not found', array('status' => 404));
        }
        
        // Check for video background first
        $bg_type = get_post_meta($post->ID, '_scene_background_type', true);
        if ($bg_type === 'video') {
            $video_url = get_post_meta($post->ID, '_scene_video_url', true);
            if (!empty($video_url)) {
                return rest_ensure_response(array(
                    'id' => 'scene:' . $id,
                    'title' => $post->post_title,
                    'description' => $post->post_excerpt,
                    'media_url' => $video_url,
                    'media_type' => 'video',
                    'stream_format' => $this->detect_stream_format($video_url),
                    'thumbnail' => get_the_post_thumbnail_url($post->ID, 'large'),
                    'duration' => 0,
                ));
            }
        }
        
        // Scene without video - return scene info
        return rest_ensure_response(array(
            'id' => 'scene:' . $id,
            'title' => $post->post_title,
            'description' => $post->post_excerpt,
            'media_url' => '',
            'media_type' => 'scene',
            'stream_format' => '',
            'thumbnail' => get_the_post_thumbnail_url($post->ID, 'large'),
            'duration' => 0,
        ));
    }
    
    /**
     * Resolve content block
     */
    private function resolve_content_block($id) {
        $post = get_post(intval($id));
        
        if (!$post) {
            return new WP_Error('not_found', 'Content block not found', array('status' => 404));
        }
        
        // Get canvas data and find video/audio layer
        $canvas_data = get_post_meta($post->ID, '_canvas_data', true);
        
        if (!empty($canvas_data)) {
            $canvas = maybe_unserialize($canvas_data);
            if (is_array($canvas) && isset($canvas['layers'])) {
                foreach ($canvas['layers'] as $layer) {
                    if (isset($layer['kind'])) {
                        if ($layer['kind'] === 'video-layer' && !empty($layer['url'])) {
                            return rest_ensure_response(array(
                                'id' => 'block:' . $id,
                                'title' => $post->post_title,
                                'description' => $post->post_excerpt,
                                'media_url' => $layer['url'],
                                'media_type' => 'video',
                                'stream_format' => $this->detect_stream_format($layer['url']),
                                'thumbnail' => isset($layer['poster']) ? $layer['poster'] : '',
                                'duration' => 0,
                            ));
                        }
                    }
                }
            }
        }
        
        return new WP_Error('no_media', 'No playable media in content block', array('status' => 404));
    }
    
    /**
     * Generic content resolution - try multiple methods
     */
    private function resolve_generic($id) {
        // Try video first
        $result = $this->resolve_video_content($id);
        if (!is_wp_error($result)) {
            return $result;
        }
        
        // Try audio
        $result = $this->resolve_audio_content($id);
        if (!is_wp_error($result)) {
            return $result;
        }
        
        // Try scene
        $result = $this->resolve_scene($id);
        if (!is_wp_error($result)) {
            return $result;
        }
        
        return new WP_Error('not_found', 'Content not found', array('status' => 404));
    }
    
    /**
     * Export Roku Feed for Direct Publisher / Universal Search
     */
    public function export_roku_feed($request) {
        $include_live = $request->get_param('include_live');
        $include_videos = $request->get_param('include_videos');
        $max_items = $request->get_param('max_items');
        
        // Get settings for provider info
        $settings = get_option('castconductor_v5_settings', array());
        $provider_name = isset($settings['channel_name']) ? $settings['channel_name'] : get_bloginfo('name');
        
        $feed = array(
            'providerName' => $provider_name,
            'lastUpdated' => gmdate('c'),
            'language' => substr(get_locale(), 0, 2),
            'movies' => array(),
            'series' => array(),
            'shortFormVideos' => array(),
            'liveFeeds' => array(),
        );
        
        // Add live stream if configured
        if ($include_live) {
            $stream_url = isset($settings['audio_stream_url']) ? $settings['audio_stream_url'] : '';
            $video_url = isset($settings['video_url']) ? $settings['video_url'] : '';
            $streaming_mode = isset($settings['streaming_mode']) ? $settings['streaming_mode'] : 'audio';
            
            $live_url = ($streaming_mode === 'video' && !empty($video_url)) ? $video_url : $stream_url;
            
            if (!empty($live_url)) {
                $feed['liveFeeds'][] = array(
                    'id' => 'live:default',
                    'title' => $provider_name . ' Live',
                    'content' => array(
                        'url' => $live_url,
                        'videoType' => ($streaming_mode === 'video') ? 'HLS' : 'AUDIO',
                    ),
                    'thumbnail' => isset($settings['logo_url']) ? $settings['logo_url'] : '',
                    'shortDescription' => 'Live streaming content from ' . $provider_name,
                );
            }
        }
        
        // Add video content from scenes with video backgrounds
        if ($include_videos) {
            $scenes_with_video = $this->get_scenes_with_video($max_items);
            foreach ($scenes_with_video as $scene) {
                $feed['shortFormVideos'][] = array(
                    'id' => 'video:' . $scene['id'],
                    'title' => $scene['title'],
                    'content' => array(
                        'dateAdded' => $scene['date_added'],
                        'videos' => array(
                            array(
                                'url' => $scene['video_url'],
                                'quality' => 'HD',
                                'videoType' => strtoupper($scene['stream_format']),
                            ),
                        ),
                        'duration' => $scene['duration'],
                    ),
                    'thumbnail' => $scene['thumbnail'],
                    'shortDescription' => $scene['description'],
                );
            }
            
            // Add video content blocks
            $video_blocks = $this->get_video_content_blocks($max_items);
            foreach ($video_blocks as $block) {
                $feed['shortFormVideos'][] = array(
                    'id' => 'video:' . $block['id'],
                    'title' => $block['title'],
                    'content' => array(
                        'dateAdded' => $block['date_added'],
                        'videos' => array(
                            array(
                                'url' => $block['video_url'],
                                'quality' => 'HD',
                                'videoType' => strtoupper($block['stream_format']),
                            ),
                        ),
                        'duration' => $block['duration'],
                    ),
                    'thumbnail' => $block['thumbnail'],
                    'shortDescription' => $block['description'],
                );
            }
        }
        
        return rest_ensure_response($feed);
    }
    
    /**
     * Get scenes that have video backgrounds
     */
    private function get_scenes_with_video($limit = 100) {
        $scenes = array();
        
        $query = new WP_Query(array(
            'post_type' => 'cc_scene',
            'posts_per_page' => $limit,
            'post_status' => 'publish',
            'meta_query' => array(
                array(
                    'key' => '_scene_background_type',
                    'value' => 'video',
                ),
            ),
        ));
        
        while ($query->have_posts()) {
            $query->the_post();
            $post = get_post();
            $video_url = get_post_meta($post->ID, '_scene_video_url', true);
            
            if (!empty($video_url)) {
                $scenes[] = array(
                    'id' => $post->ID,
                    'title' => $post->post_title,
                    'description' => $post->post_excerpt ?: wp_trim_words($post->post_content, 30),
                    'video_url' => $video_url,
                    'stream_format' => $this->detect_stream_format($video_url),
                    'thumbnail' => get_the_post_thumbnail_url($post->ID, 'large'),
                    'duration' => intval(get_post_meta($post->ID, '_video_duration', true)),
                    'date_added' => get_the_date('Y-m-d'),
                );
            }
        }
        
        wp_reset_postdata();
        
        return $scenes;
    }
    
    /**
     * Get content blocks with video layers
     */
    private function get_video_content_blocks($limit = 100) {
        $blocks = array();
        
        $query = new WP_Query(array(
            'post_type' => 'cc_content_block',
            'posts_per_page' => $limit,
            'post_status' => 'publish',
        ));
        
        while ($query->have_posts()) {
            $query->the_post();
            $post = get_post();
            
            $canvas_data = get_post_meta($post->ID, '_canvas_data', true);
            if (!empty($canvas_data)) {
                $canvas = maybe_unserialize($canvas_data);
                if (is_array($canvas) && isset($canvas['layers'])) {
                    foreach ($canvas['layers'] as $layer) {
                        if (isset($layer['kind']) && $layer['kind'] === 'video-layer' && !empty($layer['url'])) {
                            $blocks[] = array(
                                'id' => $post->ID,
                                'title' => $post->post_title,
                                'description' => $post->post_excerpt ?: wp_trim_words($post->post_content, 30),
                                'video_url' => $layer['url'],
                                'stream_format' => $this->detect_stream_format($layer['url']),
                                'thumbnail' => isset($layer['poster']) ? $layer['poster'] : get_the_post_thumbnail_url($post->ID, 'large'),
                                'duration' => 0,
                                'date_added' => get_the_date('Y-m-d'),
                            );
                            break; // Only include first video layer
                        }
                    }
                }
            }
        }
        
        wp_reset_postdata();
        
        return $blocks;
    }
    
    /**
     * Generate a content ID for a content block
     */
    public function generate_content_id($request) {
        $scene_id = $request->get_param('scene_id');
        $block_id = $request->get_param('block_id');
        $layer_index = $request->get_param('layer_index');
        $content_type = $request->get_param('content_type');
        
        // Generate content ID
        if ($block_id) {
            if ($layer_index !== null) {
                $content_id = $content_type . ':' . $block_id . '-' . $layer_index;
            } else {
                $content_id = $content_type . ':' . $block_id;
            }
        } else {
            $content_id = $content_type . ':' . $scene_id;
        }
        
        return rest_ensure_response(array(
            'content_id' => $content_id,
            'media_type' => $this->map_content_type_to_media_type($content_type),
        ));
    }
    
    /**
     * Detect stream format from URL
     */
    private function detect_stream_format($url) {
        if (empty($url)) {
            return '';
        }
        
        $url_lower = strtolower($url);
        
        if (strpos($url_lower, '.m3u8') !== false) {
            return 'hls';
        } else if (strpos($url_lower, '.mp4') !== false) {
            return 'mp4';
        } else if (strpos($url_lower, '.mpd') !== false) {
            return 'dash';
        } else if (strpos($url_lower, 'rtmp://') === 0) {
            return 'rtmp';
        } else if (strpos($url_lower, '.mp3') !== false || strpos($url_lower, '.aac') !== false) {
            return 'audio';
        }
        
        return 'hls'; // Default to HLS
    }
    
    /**
     * Map internal content type to Roku media type
     */
    private function map_content_type_to_media_type($content_type) {
        $map = array(
            'video' => 'shortFormVideo',
            'movie' => 'movie',
            'episode' => 'episode',
            'audio' => 'audio',
            'live' => 'live',
            'series' => 'series',
        );
        
        return isset($map[$content_type]) ? $map[$content_type] : 'shortFormVideo';
    }
}
