<?php

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

/**
 * VMO Real-time Call Management
 * WordPress REST API endpoints for Node.js voice service integration
 */
class VMO_Realtime_Call_Manager {
    
    private $active_calls = array();
    private $websocket_connections = array();
    
    public function __construct() {
        add_action('rest_api_init', array($this, 'register_rest_routes'));
        add_action('rest_api_init', array($this, 'setup_websocket_handler'));
        
        // Schedule cleanup of expired calls
        add_action('vmo_cleanup_expired_calls', array($this, 'cleanup_expired_calls'));
        
        if (!wp_next_scheduled('vmo_cleanup_expired_calls')) {
            wp_schedule_event(time(), 'hourly', 'vmo_cleanup_expired_calls');
        }
    }
    
    /**
     * Register REST API routes for Node.js integration
     */
    public function register_rest_routes() {
        $namespace = 'vmo/v1';
        
        // Incoming call notification
        register_rest_route($namespace, '/call-notification', array(
            'methods' => 'POST',
            'callback' => array($this, 'handle_call_notification'),
            'permission_callback' => array($this, 'verify_node_service'),
            'args' => array(
                'call_sid' => array('required' => true, 'type' => 'string'),
                'from_number' => array('required' => true, 'type' => 'string'),
                'to_number' => array('required' => true, 'type' => 'string'),
                'conference_name' => array('required' => true, 'type' => 'string')
            )
        ));
        
        // Conference status updates
        register_rest_route($namespace, '/conference-status', array(
            'methods' => 'POST',
            'callback' => array($this, 'handle_conference_status'),
            'permission_callback' => array($this, 'verify_node_service')
        ));
        
        // Conversation updates
        register_rest_route($namespace, '/conversation-update', array(
            'methods' => 'POST',
            'callback' => array($this, 'handle_conversation_update'),
            'permission_callback' => array($this, 'verify_node_service')
        ));
        
        // Business information for AI
        register_rest_route($namespace, '/business-info', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_business_info'),
            'permission_callback' => array($this, 'verify_node_service')
        ));
        
