<?php
/**
 * AR Display AI - REST API
 */

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

require_once __DIR__ . '/class-ardisplay-ai-service.php';

if (!class_exists('Ardisplay_Ai_Rest')) {
    class Ardisplay_Ai_Rest {
        public function __construct()
        {
            add_action('rest_api_init', [$this, 'register_routes']);
        }

        public function register_routes(): void
        {
            register_rest_route('ar/v1', '/ardisplay_ai/jobs', [
                'methods' => 'POST',
                'callback' => [$this, 'create_job'],
                'permission_callback' => [$this, 'check_permissions'],
                'args' => [],
            ]);

            register_rest_route('ar/v1', '/ardisplay_ai/jobs/(?P<id>[^/]+)', [
                'methods' => 'GET',
                'callback' => [$this, 'get_job'],
                'permission_callback' => [$this, 'check_permissions'],
            ]);

            register_rest_route('ar/v1', '/provider/sf3d/webhook', [
                'methods' => 'POST',
                'callback' => [$this, 'provider_webhook'],
                'permission_callback' => '__return_true',
            ]);

            register_rest_route('ar/v1', '/ardisplay_ai/credits', [
                'methods' => 'GET',
                'callback' => [$this, 'get_user_credits'],
                'permission_callback' => [$this, 'check_permissions'],
            ]);

            register_rest_route('ar/v1', '/ardisplay_ai/credits/sync', [
                'methods' => 'POST',
                'callback' => [$this, 'sync_credits'],
                'permission_callback' => [$this, 'check_permissions'],
            ]);

            register_rest_route('ar/v1', '/ardisplay_ai/credits/webhook', [
                'methods' => 'POST',
                'callback' => [$this, 'receive_credit_webhook'],
                'permission_callback' => '__return_true', // Webhook has its own auth
            ]);
        }

        public function check_permissions(WP_REST_Request $request)
        {
            return current_user_can('edit_posts') && wp_verify_nonce($request->get_header('x-wp-nonce'), 'wp_rest');
        }

        public function get_user_credits(WP_REST_Request $request)
        {
            $user_id = get_current_user_id();
            if (!$user_id) {
                return new WP_REST_Response(['error' => 'User not logged in'], 401);
            }

            // Check if the credits system is available
            if (!class_exists('ARDisplay_AI_Proxy_Credits')) {
                return new WP_REST_Response([
                    'error' => 'AI Credits system not available',
                    'message' => 'Please ensure the AR Display AI plugin is installed and activated.'
                ], 503);
            }

            // Get user's AI credits token
            $credits_manager = new ARDisplay_AI_Proxy_Credits();
            $user_credits = $credits_manager->get_or_create_user_credits($user_id);
            
            if (!$user_credits) {
                return new WP_REST_Response(['error' => 'Failed to get user credits'], 500);
            }

            $available_credits = $user_credits->total_credits_purchased - $user_credits->total_credits_spent;
            $credit_cost = intval(get_option('ardisplay_ai_proxy_credit_cost_per_model', 10));

            return new WP_REST_Response([
                'ai_credits_token' => $user_credits->ai_credits_token,
                'total_credits_purchased' => $user_credits->total_credits_purchased,
                'total_credits_spent' => $user_credits->total_credits_spent,
                'available_credits' => $available_credits,
                'credit_cost_per_model' => $credit_cost,
                'can_generate' => $available_credits >= $credit_cost,
                'purchase_url' => 'https://ardisplay.ai/product/ai-model-credits/'
            ], 200);
        }

        public function sync_credits_from_remote()
        {
            $user_id = get_current_user_id();
            if (!$user_id) {
                return ['success' => false, 'error' => 'User not logged in'];
            }

            // Get AI credits token - either from database (if proxy plugin active) or wp_options (client sites)
            $ai_credits_token = '';
            $using_database = false;
            
            if (class_exists('ARDisplay_AI_Proxy_Credits')) {
                // Proxy plugin is active - get token from database
                $credits_manager = new ARDisplay_AI_Proxy_Credits();
                $user_credits = $credits_manager->get_or_create_user_credits($user_id);
                
                if ($user_credits && !empty($user_credits->ai_credits_token)) {
                    $ai_credits_token = $user_credits->ai_credits_token;
                    $using_database = true;
                }
            }
            
            // Fallback to wp_options if no token found in database (client sites without proxy plugin)
            if (empty($ai_credits_token)) {
                $ai_credits_token = get_option('ardisplay_ai_proxy_site_token', '');
            }
            
            if (empty($ai_credits_token)) {
                return ['success' => false, 'error' => 'No AI credits token found'];
            }

            // Query ardisplay.ai for current credit status
            $proxy_base = get_option('ardisplay_ai_proxy_base_url', 'https://ardisplay.ai');
            $proxy_base = rtrim($proxy_base, '/');
            $check_urls = $this->build_proxy_endpoint_urls($proxy_base, 'credits/check?token=' . urlencode($ai_credits_token));
            
            // Check if this is local development
            $host = parse_url($proxy_base, PHP_URL_HOST);
            $is_local = in_array($host, ['localhost', 'wordpress.test', '127.0.0.1']) || 
                        (substr($host, -5) === '.test') || 
                        (substr($host, -6) === '.local');

            $data = null;
            $last_error = 'Invalid response from credit server';
            $last_endpoint = '';

            foreach ($check_urls as $check_url) {
                $last_endpoint = $check_url;
                error_log('[AR AI] Syncing credits from: ' . $check_url);

                $response = wp_remote_get($check_url, [
                    'timeout' => 15,
                    'sslverify' => !$is_local // Disable SSL verification for local dev
                ]);

                if (is_wp_error($response)) {
                    $last_error = 'Failed to connect to credit server: ' . $response->get_error_message();
                    error_log('[AR AI] Credit sync failed (' . $check_url . '): ' . $response->get_error_message());
                    continue;
                }

                $code = wp_remote_retrieve_response_code($response);
                $body = wp_remote_retrieve_body($response);
                $decoded = json_decode($body, true);

                if ($code === 404 && is_array($decoded) && ($decoded['code'] ?? '') === 'rest_no_route') {
                    // Try next namespace fallback
                    $last_error = 'Remote proxy does not recognise credits endpoint (rest_no_route)';
                    error_log('[AR AI] Credit sync endpoint returned rest_no_route: ' . $check_url);
                    continue;
                }

                if ($code !== 200 || !isset($decoded['valid']) || !$decoded['valid']) {
                    $last_error = 'Invalid response from credit server';
                    error_log('[AR AI] Credit sync returned invalid response (HTTP ' . $code . ') from ' . $check_url . ': ' . $body);
                    continue;
                }

                $data = $decoded;
                break;
            }

            if (!$data) {
                if ($last_endpoint) {
                    $last_error .= ' (last endpoint: ' . $last_endpoint . ')';
                }
                return ['success' => false, 'error' => $last_error];
            }

            // Update local storage with remote credit values
            $available = intval($data['available'] ?? 0);
            
            if ($using_database) {
                // Update database if proxy plugin is active
                global $wpdb;
                $table_credits = $wpdb->prefix . 'ardisplay_ai_credits';
                
                // Calculate purchased and spent from available
                $current_spent = intval($user_credits->total_credits_spent);
                $new_purchased = $available + $current_spent;
                
                $result = $wpdb->update(
                    $table_credits,
                    [
                        'total_credits_purchased' => $new_purchased,
                        'updated_at' => current_time('mysql')
                    ],
                    ['user_id' => $user_id],
                    ['%d', '%s'],
                    ['%d']
                );

                if ($result === false) {
                    error_log('[AR AI] Failed to update local credits for user ' . $user_id);
                    return ['success' => false, 'error' => 'Failed to update local credits'];
                }
                
                error_log('[AR AI] Successfully synced credits for user ' . $user_id . ': ' . $available . ' available');

                return [
                    'success' => true,
                    'available_credits' => $available,
                    'total_credits_purchased' => $new_purchased,
                    'total_credits_spent' => $current_spent
                ];
            } else {
                // Store in wp_options for client sites without proxy plugin
                $total_purchased = intval($data['total_credits_purchased'] ?? $data['total'] ?? $available);
                $total_spent = intval($data['total_credits_spent'] ?? $data['spent'] ?? max(0, $total_purchased - $available));

                update_option('ardisplay_ai_proxy_cached_credits', [
                    'available_credits' => $available,
                    'total_credits_purchased' => $total_purchased,
                    'total_credits_spent' => $total_spent,
                    // Legacy keys retained for backward compatibility
                    'available' => $available,
                    'total_purchased' => $total_purchased,
                    'total_spent' => $total_spent,
                    'updated_at' => current_time('mysql')
                ]);

                error_log('[AR AI] Successfully synced credits for user ' . $user_id . ': ' . $available . ' available (cached in options)');

                return [
                    'success' => true,
                    'available_credits' => $available,
                    'total_credits_purchased' => $total_purchased,
                    'total_credits_spent' => $total_spent
                ];
            }
        }

        public function sync_credits(WP_REST_Request $request)
        {
            $result = $this->sync_credits_from_remote();
            
            if ($result['success']) {
                return new WP_REST_Response([
                    'success' => true,
                    'message' => 'Credits synced successfully',
                    'data' => $result
                ], 200);
            } else {
                return new WP_REST_Response([
                    'success' => false,
                    'message' => $result['error'] ?? 'Failed to sync credits'
                ], 500);
            }
        }

        public function receive_credit_webhook(WP_REST_Request $request)
        {
            $payload = $request->get_json_params();
            $ai_credits_token = $request->get_header('X-ARDISPLAY-AI-Token');
            
            if (!$ai_credits_token) {
                error_log('[AR AI] Webhook received without token');
                return new WP_REST_Response(['error' => 'Missing authentication token'], 401);
            }
            
            $has_real_proxy = class_exists('ARDisplay_AI_Proxy_Credits') && method_exists('ARDisplay_AI_Proxy_Credits', 'get_user_credits_summary');

            // Extract credit data from payload
            $new_purchased = intval($payload['total_credits_purchased'] ?? 0);
            $new_spent = intval($payload['total_credits_spent'] ?? 0);
            $available = intval($payload['available_credits'] ?? 0);

            if ($has_real_proxy) {
                $credits_manager = new ARDisplay_AI_Proxy_Credits();
                global $wpdb;
                $table_credits = $wpdb->prefix . 'ardisplay_ai_credits';

                $user_record = $wpdb->get_row($wpdb->prepare(
                    "SELECT * FROM {$table_credits} WHERE ai_credits_token = %s",
                    $ai_credits_token
                ));

                if (!$user_record) {
                    error_log('[AR AI] Webhook received with invalid token: ' . $ai_credits_token);
                    return new WP_REST_Response(['error' => 'Invalid token'], 401);
                }

                error_log('[AR AI] Webhook updating credits for user ' . $user_record->user_id . ': purchased=' . $new_purchased . ', spent=' . $new_spent . ', available=' . $available);

                $result = $wpdb->update(
                    $table_credits,
                    [
                        'total_credits_purchased' => $new_purchased,
                        'total_credits_spent' => $new_spent,
                        'updated_at' => current_time('mysql')
                    ],
                    ['ai_credits_token' => $ai_credits_token],
                    ['%d', '%d', '%s'],
                    ['%s']
                );

                if ($result === false) {
                    error_log('[AR AI] Webhook failed to update credits for token: ' . $ai_credits_token);
                    return new WP_REST_Response(['error' => 'Failed to update credits'], 500);
                }

                error_log('[AR AI] Webhook successfully updated credits for user ' . $user_record->user_id);
            } else {
                // Client site without proxy database - update cached option
                $site_token = get_option('ardisplay_ai_proxy_site_token', '');
                if (!$site_token || $site_token !== $ai_credits_token) {
                    error_log('[AR AI] Webhook received with mismatched token for client site');
                    return new WP_REST_Response(['error' => 'Invalid token'], 401);
                }

                if ($new_purchased === 0 && $new_spent === 0 && $available === 0) {
                    error_log('[AR AI] Webhook payload missing credit totals, falling back to sync');
                    $this->sync_credits_from_remote();
                } else {
                    $computed_purchased = $new_purchased > 0 ? $new_purchased : ($available + $new_spent);
                    $computed_spent = $new_spent;
                    update_option('ardisplay_ai_proxy_cached_credits', [
                        'available_credits' => $available,
                        'total_credits_purchased' => $computed_purchased,
                        'total_credits_spent' => $computed_spent,
                        // legacy keys
                        'available' => $available,
                        'total_purchased' => $computed_purchased,
                        'total_spent' => $computed_spent,
                        'updated_at' => current_time('mysql')
                    ]);
                    error_log('[AR AI] Webhook updated cached credits for client site: purchased=' . $computed_purchased . ', spent=' . $computed_spent . ', available=' . $available);
                }
            }

            return new WP_REST_Response([
                'success' => true,
                'message' => 'Credits updated successfully'
            ], 200);
        }

        public function create_job(WP_REST_Request $request)
        {
            $params = $request->get_json_params();
            $post_id = isset($params['post_id']) ? intval($params['post_id']) : 0;
            $image_ids = isset($params['image_ids']) && is_array($params['image_ids']) ? array_map('intval', $params['image_ids']) : [];
            $gen_params = isset($params['params']) && is_array($params['params']) ? $params['params'] : [];
            if (!$post_id || empty($image_ids)) {
                return new WP_REST_Response(['message' => __('Missing post_id or image_ids', 'ar-for-wordpress')], 400);
            }

            // Check if the REAL credits system is available (not just the fallback stub)
            $has_real_proxy = class_exists('ARDisplay_AI_Proxy_Credits') && method_exists('ARDisplay_AI_Proxy_Credits', 'get_user_credits_summary');
            $user_id = get_current_user_id();
            
            if (!$user_id) {
                return new WP_REST_Response(['message' => __('User not logged in', 'ar-for-wordpress')], 401);
            }

            $credit_cost = intval(get_option('ardisplay_ai_proxy_credit_cost_per_model', 10));
            $proxy_base = 'https://ardisplay.ai';
            
            if ($has_real_proxy) {
                // Real proxy plugin active - use database credits
                $credits_manager = new ARDisplay_AI_Proxy_Credits();
                $user_credits = $credits_manager->get_or_create_user_credits($user_id);
                
                if (!$user_credits) {
                    return new WP_REST_Response(['message' => __('Failed to get user credits', 'ar-for-wordpress')], 500);
                }

                // Check if user has enough credits
                $available_credits = $user_credits->total_credits_purchased - $user_credits->total_credits_spent;
                
                if ($available_credits < $credit_cost) {
                    return new WP_REST_Response([
                        'message' => __('Insufficient credits to generate AI model', 'ar-for-wordpress'),
                        'available_credits' => $available_credits,
                        'required_credits' => $credit_cost,
                        'purchase_url' => 'https://ardisplay.ai/product/ai-model-credits/'
                    ], 402);
                }

                $ai_credits_token = $user_credits->ai_credits_token;
                if ($proxy_base === '' || $ai_credits_token === '') {
                    error_log('[AR AI] Missing proxy configuration: base or AI credits token');
                    return new WP_REST_Response(['message' => __('AI proxy not configured (base URL or AI credits token missing).', 'ar-for-wordpress')], 400);
                }
            } else {
                // Client site - use cached credits from wp_options
                $ai_credits_token = get_option('ardisplay_ai_proxy_site_token', '');
                
                // Check for wp-config.php fallback token
                if (empty($ai_credits_token) && defined('ARDISPLAY_AI_FALLBACK_TOKEN')) {
                    $ai_credits_token = ARDISPLAY_AI_FALLBACK_TOKEN;
                }
                
                if ($proxy_base === '' || $ai_credits_token === '') {
                    return new WP_REST_Response([
                        'message' => __('AI Credits system not available and fallback token not configured. Please install the AR Display AI plugin or configure a fallback token in wp-config.php.', 'ar-for-wordpress')
                    ], 503);
                }
                
                // Get cached credits from wp_options
                $cached_credits = get_option('ardisplay_ai_proxy_cached_credits', null);
                
                if ($cached_credits === null) {
                    // No cached credits - try to sync first
                    $this->sync_credits_from_remote();
                    $cached_credits = get_option('ardisplay_ai_proxy_cached_credits', null);
                }
                
                if ($cached_credits === null) {
                    return new WP_REST_Response([
                        'message' => __('Unable to retrieve credit information. Please try refreshing credits on the settings page.', 'ar-for-wordpress')
                    ], 500);
                }
                
                // Check if user has enough credits
                $available_credits = intval($cached_credits['available_credits'] ?? $cached_credits['available'] ?? 0);
                
                if ($available_credits < $credit_cost) {
                    return new WP_REST_Response([
                        'message' => __('Insufficient credits to generate AI model', 'ar-for-wordpress'),
                        'available_credits' => $available_credits,
                        'required_credits' => $credit_cost,
                        'purchase_url' => 'https://ardisplay.ai/product/ai-model-credits/'
                    ], 402);
                }
            }

            // Non-local: forward image URLs to proxy
            $image_urls = [];
            foreach ($image_ids as $aid) {
                $url = wp_get_attachment_url($aid);
                if ($url) {
                    $image_urls[] = $url;
                }
            }
            
            if (empty($image_urls)) {
                return new WP_REST_Response(['message' => __('No valid image URLs found', 'ar-for-wordpress')], 400);
            }

            $image_name = $this->build_image_name($image_ids, $image_urls);
            update_post_meta($post_id, '_ardisplay_ai_last_image_name', $image_name);
            update_post_meta($post_id, '_ardisplay_ai_ai_token', $ai_credits_token);
            update_post_meta($post_id, '_ardisplay_ai_job_user_id', $user_id);
            update_post_meta($post_id, '_ardisplay_ai_credits_spent', '0');

            // If local dev, forward image bytes directly to proxy (multipart)
            $host = parse_url(home_url(), PHP_URL_HOST);
            $is_local = in_array($host, ['localhost', 'wordpress.test', '127.0.0.1']) || 
                        (substr($host, -5) === '.test') || 
                        (substr($host, -6) === '.local') ||
                        (strpos($host, '.test') !== false) ||
                        (strpos($host, '.local') !== false);
            
            if ($is_local) {
                $file_paths = [];
                $valid_images = [];
                
                foreach ($image_ids as $aid) {
                    $path = get_attached_file($aid);
                    if ($path && file_exists($path)) {
                        $file_paths[] = $path;
                        $valid_images[] = $aid;
                    }
                }
                
                if (!empty($file_paths)) {
                    // Don't spend credits yet - wait for successful completion
                    $result = $this->forward_multipart_to_proxy($file_paths, rest_url('ar/v1/provider/sf3d/webhook'), $gen_params, $ai_credits_token);
                    
                    if (isset($result['error'])) {
                        // Request failed - no credits spent
                        return new WP_REST_Response(['message' => $result['error']], 500);
                    }
                    
                    if (($result['status'] ?? '') === 'succeeded' && !empty($result['result']['glb_url'])) {
                        // Only now spend credits since request succeeded
                        $has_real_proxy = class_exists('ARDisplay_AI_Proxy_Credits') && method_exists('ARDisplay_AI_Proxy_Credits', 'get_user_credits_summary');
                        
                        if ($has_real_proxy) {
                            $credits_manager = new ARDisplay_AI_Proxy_Credits();
                            $credits_manager->spend_credits($ai_credits_token, $image_name, home_url(), $result['job_id'] ?? null);
                            update_post_meta($post_id, '_ardisplay_ai_credits_spent', '1');
                        } else {
                            $this->maybe_spend_remote_credits($post_id, $ai_credits_token, $image_name, $result['job_id'] ?? null);
                        }
                        
                        if (!empty($result['job_id'])) {
                            update_post_meta($post_id, '_ardisplay_ai_job_id', sanitize_text_field($result['job_id']));
                            update_post_meta($post_id, '_ardisplay_ai_job_status', sanitize_text_field($result['status'] ?? 'succeeded'));
                        }

                        $remote_glb_url = esc_url_raw($result['result']['glb_url']);
                        $attachment_id = $this->download_and_attach_glb($remote_glb_url, $post_id);
                        if ($attachment_id) {
                            update_post_meta($post_id, '_ardisplay_ai_generated_glb', $attachment_id);
                            $local_glb_url = wp_get_attachment_url($attachment_id);
                            update_post_meta($post_id, '_glb_file', $local_glb_url);
                            return new WP_REST_Response([
                                'status' => 'succeeded',
                                'result' => ['glb_url' => $local_glb_url],
                            ], 200);
                        }
                        return new WP_REST_Response([
                            'status' => 'succeeded',
                            'result' => ['glb_url' => $remote_glb_url],
                        ], 200);
                    }
                    if (!empty($result['job_id'])) {
                        update_post_meta($post_id, '_ardisplay_ai_job_id', sanitize_text_field($result['job_id']));
                        update_post_meta($post_id, '_ardisplay_ai_job_status', sanitize_text_field($result['status'] ?? 'queued'));
                    }
                    return new WP_REST_Response($result, 200);
                } else {
                    // No valid local files found
                    return new WP_REST_Response([
                        'message' => __('Local development mode: No valid image files found. Please ensure images are properly uploaded.', 'ar-for-wordpress')
                    ], 400);
                }
            }
            
            // Non-local: forward image URLs to proxy
            $result = $this->forward_urls_to_proxy($image_urls, rest_url('ar/v1/provider/sf3d/webhook'), $gen_params, $ai_credits_token);
            
            if (isset($result['error'])) {
                // Request failed - no credits spent
                return new WP_REST_Response(['message' => $result['error']], 500);
            }
            
            if (($result['status'] ?? '') === 'succeeded' && !empty($result['result']['glb_url'])) {
                // Only now spend credits since request succeeded
                $has_real_proxy = class_exists('ARDisplay_AI_Proxy_Credits') && method_exists('ARDisplay_AI_Proxy_Credits', 'get_user_credits_summary');
                
                if ($has_real_proxy) {
                    $credits_manager = new ARDisplay_AI_Proxy_Credits();
                    $credits_manager->spend_credits($ai_credits_token, $image_name, home_url(), $result['job_id'] ?? null);
                    update_post_meta($post_id, '_ardisplay_ai_credits_spent', '1');
                } else {
                    $this->maybe_spend_remote_credits($post_id, $ai_credits_token, $image_name, $result['job_id'] ?? null);
                }
                
                if (!empty($result['job_id'])) {
                    update_post_meta($post_id, '_ardisplay_ai_job_id', sanitize_text_field($result['job_id']));
                    update_post_meta($post_id, '_ardisplay_ai_job_status', sanitize_text_field($result['status'] ?? 'succeeded'));
                }

                $remote_glb_url = esc_url_raw($result['result']['glb_url']);
                $attachment_id = $this->download_and_attach_glb($remote_glb_url, $post_id);
                if ($attachment_id) {
                    update_post_meta($post_id, '_ardisplay_ai_generated_glb', $attachment_id);
                    $local_glb_url = wp_get_attachment_url($attachment_id);
                    update_post_meta($post_id, '_glb_file', $local_glb_url);
                    return new WP_REST_Response([
                        'status' => 'succeeded',
                        'result' => ['glb_url' => $local_glb_url],
                    ], 200);
                }
                return new WP_REST_Response([
                    'status' => 'succeeded',
                    'result' => ['glb_url' => $remote_glb_url],
                ], 200);
            }
            if (!empty($result['job_id'])) {
                update_post_meta($post_id, '_ardisplay_ai_job_id', sanitize_text_field($result['job_id']));
                update_post_meta($post_id, '_ardisplay_ai_job_status', sanitize_text_field($result['status'] ?? 'queued'));
            }
            return new WP_REST_Response($result, 200);
        }

        public function get_job(WP_REST_Request $request)
        {
            $job_id = $request['id'];
            $service = new Ardisplay_Ai_Service();
            $result = $service->provider()->get_job(sanitize_text_field($job_id));

            if (($result['status'] ?? '') === 'succeeded') {
                $post = $this->find_post_by_meta('_ardisplay_ai_job_id', $job_id);
                if ($post) {
                    $token = get_post_meta($post->ID, '_ardisplay_ai_ai_token', true);
                    $image_name = get_post_meta($post->ID, '_ardisplay_ai_last_image_name', true) ?: __('AI Model Generation', 'ar-for-wordpress');
                    $this->maybe_spend_remote_credits($post->ID, $token, $image_name, $job_id);
                }
            }

            return new WP_REST_Response($result, 200);
        }

        public function provider_webhook(WP_REST_Request $request)
        {
            $payload = $request->get_json_params();
            $job_id = sanitize_text_field($payload['job_id'] ?? '');
            $status = sanitize_text_field($payload['status'] ?? '');
            $glb_url = isset($payload['result']['glb_url']) ? esc_url_raw($payload['result']['glb_url']) : '';
            if (!$job_id) {
                return new WP_REST_Response(['message' => 'Missing job_id'], 400);
            }

            // Find post by job id
            $post = $this->find_post_by_meta('_ardisplay_ai_job_id', $job_id);
            if (!$post) {
                return new WP_REST_Response(['message' => 'Job not found'], 404);
            }

            update_post_meta($post->ID, '_ardisplay_ai_job_status', $status);

            if ($status === 'succeeded' && $glb_url) {
                $attachment_id = $this->download_and_attach_glb($glb_url, $post->ID);
                if ($attachment_id) {
                    update_post_meta($post->ID, '_ardisplay_ai_generated_glb', $attachment_id);
                    // Also set as active GLB for viewing
                    update_post_meta($post->ID, '_glb_file', wp_get_attachment_url($attachment_id));
                }
            }

            if ($status === 'succeeded') {
                $token = get_post_meta($post->ID, '_ardisplay_ai_ai_token', true);
                $image_name = get_post_meta($post->ID, '_ardisplay_ai_last_image_name', true) ?: __('AI Model Generation', 'ar-for-wordpress');
                $this->maybe_spend_remote_credits($post->ID, $token, $image_name, $job_id);
            }

            return new WP_REST_Response(['ok' => true], 200);
        }

        private function find_post_by_meta(string $key, string $value)
        {
            $q = new WP_Query([
                'post_type' => 'armodels',
                'posts_per_page' => 1,
                'meta_query' => [
                    [ 'key' => $key, 'value' => $value, 'compare' => '=' ],
                ],
                'fields' => 'all',
            ]);
            return $q->have_posts() ? $q->posts[0] : null;
        }

        private function download_and_attach_glb(string $url, int $post_id): int
        {
            // Download to tmp then sideload into media
            require_once ABSPATH . 'wp-admin/includes/file.php';
            require_once ABSPATH . 'wp-admin/includes/media.php';
            require_once ABSPATH . 'wp-admin/includes/image.php';

            // Preferred: fetch via wp_remote_get and write to temp file to avoid SSL issues in download_url on local dev
            $response = wp_remote_get($url, [ 'timeout' => 120, 'sslverify' => false ]);
            if (is_wp_error($response)) {
                error_log('[AR AI] GLB fetch failed: ' . $response->get_error_message());
                return 0;
            }
            $body = wp_remote_retrieve_body($response);
            if ($body === '' || $body === null) {
                error_log('[AR AI] GLB fetch empty body');
                return 0;
            }
            $name = wp_basename(parse_url($url, PHP_URL_PATH) ?: ('model-' . $post_id . '.glb'));
            $tmp = wp_tempnam($name);
            if (!$tmp || file_put_contents($tmp, $body) === false) {
                error_log('[AR AI] GLB temp write failed');
                return 0;
            }
            $file = [ 'name' => $name, 'tmp_name' => $tmp, 'type' => 'model/gltf-binary' ];
            $attachment_id = media_handle_sideload($file, $post_id, 'AI generated 3D model');
            @unlink($tmp);
            if (is_wp_error($attachment_id)) {
                error_log('[AR AI] GLB sideload failed: ' . $attachment_id->get_error_message());
                return 0;
            }
            return intval($attachment_id);
        }

        private function build_image_name(array $image_ids, array $image_urls): string
        {
            $names = [];
            foreach (array_slice($image_ids, 0, 3) as $index => $aid) {
                $filename = basename(get_attached_file($aid) ?: '');
                if (!$filename && isset($image_urls[$index])) {
                    $filename = basename(parse_url($image_urls[$index], PHP_URL_PATH) ?: '');
                }
                if ($filename) {
                    $names[] = $filename;
                }
            }
            if (empty($names)) {
                foreach (array_slice($image_urls, 0, 3) as $url) {
                    $basename = basename(parse_url($url, PHP_URL_PATH) ?: '');
                    if ($basename) {
                        $names[] = $basename;
                    }
                }
            }
            if (empty($names)) {
                return __('AI Model Generation', 'ar-for-wordpress');
            }
            $name = implode(', ', $names);
            if (count($image_ids) > 3 || count($image_urls) > 3) {
                $name .= '...';
            }
            return $name;
        }

        private function spend_remote_credits(string $ai_credits_token, string $image_name, ?string $job_id = null): bool
        {
            if (!$ai_credits_token) {
                return false;
            }
            $proxy_base = get_option('ardisplay_ai_proxy_base_url', 'https://ardisplay.ai');
            $endpoint = rtrim($proxy_base, '/') . '/wp-json/ardisplay-ai-proxy/v1/credits/spend';
            $payload = [
                'image_name' => $image_name,
                'site_url' => home_url(),
            ];
            if ($job_id) {
                $payload['job_id'] = $job_id;
            }
            $response = wp_remote_post($endpoint, [
                'headers' => [
                    'Content-Type' => 'application/json',
                    'X-ARDISPLAY-AI-Token' => $ai_credits_token,
                ],
                'body' => wp_json_encode($payload),
                'timeout' => 15,
            ]);
            if (is_wp_error($response)) {
                error_log('[AR AI] Remote spend failed: ' . $response->get_error_message());
                return false;
            }
            $code = wp_remote_retrieve_response_code($response);
            if ($code >= 200 && $code < 300) {
                return true;
            }
            error_log('[AR AI] Remote spend returned HTTP ' . $code . ': ' . wp_remote_retrieve_body($response));
            return false;
        }

        private function refresh_remote_credit_cache(string $ai_credits_token): void
        {
            if (!$ai_credits_token) {
                return;
            }
            $proxy_base = get_option('ardisplay_ai_proxy_base_url', 'https://ardisplay.ai');
            $check_urls = $this->build_proxy_endpoint_urls($proxy_base, 'credits/check?token=' . urlencode($ai_credits_token));
            foreach ($check_urls as $check_url) {
                $response = wp_remote_get($check_url, [
                    'timeout' => 15,
                    'sslverify' => true,
                ]);
                if (is_wp_error($response)) {
                    continue;
                }
                $code = wp_remote_retrieve_response_code($response);
                $body = wp_remote_retrieve_body($response);
                $data = json_decode($body, true);
                if ($code !== 200 || !isset($data['valid']) || !$data['valid']) {
                    continue;
                }
                $available = intval($data['available'] ?? 0);
                $total_purchased = intval($data['total_credits_purchased'] ?? $data['total'] ?? $available);
                $total_spent = intval($data['total_credits_spent'] ?? $data['spent'] ?? max(0, $total_purchased - $available));
                update_option('ardisplay_ai_proxy_cached_credits', [
                    'available_credits' => $available,
                    'total_credits_purchased' => $total_purchased,
                    'total_credits_spent' => $total_spent,
                    'available' => $available,
                    'total_purchased' => $total_purchased,
                    'total_spent' => $total_spent,
                    'updated_at' => current_time('mysql')
                ]);
                return;
            }
        }

        private function maybe_spend_remote_credits(int $post_id, string $ai_credits_token, string $image_name, ?string $job_id = null): void
        {
            $has_real_proxy = class_exists('ARDisplay_AI_Proxy_Credits') && method_exists('ARDisplay_AI_Proxy_Credits', 'get_user_credits_summary');
            if ($has_real_proxy || !$ai_credits_token || get_post_meta($post_id, '_ardisplay_ai_credits_spent', true) === '1') {
                return;
            }
            if ($this->spend_remote_credits($ai_credits_token, $image_name, $job_id)) {
                update_post_meta($post_id, '_ardisplay_ai_credits_spent', '1');
                $this->refresh_remote_credit_cache($ai_credits_token);
            }
        }

        private function forward_multipart_to_proxy(array $file_paths, string $webhook, array $gen_params = [], string $ai_credits_token = ''): array
        {
            // Try to get the proxy base URL from the proxy plugin settings
            $proxy_base = '';
            if (class_exists('ARDisplay_AI_Proxy_Credits')) {
                $proxy_base = get_option('ardisplay_ai_proxy_base_url', 'https://ardisplay.ai');
            } else {
                // Fallback for when proxy plugin is not active
                $proxy_base = get_option('ardisplay_ai_proxy_base_url', 'https://ardisplay.ai');
            }
            
            $proxy_base = rtrim($proxy_base, '/');
            if (!$proxy_base || !$ai_credits_token) {
                return ['error' => 'Proxy not configured or missing AI credits token'];
            }
            
            // Check if this is local development
            $host = parse_url($proxy_base, PHP_URL_HOST);
            $is_local = in_array($host, ['localhost', 'wordpress.test', '127.0.0.1']) || 
                        (substr($host, -5) === '.test') || 
                        (substr($host, -6) === '.local') ||
                        (strpos($host, '.test') !== false) ||
                        (strpos($host, '.local') !== false);
            
            $endpoints = $this->build_proxy_endpoint_urls($proxy_base, 'jobs');
            $boundary = wp_generate_password(24, false);
            $headers = [
                'X-ARDISPLAY-AI-Token' => $ai_credits_token,
                'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
            ];
            $body = '';
            // webhook
            $body .= "--{$boundary}\r\n";
            $body .= "Content-Disposition: form-data; name=\"webhook\"\r\n\r\n{$webhook}\r\n";
            // optional params
            foreach ($gen_params as $k => $v) {
                if ($v === null || $v === '') { continue; }
                $v = is_scalar($v) ? (string) $v : wp_json_encode($v);
                $body .= "--{$boundary}\r\n";
                $body .= "Content-Disposition: form-data; name=\"params[{$k}]\"\r\n\r\n{$v}\r\n";
            }
            foreach ($file_paths as $path) {
                $name = basename($path);
                $contents = file_get_contents($path);
                if ($contents === false) { continue; }
                $body .= "--{$boundary}\r\n";
                $body .= "Content-Disposition: form-data; name=\"file[]\"; filename=\"{$name}\"\r\n";
                $body .= "Content-Type: application/octet-stream\r\n\r\n";
                $body .= $contents . "\r\n";
            }
            $body .= "--{$boundary}--\r\n";
            
            $request_args = [
                'headers' => $headers, 
                'body' => $body, 
                'timeout' => 180
            ];
            
            // Disable SSL verification for local development
            if ($is_local) {
                $request_args['sslverify'] = false;
            }
            
            $last_error = 'Failed to contact proxy server';
            $last_endpoint = '';
            $attempted_endpoints = [];
            foreach ($endpoints as $endpoint) {
                $last_endpoint = $endpoint;
                $attempted_endpoints[] = $endpoint;
                error_log('[AR AI] Multipart proxy attempt: ' . $endpoint);
                $response = wp_remote_post($endpoint, $request_args);
                if (is_wp_error($response)) {
                    $last_error = $response->get_error_message();
                    continue;
                }

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

                if ($code === 404 && is_array($data) && ($data['code'] ?? '') === 'rest_no_route') {
                    $last_error = 'Proxy endpoint not found (rest_no_route)';
                    error_log('[AR AI] Multipart proxy rest_no_route: ' . $endpoint);
                    continue;
                }

                if ($code >= 400) {
                    $last_error = $data['message'] ?? ('HTTP ' . $code);
                    error_log('[AR AI] Multipart proxy HTTP ' . $code . ' from ' . $endpoint . ': ' . $body);
                    continue;
                }

                return $data ?: [];
            }

            if ($last_endpoint) {
                $last_error .= ' (last endpoint: ' . $last_endpoint . ')';
            }
            
            // Include all attempted endpoints in error for debugging
            $last_error .= ' | Attempted: ' . implode(', ', array_slice($attempted_endpoints, 0, 5));
            if (count($attempted_endpoints) > 5) {
                $last_error .= ' ... (and ' . (count($attempted_endpoints) - 5) . ' more)';
            }

            return ['error' => $last_error, 'attempted_endpoints' => $attempted_endpoints];
        }

        private function forward_urls_to_proxy(array $image_urls, string $webhook, array $gen_params = [], string $ai_credits_token = ''): array
        {
            // Try to get the proxy base URL from the proxy plugin settings
            $proxy_base = '';
            if (class_exists('ARDisplay_AI_Proxy_Credits')) {
                $proxy_base = get_option('ardisplay_ai_proxy_base_url', 'https://ardisplay.ai');
            } else {
                // Fallback for when proxy plugin is not active
                $proxy_base = get_option('ardisplay_ai_proxy_base_url', 'https://ardisplay.ai');
            }
            
            $proxy_base = rtrim($proxy_base, '/');
            if (!$proxy_base || !$ai_credits_token) {
                return ['error' => 'Proxy not configured or missing AI credits token'];
            }
            
            // Check if this is local development
            $host = parse_url($proxy_base, PHP_URL_HOST);
            $is_local = in_array($host, ['localhost', 'wordpress.test', '127.0.0.1']) || 
                        (substr($host, -5) === '.test') || 
                        (substr($host, -6) === '.local') ||
                        (strpos($host, '.test') !== false) ||
                        (strpos($host, '.local') !== false);
            
            $endpoints = $this->build_proxy_endpoint_urls($proxy_base, 'jobs');
            $headers = [
                'X-ARDISPLAY-AI-Token' => $ai_credits_token,
                'Content-Type' => 'application/json',
            ];
            
            $body = [
                'images' => $image_urls,
                'webhook' => $webhook,
                'params' => $gen_params,
            ];
            
            $request_args = [
                'headers' => $headers,
                'body' => wp_json_encode($body),
                'timeout' => 180
            ];
            
            // Disable SSL verification for local development
            if ($is_local) {
                $request_args['sslverify'] = false;
            }
            
            $last_error = 'Failed to contact proxy server';
            $last_endpoint = '';
            $attempted_endpoints = [];
            foreach ($endpoints as $endpoint) {
                $last_endpoint = $endpoint;
                $attempted_endpoints[] = $endpoint;
                error_log('[AR AI] URL proxy attempt: ' . $endpoint);
                $response = wp_remote_post($endpoint, $request_args);
                
                if (is_wp_error($response)) {
                    $last_error = $response->get_error_message();
                    continue;
                }
                
                $code = wp_remote_retrieve_response_code($response);
                $body = wp_remote_retrieve_body($response);
                $data = json_decode($body, true);
                
                if ($code === 404 && is_array($data) && ($data['code'] ?? '') === 'rest_no_route') {
                    $last_error = 'Proxy endpoint not found (rest_no_route)';
                    error_log('[AR AI] URL proxy rest_no_route: ' . $endpoint);
                    continue;
                }
                
                if ($code >= 400) {
                    $last_error = $data['message'] ?? ('HTTP ' . $code);
                    error_log('[AR AI] URL proxy HTTP ' . $code . ' from ' . $endpoint . ': ' . $body);
                    continue;
                }
                
                return $data ?: [];
            }

            if ($last_endpoint) {
                $last_error .= ' (last endpoint: ' . $last_endpoint . ')';
            }
            
            // Include all attempted endpoints in error for debugging
            $last_error .= ' | Attempted: ' . implode(', ', array_slice($attempted_endpoints, 0, 5));
            if (count($attempted_endpoints) > 5) {
                $last_error .= ' ... (and ' . (count($attempted_endpoints) - 5) . ' more)';
            }

            return ['error' => $last_error, 'attempted_endpoints' => $attempted_endpoints];
        }

        private function build_proxy_endpoint_urls(string $proxy_base, string $path): array
        {
            $proxy_base = rtrim($proxy_base, '/');
            $path = '/' . ltrim($path, '/');
            $namespaces = [
                'ardisplay-ai-proxy/v1',
                'ardisplay-ai/v1',
                'ardisplay_ai-proxy/v1',
                'ardisplay_ai_proxy/v1',
            ];

            $urls = [];
            foreach ($namespaces as $ns) {
                $urls[] = $proxy_base . '/wp-json/' . $ns . $path;
                $urls[] = $proxy_base . '/wp-json/' . $ns . $path . '/';
                $urls[] = $proxy_base . '/?rest_route=/' . $ns . $path;
                $urls[] = $proxy_base . '/?rest_route=/' . $ns . $path . '/';
                $urls[] = $proxy_base . '/index.php?rest_route=/' . $ns . $path;
                $urls[] = $proxy_base . '/index.php?rest_route=/' . $ns . $path . '/';
            }

            return array_values(array_unique($urls));
        }
    }
}

// Bootstrap
new Ardisplay_Ai_Rest();


