<?php
/**
 * Cast Conductor Proprietary License v5
 * SPDX-License-Identifier: LicenseRef-CastConductor-Proprietary-v5
 * 
 * Copyright (c) 2025 CastConductor.com. All Rights Reserved.
 * 
 * Fetch Proxy Controller
 * 
 * Proxies arbitrary JSON API requests to avoid CORS issues
 * Used by the Canvas Editor's Custom API URL feature
 */

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

class CastConductor_Fetch_Proxy_Controller extends WP_REST_Controller {
    
    /**
     * API namespace
     */
    protected $namespace = 'castconductor/v5';
    
    /**
     * API base route
     */
    protected $rest_base = 'proxy';
    
    /**
     * Register routes
     */
    public function register_routes() {
        // Fetch arbitrary JSON URL (POST to pass URL in body, avoiding URL encoding issues)
        register_rest_route($this->namespace, '/' . $this->rest_base . '/fetch', [
            [
                'methods' => 'POST',
                'callback' => [$this, 'fetch_url'],
                'permission_callback' => [$this, 'admin_permissions_check'],
                'args' => [
                    'url' => [
                        'required' => true,
                        'type' => 'string',
                        'description' => 'JSON API URL to fetch',
                        'validate_callback' => function($param) {
                            return filter_var($param, FILTER_VALIDATE_URL) !== false;
                        }
                    ],
                    'method' => [
                        'required' => false,
                        'type' => 'string',
                        'default' => 'GET',
                        'enum' => ['GET', 'POST']
                    ],
                    'headers' => [
                        'required' => false,
                        'type' => 'object',
                        'default' => []
                    ],
                    'auth' => [
                        'required' => false,
                        'type' => 'object',
                        'description' => 'Authentication configuration',
                        'default' => ['type' => 'none'],
                        'properties' => [
                            'type' => [
                                'type' => 'string',
                                'enum' => ['none', 'header', 'query', 'bearer', 'basic']
                            ],
                            'key_name' => ['type' => 'string'],
                            'key_value' => ['type' => 'string'],
                            'secret' => ['type' => 'string']
                        ]
                    ],
                    'body' => [
                        'required' => false,
                        'type' => 'string',
                        'default' => ''
                    ],
                    'timeout' => [
                        'required' => false,
                        'type' => 'integer',
                        'default' => 10,
                        'minimum' => 1,
                        'maximum' => 30
                    ]
                ]
            ]
        ]);
    }
    
    /**
     * Check if user has admin permissions
     * Allows: Administrators and Editors (edit_posts)
     */
    public function admin_permissions_check($request) {
        return current_user_can('manage_options') || current_user_can('edit_posts');
    }
    
    /**
     * Fetch JSON from arbitrary URL
     */
    public function fetch_url($request) {
        $url = $request->get_param('url');
        $method = $request->get_param('method') ?: 'GET';
        $headers = $request->get_param('headers') ?: [];
        $auth = $request->get_param('auth') ?: ['type' => 'none'];
        $body = $request->get_param('body') ?: '';
        $timeout = $request->get_param('timeout') ?: 10;
        
        // Process authentication configuration
        $auth_type = isset($auth['type']) ? $auth['type'] : 'none';
        $auth_key_name = isset($auth['key_name']) ? $auth['key_name'] : '';
        $auth_key_value = isset($auth['key_value']) ? $auth['key_value'] : '';
        $auth_secret = isset($auth['secret']) ? $auth['secret'] : '';
        
        // Apply authentication based on type
        switch ($auth_type) {
            case 'header':
                // API key in custom header (e.g., X-API-Key: abc123)
                if (!empty($auth_key_name) && !empty($auth_key_value)) {
                    $headers[$auth_key_name] = $auth_key_value;
                }
                break;
                
            case 'query':
                // API key as query parameter
                if (!empty($auth_key_name) && !empty($auth_key_value)) {
                    $separator = (strpos($url, '?') !== false) ? '&' : '?';
                    $url .= $separator . urlencode($auth_key_name) . '=' . urlencode($auth_key_value);
                }
                break;
                
            case 'bearer':
                // Bearer token authentication
                if (!empty($auth_key_value)) {
                    $headers['Authorization'] = 'Bearer ' . $auth_key_value;
                }
                break;
                
            case 'basic':
                // Basic auth (username:password encoded in base64)
                if (!empty($auth_key_value)) {
                    $credentials = $auth_key_value;
                    if (!empty($auth_secret)) {
                        $credentials .= ':' . $auth_secret;
                    }
                    $headers['Authorization'] = 'Basic ' . base64_encode($credentials);
                }
                break;
                
            case 'none':
            default:
                // No authentication
                break;
        }
        
        // Validate URL is HTTPS for security
        if (strpos($url, 'https://') !== 0) {
            // Allow HTTP only in development
            if (!defined('WP_DEBUG') || !WP_DEBUG) {
                if (strpos($url, 'http://') === 0) {
                    return new WP_Error(
                        'insecure_url',
                        'Only HTTPS URLs are allowed in production',
                        ['status' => 400]
                    );
                }
            }
        }
        
        // Build request args
        $args = [
            'method' => $method,
            'timeout' => $timeout,
            'headers' => array_merge([
                'Accept' => 'application/json',
                'User-Agent' => 'CastConductor/5.0 (WordPress Plugin)'
            ], (array) $headers)
        ];
        
        if ($method === 'POST' && !empty($body)) {
            $args['body'] = $body;
        }
        
        // Make the request
        $response = wp_remote_request($url, $args);
        
        if (is_wp_error($response)) {
            return new WP_Error(
                'request_failed',
                'Failed to fetch URL: ' . $response->get_error_message(),
                ['status' => 502]
            );
        }
        
        $status_code = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        
        // Check for HTTP errors
        if ($status_code >= 400) {
            return new WP_Error(
                'http_error',
                "Remote server returned HTTP {$status_code}",
                ['status' => $status_code]
            );
        }
        
        // Try to parse as JSON
        $data = json_decode($body, true);
        
        if (json_last_error() !== JSON_ERROR_NONE) {
            return new WP_Error(
                'invalid_json',
                'Response is not valid JSON: ' . json_last_error_msg(),
                ['status' => 422]
            );
        }
        
        // Return the proxied JSON data
        return rest_ensure_response($data);
    }
}

/**
 * Initialize the controller
 */
add_action('rest_api_init', function() {
    $controller = new CastConductor_Fetch_Proxy_Controller();
    $controller->register_routes();
});