        // Call preferences
        register_rest_route($namespace, '/call-preferences', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_call_preferences'),
            'permission_callback' => array($this, 'verify_node_service')
        ));
        
        // Send SMS alert
        register_rest_route($namespace, '/send-sms-alert', array(
            'methods' => 'POST',
            'callback' => array($this, 'send_sms_alert'),
            'permission_callback' => array($this, 'verify_node_service')
        ));
        
        // Send push notification
        register_rest_route($namespace, '/send-push-alert', array(
            'methods' => 'POST',
            'callback' => array($this, 'send_push_alert'),
            'permission_callback' => array($this, 'verify_node_service')
        ));
        
        // Send email alert
        register_rest_route($namespace, '/send-email-alert', array(
            'methods' => 'POST',
            'callback' => array($this, 'send_email_alert'),
            'permission_callback' => array($this, 'verify_node_service')
        ));
        
        // WebSocket alert for live dashboard
        register_rest_route($namespace, '/websocket-alert', array(
            'methods' => 'POST',
            'callback' => array($this, 'send_websocket_alert'),
            'permission_callback' => array($this, 'verify_node_service')
        ));
        
        // Call controls for admin
        register_rest_route($namespace, '/call-controls/(?P<conference_sid>[a-zA-Z0-9_-]+)', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_call_controls'),
            'permission_callback' => function() { return current_user_can('manage_options'); }
        ));
        
        // Call completion logging
        register_rest_route($namespace, '/call-completion', array(
            'methods' => 'POST',
            'callback' => array($this, 'log_call_completion'),
            'permission_callback' => array($this, 'verify_node_service')
        ));
        
        // Test connection
        register_rest_route($namespace, '/test-connection', array(
            'methods' => 'GET',
            'callback' => array($this, 'test_connection'),
            'permission_callback' => array($this, 'verify_node_service')
        ));
        
        // Live call dashboard (admin only)
        register_rest_route($namespace, '/live-calls', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_live_calls'),
            'permission_callback' => function() { return current_user_can('manage_options'); }
        ));
        
        // Call control actions (admin only)
        register_rest_route($namespace, '/call-action', array(
            'methods' => 'POST',
            'callback' => array($this, 'handle_call_action'),
            'permission_callback' => function() { return current_user_can('manage_options'); }
        ));
    }
    
    /**
     * Handle incoming call notification from Node service
     */
    public function handle_call_notification($request) {
        $params = $request->get_json_params();
        
        $call_data = array(
            'call_sid' => sanitize_text_field($params['call_sid']),
            'from_number' => sanitize_text_field($params['from_number']),
            'to_number' => sanitize_text_field($params['to_number']),
            'conference_name' => sanitize_text_field($params['conference_name']),
            'status' => 'active',
            'start_time' => current_time('mysql'),
            'conversation' => array(),
            'ai_summary' => ''
        );
        
        // Store active call
        $this->active_calls[$params['call_sid']] = $call_data;
        
        // Save to database (enhanced business calls schema)
        global $wpdb;
        $calls_table = $wpdb->prefix . 'vmo_business_calls';
        $phones_table = $wpdb->prefix . 'vmo_business_phones';

        // Try to resolve owner (user_id) from destination number
        $owner_id = (int) $wpdb->get_var($wpdb->prepare(
            "SELECT user_id FROM {$phones_table} WHERE phone_number = %s LIMIT 1",
            $call_data['to_number']
        ));

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->insert($calls_table, array(
            'user_id' => $owner_id,
            'call_sid' => $call_data['call_sid'],
            'from_number' => $call_data['from_number'],
            'to_number' => $call_data['to_number'],
            'call_status' => $call_data['status'],
            'call_start_time' => $call_data['start_time'],
            'ai_summary' => $call_data['ai_summary'],
            'conference_sid' => $call_data['conference_name'],
            'last_activity' => current_time('mysql')
        ), array('%d','%s','%s','%s','%s','%s','%s','%s','%s'));
        
        // Send real-time alerts
        $this->send_real_time_alerts($call_data);
        
        // Auto-dial business owner if enabled
        $auto_dial = get_option('vmo_auto_dial_owner', false);
        if ($auto_dial) {
            $this->schedule_owner_dial($call_data);
        }
        
        return new WP_REST_Response(array(
            'success' => true,
            'message' => 'Call notification received',
            'call_id' => $call_data['call_sid']
        ), 200);
    }
    
    /**
     * Handle conference status updates
     */
    public function handle_conference_status($request) {
        $params = $request->get_json_params();
        
        $conference_sid = sanitize_text_field($params['conference_sid']);
        $event = sanitize_text_field($params['event']);
        $participant = sanitize_text_field($params['participant']);
        
        // Log conference event
        error_log("Conference {$conference_sid}: {$event} - {$participant}");
        
        // Update active call status
        foreach ($this->active_calls as $call_sid => &$call_data) {
            if ($call_data['conference_name'] === $conference_sid) {
                $call_data['events'][] = array(
                    'event' => $event,
                    'participant' => $participant,
                    'timestamp' => current_time('mysql')
                );
                break;
            }
        }
        
        return new WP_REST_Response(array('success' => true), 200);
    }
    
    /**
     * Handle conversation updates
     */
    public function handle_conversation_update($request) {
        $params = $request->get_json_params();
        
        $call_sid = sanitize_text_field($params['call_sid']);
        $user_text = sanitize_textarea_field($params['user_text']);
        $ai_text = sanitize_textarea_field($params['ai_text']);
        
        // Add to active call conversation and persist to logs
        if (isset($this->active_calls[$call_sid])) {
            $this->active_calls[$call_sid]['conversation'][] = array(
                'timestamp' => current_time('mysql'),
                'user' => $user_text,
                'ai' => $ai_text
            );

            // Update database
            global $wpdb;
            $calls_table = $wpdb->prefix . 'vmo_business_calls';
            $logs_table = $wpdb->prefix . 'vmo_call_logs';

            $call_id = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$calls_table} WHERE call_sid = %s LIMIT 1", $call_sid));
            if ($call_id) {
                if (!empty($user_text)) {
                    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                    $wpdb->insert($logs_table, array(
                        'call_id' => (int)$call_id,
                        'speaker' => 'user',
                        'message' => $user_text,
                        'timestamp' => current_time('mysql')
                    ), array('%d','%s','%s','%s'));
                }
                if (!empty($ai_text)) {
                    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                    $wpdb->insert($logs_table, array(
                        'call_id' => (int)$call_id,
                        'speaker' => 'ai',
                        'message' => $ai_text,
                        'timestamp' => current_time('mysql')
                    ), array('%d','%s','%s','%s'));
                }
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                $wpdb->update($calls_table, array('last_activity' => current_time('mysql')), array('id' => (int)$call_id), array('%s'), array('%d'));
            }
        }
        
        return new WP_REST_Response(array('success' => true), 200);
    }
    
    /**
     * Get business information for AI
     */
    public function get_business_info($request) {
        $business_name = get_option('vmo_business_name', get_bloginfo('name'));
        $business_description = get_option('vmo_business_description', '');
        $business_hours = get_option('vmo_business_hours', '');

        // Prefer per-user AI greeting if we can resolve the business owner by destination number
        $ai_prompt = '';
        $maybe_to = $request->get_param('to_number');
        if (empty($maybe_to)) {
            // Some integrations might pass headers instead
            $maybe_to = $request->get_header('x-vmo-to-number');
        }
        if (!empty($maybe_to)) {
            global $wpdb;
            $phones_table = $wpdb->prefix . 'vmo_business_phones';
            $owner_id = (int) $wpdb->get_var($wpdb->prepare(
                "SELECT user_id FROM {$phones_table} WHERE phone_number = %s LIMIT 1",
                $maybe_to
            ));
            if ($owner_id > 0) {
                $ai_prompt = get_user_meta($owner_id, 'vmo_ai_phone_greeting', true);
                if (empty($ai_prompt)) {
                    // Also check enhanced settings array where we mirror prompt
                    $settings = get_user_meta($owner_id, 'vmo_ai_receptionist_settings', true);
                    if (is_array($settings) && !empty($settings['prompt'])) {
                        $ai_prompt = $settings['prompt'];
                    }
                }
            }
        }
        // Fallbacks: current user (if any), then global option
        if (empty($ai_prompt)) {
            $uid = get_current_user_id();
            if ($uid) {
                $ai_prompt = get_user_meta($uid, 'vmo_ai_phone_greeting', true);
                if (empty($ai_prompt)) {
                    $settings = get_user_meta($uid, 'vmo_ai_receptionist_settings', true);
                    if (is_array($settings) && !empty($settings['prompt'])) {
                        $ai_prompt = $settings['prompt'];
                    }
                }
            }
        }
        if (empty($ai_prompt)) {
            $ai_prompt = get_option('vmo_ai_phone_prompt', '');
        }
        
        return new WP_REST_Response(array(
            'business_name' => $business_name,
            'business_description' => $business_description,
            'ai_prompt' => $ai_prompt,
            'business_hours' => $business_hours,
            'contact_info' => array(
                'website' => home_url(),
                'email' => get_option('admin_email')
            )
        ), 200);
    }
    
    /**
     * Get call preferences
     */
    public function get_call_preferences($request) {
        return new WP_REST_Response(array(
            'auto_dial_owner' => get_option('vmo_auto_dial_owner', false),
            'owner_phone' => get_option('vmo_owner_phone_number', ''),
            'dial_delay' => get_option('vmo_owner_dial_delay', 5), // seconds
            'enable_sms_alerts' => get_option('vmo_enable_sms_alerts', true),
            'enable_email_alerts' => get_option('vmo_enable_email_alerts', true),
            'enable_push_alerts' => get_option('vmo_enable_push_alerts', false)
        ), 200);
    }
    
    /**
     * Send SMS alert
     */
    public function send_sms_alert($request) {
        $params = $request->get_json_params();
        
        $owner_phone = get_option('vmo_owner_phone_number', '');
        if (empty($owner_phone) || !get_option('vmo_enable_sms_alerts', true)) {
            return new WP_REST_Response(array('success' => false, 'message' => 'SMS alerts disabled'), 200);
        }

        // ✅ TOKEN CHECK: Verify balance before sending SMS alert
        $user_id = get_current_user_id();
        if ($user_id && class_exists('VMO_Twilio_Token_Economics')) {
            if (!VMO_Twilio_Token_Economics::get_instance()->can_send_sms($user_id)) {
                return new WP_REST_Response(array('success' => false, 'message' => 'Insufficient tokens for SMS'), 402);
            }
        }
        
        // Use Twilio to send SMS
        try {
            require_once plugin_dir_path(__FILE__) . 'class-vmo-twilio-enhanced-client.php';
            $twilio_client = new VMO_Twilio_Enhanced_Client();
            
            $message = sanitize_text_field($params['message']);
            $result = $twilio_client->send_sms($owner_phone, $message);
            
            if ($result) {
                // Note: Token deduction happens inside $twilio_client->send_sms()
                return new WP_REST_Response(array('success' => true, 'message' => 'SMS sent'), 200);
            } else {
                return new WP_REST_Response(array('success' => false, 'message' => 'SMS failed'), 200);
            }
            
        } catch (Exception $e) {
            return new WP_REST_Response(array('success' => false, 'message' => $e->getMessage()), 500);
        }
    }
    
    /**
     * Queue an alert for polling clients and fall back to email when push providers are not configured.
     */
    public function send_push_alert($request) {
        $params = $request->get_json_params();

        $user_id = $params['user_id'] ?? 0;
        $title   = sanitize_text_field($params['title'] ?? 'Incoming Call');
        $body    = sanitize_text_field($params['body'] ?? '');
        $data    = $params['data'] ?? [];

        if (empty($user_id)) {
            return new WP_REST_Response(array('success' => false, 'message' => 'Missing user_id'), 400);
        }

        // Store alert as a transient so the polling endpoint can deliver it
        $alerts_key = 'vmo_push_alerts_' . intval($user_id);
        $existing = get_transient($alerts_key) ?: [];
        $existing[] = [
            'title' => $title,
            'body'  => $body,
            'data'  => $data,
            'time'  => current_time('mysql'),
        ];
        set_transient($alerts_key, $existing, 300); // Expire after 5 minutes

        // Also try wp_mail as fallback notification
        $user = get_user_by('ID', $user_id);
        if ($user && get_option('vmo_enable_email_alerts', true)) {
            wp_mail(
                $user->user_email,
                '[VMO] ' . $title,
                $body . "\n\nThis alert was sent because push notifications are not yet configured.",
                ['Content-Type: text/plain; charset=UTF-8']
            );
        }

        return new WP_REST_Response(array(
            'success' => true,
            'message' => 'Alert queued (transient + email fallback)',
            'delivery' => 'transient_polling'
        ), 200);
    }
    
    /**
     * Send email alert
     */
    public function send_email_alert($request) {
        $params = $request->get_json_params();
        
        if (!get_option('vmo_enable_email_alerts', true)) {
            return new WP_REST_Response(array('success' => false, 'message' => 'Email alerts disabled'), 200);
        }
        
        $to = get_option('admin_email');
        $subject = sanitize_text_field($params['subject']);
        $from_number = sanitize_text_field($params['from_number']);
        $call_sid = sanitize_text_field($params['call_sid']);
        
        $message = "You have an incoming call from {$from_number}.\n\n";
        $message .= "Call ID: {$call_sid}\n";
        $message .= "Time: " . current_time('F j, Y g:i a') . "\n\n";
        $message .= "Your AI assistant is handling the call. You can join by dialing your business number.\n\n";
        $message .= "View live calls: " . admin_url('admin.php?page=vmo-live-calls');
        
        $sent = wp_mail($to, $subject, $message);
        
        return new WP_REST_Response(array('success' => $sent), 200);
    }
    
    /**
     * Send WebSocket alert for live dashboard
     */
    public function send_websocket_alert($request) {
        $params = $request->get_json_params();
        
        // Store alert for WebSocket connections
        $alert_data = array(
            'type' => 'incoming_call',
            'call_sid' => sanitize_text_field($params['call_sid']),
            'from_number' => sanitize_text_field($params['from_number']),
            'conference_name' => sanitize_text_field($params['conference_name']),
            'timestamp' => current_time('mysql')
        );
        
        // In a real implementation, this would push to WebSocket connections
        // For now, store in transient for polling-based updates
        set_transient('vmo_live_call_alert_' . $params['call_sid'], $alert_data, 300); // 5 minutes
        
        return new WP_REST_Response(array('success' => true), 200);
    }
    
    /**
     * Get live calls for admin dashboard
     */
    public function get_live_calls($request) {
        global $wpdb;
        $calls_table = $wpdb->prefix . 'vmo_business_calls';
        $logs_table = $wpdb->prefix . 'vmo_call_logs';

        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $active_calls = $wpdb->get_results(
            "SELECT * FROM {$calls_table} 
             WHERE call_status = 'active' 
             ORDER BY call_start_time DESC"
        );

        $formatted_calls = array();
        foreach ($active_calls as $call) {
            $conversation_count = (int)$wpdb->get_var($wpdb->prepare(
                "SELECT COUNT(*) FROM {$logs_table} WHERE call_id = %d",
                $call->id
            ));

            $formatted_calls[] = array(
                'call_sid' => $call->call_sid,
                'from_number' => $call->from_number,
                'to_number' => $call->to_number,
                'conference_name' => $call->conference_sid,
                'start_time' => $call->call_start_time,
                'duration' => human_time_diff(strtotime($call->call_start_time)),
                'conversation_count' => $conversation_count,
                'last_activity' => $call->last_activity,
                'ai_summary' => $call->ai_summary
            );
        }

        return new WP_REST_Response($formatted_calls, 200);
    }

    /**
     * Get live controls and transcript state for a conference.
     */
    public function get_call_controls($request) {
        $conference_sid = sanitize_text_field($request['conference_sid'] ?? '');
        if ($conference_sid === '') {
            return new WP_REST_Response(array(
                'success' => false,
                'message' => 'Missing conference identifier',
            ), 400);
        }

        $call_context = $this->resolve_call_context('', $conference_sid);
        if (empty($call_context['call_sid'])) {
            return new WP_REST_Response(array(
                'success' => false,
                'message' => 'Call not found for conference',
                'conference_sid' => $conference_sid,
            ), 404);
        }

        $transcript_state = array(
            'transcript' => $call_context['transcript'],
            'ai_handled' => $call_context['ai_handled'],
            'status' => $call_context['status'],
        );

        if (class_exists('VMO_Twilio_Manager')) {
            $twilio_manager = VMO_Twilio_Manager::get_instance();
            if (method_exists($twilio_manager, 'get_call_transcript')) {
                $twilio_state = $twilio_manager->get_call_transcript($call_context['call_sid'], (int) $call_context['user_id']);
                if (is_array($twilio_state)) {
                    $transcript_state = array_merge($transcript_state, $twilio_state);
                }
            }
        }

        return new WP_REST_Response(array(
            'success' => true,
            'call_sid' => $call_context['call_sid'],
            'conference_sid' => $call_context['conference_sid'],
            'user_id' => (int) $call_context['user_id'],
            'from_number' => $call_context['from_number'],
            'to_number' => $call_context['to_number'],
            'ai_summary' => $call_context['ai_summary'],
            'start_time' => $call_context['start_time'],
            'status' => $transcript_state['status'] ?? $call_context['status'],
            'transcript' => $transcript_state['transcript'] ?? '',
            'ai_handled' => !empty($transcript_state['ai_handled']),
            'available_actions' => array('join', 'listen', 'whisper', 'barge', 'resume_ai'),
        ), 200);
    }

    /**
     * Resolve call context from the business call tables.
     */
    private function resolve_call_context($call_sid = '', $conference_sid = '') {
        global $wpdb;

        $context = array(
            'user_id' => 0,
            'call_sid' => sanitize_text_field((string) $call_sid),
            'conference_sid' => sanitize_text_field((string) $conference_sid),
            'from_number' => '',
            'to_number' => '',
            'status' => '',
            'transcript' => '',
            'ai_summary' => '',
            'ai_handled' => false,
            'start_time' => '',
        );

        $business_calls_table = $wpdb->prefix . 'vmo_business_calls';
        if ($wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $business_calls_table)) === $business_calls_table) {
            if ($conference_sid !== '') {
                $row = $wpdb->get_row($wpdb->prepare(
                    "SELECT user_id, call_sid, conference_sid, from_number, to_number, call_status, transcription, ai_summary, call_start_time
                     FROM {$business_calls_table}
                     WHERE conference_sid = %s
                     ORDER BY id DESC
                     LIMIT 1",
                    $conference_sid
                ), ARRAY_A);
            } elseif ($call_sid !== '') {
                $row = $wpdb->get_row($wpdb->prepare(
                    "SELECT user_id, call_sid, conference_sid, from_number, to_number, call_status, transcription, ai_summary, call_start_time
                     FROM {$business_calls_table}
                     WHERE call_sid = %s
                     ORDER BY id DESC
                     LIMIT 1",
                    $call_sid
                ), ARRAY_A);
            } else {
                $row = null;
            }

            if (is_array($row) && !empty($row)) {
                $context['user_id'] = (int) ($row['user_id'] ?? 0);
                $context['call_sid'] = sanitize_text_field((string) ($row['call_sid'] ?? $context['call_sid']));
                $context['conference_sid'] = sanitize_text_field((string) ($row['conference_sid'] ?? $context['conference_sid']));
                $context['from_number'] = sanitize_text_field((string) ($row['from_number'] ?? ''));
                $context['to_number'] = sanitize_text_field((string) ($row['to_number'] ?? ''));
                $context['status'] = sanitize_text_field((string) ($row['call_status'] ?? ''));
                $context['transcript'] = sanitize_textarea_field((string) ($row['transcription'] ?? ''));
                $context['ai_summary'] = sanitize_textarea_field((string) ($row['ai_summary'] ?? ''));
                $context['start_time'] = sanitize_text_field((string) ($row['call_start_time'] ?? ''));
            }
        }

        $phone_calls_table = $wpdb->prefix . 'vmo_phone_calls';
        if ($wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $phone_calls_table)) === $phone_calls_table) {
            if ($call_sid !== '' || $context['call_sid'] !== '') {
                $lookup_call_sid = $context['call_sid'] !== '' ? $context['call_sid'] : $call_sid;
                $phone_row = $wpdb->get_row($wpdb->prepare(
                    "SELECT user_id, call_sid, caller_number, status, transcript, topic, ai_handled, created_at
                     FROM {$phone_calls_table}
                     WHERE call_sid = %s
                     ORDER BY id DESC
                     LIMIT 1",
                    $lookup_call_sid
                ), ARRAY_A);
            } elseif ($conference_sid !== '' || $context['conference_sid'] !== '') {
                $lookup_conference_sid = $context['conference_sid'] !== '' ? $context['conference_sid'] : $conference_sid;
                $phone_row = $wpdb->get_row($wpdb->prepare(
                    "SELECT user_id, call_sid, caller_number, status, transcript, topic, ai_handled, created_at
                     FROM {$phone_calls_table}
                     WHERE topic = %s
                     ORDER BY id DESC
                     LIMIT 1",
                    'conference:' . $lookup_conference_sid
                ), ARRAY_A);
            } else {
                $phone_row = null;
            }

            if (is_array($phone_row) && !empty($phone_row)) {
                $context['user_id'] = (int) ($phone_row['user_id'] ?? $context['user_id']);
                $context['call_sid'] = sanitize_text_field((string) ($phone_row['call_sid'] ?? $context['call_sid']));
                $context['from_number'] = $context['from_number'] !== '' ? $context['from_number'] : sanitize_text_field((string) ($phone_row['caller_number'] ?? ''));
                $context['status'] = $context['status'] !== '' ? $context['status'] : sanitize_text_field((string) ($phone_row['status'] ?? ''));
                $context['transcript'] = $context['transcript'] !== '' ? $context['transcript'] : sanitize_textarea_field((string) ($phone_row['transcript'] ?? ''));
                $context['ai_handled'] = !empty($phone_row['ai_handled']);
                $context['start_time'] = $context['start_time'] !== '' ? $context['start_time'] : sanitize_text_field((string) ($phone_row['created_at'] ?? ''));

                if ($context['conference_sid'] === '') {
                    $topic = (string) ($phone_row['topic'] ?? '');
                    if (strpos($topic, 'conference:') === 0) {
                        $context['conference_sid'] = sanitize_text_field(substr($topic, 11));
                    }
                }
            }
        }

        return $context;
    }

    /**
     * Attempt call control via the optional Node bridge.
     */
    private function dispatch_call_action_to_node($action, $call_sid, $conference_name) {
        $node_service_url = trim((string) get_option('vmo_node_service_url', 'http://localhost:3000'));
        if ($node_service_url === '') {
            return array(
                'success' => false,
                'message' => 'Node service URL not configured',
            );
        }

        $response = wp_remote_post(untrailingslashit($node_service_url) . '/wordpress/call-control', array(
            'timeout' => 4,
            'body' => wp_json_encode(array(
                'action' => $action,
                'callSid' => $call_sid,
                'conferenceSid' => $conference_name,
            )),
            'headers' => array(
                'Content-Type' => 'application/json',
            ),
        ));

        if (is_wp_error($response)) {
            return array(
                'success' => false,
                'message' => $response->get_error_message(),
            );
        }

        $body = wp_remote_retrieve_body($response);
        $result = json_decode($body, true);
        if (!is_array($result)) {
            return array(
                'success' => false,
                'message' => 'Node service returned an invalid response',
            );
        }

        return $result;
    }
    
    /**
     * Handle call control actions
     */
    public function handle_call_action($request) {
        $params = $request->get_json_params();

        $action = sanitize_text_field($params['action'] ?? '');
        $call_sid = sanitize_text_field($params['call_sid'] ?? '');
        $conference_name = sanitize_text_field($params['conference_name'] ?? ($params['conference_sid'] ?? ''));
        $via = sanitize_text_field($params['via'] ?? 'auto');

        if (!in_array($action, array('join', 'listen', 'whisper', 'barge', 'resume_ai'), true)) {
            return new WP_REST_Response(array(
                'success' => false,
                'message' => 'Invalid action type',
            ), 400);
        }

        $call_context = $this->resolve_call_context($call_sid, $conference_name);
        if ($call_sid === '') {
            $call_sid = $call_context['call_sid'];
        }
        if ($conference_name === '') {
            $conference_name = $call_context['conference_sid'];
        }

        if ($call_sid === '') {
            return new WP_REST_Response(array(
                'success' => false,
                'message' => 'Missing call SID',
            ), 400);
        }

        $node_result = $this->dispatch_call_action_to_node($action, $call_sid, $conference_name);
        if (!empty($node_result['success'])) {
            return new WP_REST_Response($node_result, 200);
        }

        if (class_exists('VMO_Twilio_Manager')) {
            $user_id = !empty($call_context['user_id']) ? (int) $call_context['user_id'] : get_current_user_id();
            $twilio_manager = VMO_Twilio_Manager::get_instance();
            $result = $twilio_manager->call_action($action, $call_sid, $conference_name, $user_id, $via);

            if (!is_wp_error($result)) {
                if (!is_array($result)) {
                    $result = array('message' => 'Call action completed');
                }
                $result['success'] = true;
                $result['routed_via'] = 'twilio_fallback';
                if (!empty($node_result['message'])) {
                    $result['node_bridge_error'] = $node_result['message'];
                }

                return new WP_REST_Response($result, 200);
            }

            return new WP_REST_Response(array(
                'success' => false,
                'message' => $result->get_error_message(),
                'node_bridge_error' => $node_result['message'] ?? '',
            ), 500);
        }

        return new WP_REST_Response(array(
            'success' => false,
            'message' => $node_result['message'] ?? 'No call control backend available',
        ), 500);
    }
    
    /**
     * Log call completion
     */
    public function log_call_completion($request) {
        $params = $request->get_json_params();
        
        $call_sid = sanitize_text_field($params['call_sid']);
        $duration = intval($params['duration']);
        $transcript = sanitize_textarea_field($params['transcript']);
        $summary = sanitize_textarea_field($params['summary']);
        
        global $wpdb;
        $calls_table = $wpdb->prefix . 'vmo_business_calls';
        $recordings_table = $wpdb->prefix . 'vmo_call_recordings';

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->update($calls_table,
            array(
                'call_status' => 'completed',
                'call_end_time' => current_time('mysql'),
                'call_duration' => $duration,
                'transcription' => $transcript,
                'ai_summary' => $summary
            ),
            array('call_sid' => $call_sid),
            array('%s', '%s', '%d', '%s', '%s'),
            array('%s')
        );

        // Persist recording if provided
        if (!empty($params['recording_sid']) && !empty($params['recording_url'])) {
            $call_id = (int)$wpdb->get_var($wpdb->prepare("SELECT id FROM {$calls_table} WHERE call_sid = %s", $call_sid));
            if ($call_id) {
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                $wpdb->insert($recordings_table, array(
                    'call_id' => $call_id,
                    'recording_sid' => sanitize_text_field($params['recording_sid']),
                    'recording_url' => esc_url_raw($params['recording_url']),
                    'duration' => intval($params['recording_duration'] ?? 0)
                ), array('%d','%s','%s','%d'));
            }
        }
        
        // Remove from active calls
        unset($this->active_calls[$call_sid]);
        
        return new WP_REST_Response(array('success' => true), 200);
    }
    
    /**
     * Test connection from Node service
     */
    public function test_connection($request) {
        return new WP_REST_Response(array(
            'success' => true,
            'message' => 'WordPress connection successful',
            'timestamp' => current_time('mysql'),
            'wordpress_version' => get_bloginfo('version'),
            'plugin_version' => VMO_AI_BUILDER_VERSION
        ), 200);
    }
    
    /**
     * Verify requests from Node.js service
     */
    public function verify_node_service($request) {
        // Simple authentication - in production, use proper JWT or API keys
        $auth_header = $request->get_header('authorization');
        $expected_token = get_option('vmo_node_service_token', 'default_token');
        
        if ($auth_header && str_replace('Bearer ', '', $auth_header) === $expected_token) {
            return true;
        }
        
        // For development, allow localhost
        $origin = (string) ($request->get_header('origin') ?? '');
        if (strpos($origin, 'localhost') !== false || strpos($origin, '127.0.0.1') !== false) {
            return true;
        }
        
        return new WP_Error('auth_failed', 'Authentication required', array('status' => 401));
    }
    
    /**
     * Send real-time alerts
     */
    private function send_real_time_alerts($call_data) {
        // Schedule immediate alerts
        wp_schedule_single_event(time() + 1, 'vmo_send_call_alerts', array($call_data));
    }
    
    /**
     * Schedule business owner dial-in
     */
    private function schedule_owner_dial($call_data) {
        $delay = get_option('vmo_owner_dial_delay', 5);
        wp_schedule_single_event(time() + $delay, 'vmo_dial_owner', array($call_data));
    }
    
    /**
     * Setup real-time alert delivery via a lightweight REST polling endpoint.
     */
    public function setup_websocket_handler() {
        // WebSocket requires a persistent server process which WordPress cannot provide natively.
        // Instead, we register a lightweight REST polling endpoint that clients can hit every few seconds
        // to retrieve queued alerts (stored as transients by send_push_alert).
        register_rest_route('vmo-phone/v1', '/poll-alerts', [
            'methods'             => 'GET',
            'callback'            => [$this, 'poll_alerts'],
            'permission_callback' => function() {
                return is_user_logged_in();
            },
        ]);
    }

    /**
     * Polling endpoint: return and clear any queued push alerts for the current user.
     */
    public function poll_alerts($request) {
        $user_id = get_current_user_id();
        $alerts_key = 'vmo_push_alerts_' . $user_id;
        $alerts = get_transient($alerts_key) ?: [];

        if (!empty($alerts)) {
            delete_transient($alerts_key);
        }

        return new WP_REST_Response([
            'success' => true,
            'alerts'  => $alerts,
        ], 200);
    }
    
    /**
     * Cleanup expired calls
     */
    public function cleanup_expired_calls() {
        global $wpdb;
        $calls_table = $wpdb->prefix . 'vmo_business_calls';

        // Expire calls inactive for > 1 hour
        $threshold = date('Y-m-d H:i:s', strtotime('-1 hour'));
        $wpdb->query($wpdb->prepare(
            "UPDATE {$calls_table} SET call_status = 'expired' WHERE call_status = 'active' AND last_activity < %s",
            $threshold
        ));
        
        // Clean up active calls array
        foreach ($this->active_calls as $call_sid => $call_data) {
            if (strtotime($call_data['start_time']) < strtotime('-1 hour')) {
                unset($this->active_calls[$call_sid]);
            }
        }
    }
}

// Initialize the realtime call manager
new VMO_Realtime_Call_Manager();
