<?php
/**
 * Settings Endpoint for BoostBot REST API.
 *
 * @package BoostBot
 */

// Prevent direct access to the file.
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
if (!defined('ABSPATH')) {
    exit;
}

/**
 * BoostBot_Settings_Endpoint class.
 *
 * Handles plugin settings management (Admin only).
 *
 * @since 1.0.0
 */
class BoostBot_Settings_Endpoint extends BoostBot_Base_Endpoint
{
    /**
     * The base path for this endpoint.
     *
     * @since 1.0.0
     * @access protected
     * @var string $rest_base
     */
    protected $rest_base = 'settings';

    /**
     * Register the routes for this endpoint.
     *
     * @since 1.0.0
     */
    public function register()
    {
        // GET /wp-json/boostbot/v1/settings - Get all settings
        $this->register_route(
            '',
            'GET',
            [$this, 'get_settings'],
            [$this, 'admin_access']
        );

        // POST /wp-json/boostbot/v1/settings - Update settings
        $this->register_route(
            '',
            'POST',
            [$this, 'update_settings'],
            [$this, 'admin_access']
        );

        // POST /wp-json/boostbot/v1/settings/reset - Reset to defaults
        $this->register_route(
            '/reset',
            'POST',
            [$this, 'reset_settings'],
            [$this, 'admin_access']
        );

        // GET /wp-json/boostbot/v1/settings/crm - Get CRM settings
        $this->register_route(
            '/crm',
            'GET',
            [$this, 'get_crm_settings'],
            [$this, 'admin_access']
        );


        // POST /wp-json/boostbot/v1/settings/crm/generate-key - Generate CRM API key
        $this->register_route(
            '/crm/generate-key',
            'POST',
            [$this, 'generate_crm_key'],
            [$this, 'admin_access']
        );

        // POST /wp-json/boostbot/v1/settings/crm/webhook - Save webhook config
        $this->register_route(
            '/crm/webhook',
            'POST',
            [$this, 'update_crm_webhook_settings'],
            [$this, 'admin_access']
        );

        // POST /wp-json/boostbot/v1/settings/crm/test-webhook - Test webhook
        $this->register_route(
            '/crm/test-webhook',
            'POST',
            [$this, 'test_crm_webhook'],
            [$this, 'admin_access']
        );

        // GET /wp-json/boostbot/v1/settings/connection-status
        $this->register_route(
            '/connection-status',
            'GET',
            [$this, 'get_connection_status'],
            [$this, 'admin_access']
        );
    }

    /**
     * Get all settings.
     *
     * @since 1.0.0
     * @param WP_REST_Request $request The REST request object.
     * @return WP_REST_Response The response.
     */
    public function get_settings($request)
    {
        BoostBot_Logger::debug('Getting settings');
        // Legacy subscription licensing is deprecated; settings are never frozen.
        $settings_frozen = false;

        // Get all settings
        $settings = BoostBot_Settings::get_all();
        // Credits backend base URL is hardcoded and must not be exposed in admin settings.
        unset( $settings['backend_base_url'] );

        // Override per-language keys with language-scoped values when requested.
        $request_language = '';
        if ( $request->has_param( 'language' ) ) {
            $request_language = BoostBot_Language::sanitize( $request->get_param( 'language' ) );
        }
        if ( ! empty( $request_language ) ) {
            foreach ( BoostBot_Settings::get_per_language_keys() as $plk ) {
                $settings[ $plk ] = BoostBot_Settings::get_for_language( $plk, $request_language, '' );
            }
        }
        // BYOK is no longer supported. Never expose or use BYOK keys.
        $settings['api_key_set'] = false;
        $settings['api_key']     = '';
        $settings['openai_api_key_set'] = false;
        $settings['openai_api_key']     = '';

        // Credits backend site API key (masked) + flags
        if ( ! empty( $settings['backend_site_api_key'] ) ) {
            $settings['backend_site_api_key_set'] = true;
            // IMPORTANT: Do NOT return a masked key in the same field that can be POSTed back.
            // Admin UI often POSTs the entire settings object, and a masked value like
            // "xxxxxxxxxx...yyyy" would overwrite the real per-site key and break all backend auth (401s).
            $settings['backend_site_api_key'] = '';
        } else {
            $settings['backend_site_api_key_set'] = false;
            $settings['backend_site_api_key']     = '';
        }

        // Decode JSON settings for the frontend
        if ( isset( $settings['wizard_progress'] ) && is_string( $settings['wizard_progress'] ) ) {
            $decoded = json_decode( $settings['wizard_progress'], true );
            $settings['wizard_progress'] = is_array( $decoded ) ? $decoded : array();
        }

        // Add license info
        $settings['license_status'] = 'free';
        $settings['settings_frozen'] = $settings_frozen;

        if (class_exists('BoostBot_License_Manager')) {
            $license_manager = new BoostBot_License_Manager();
            $settings['license_status'] = $license_manager->get_license_status();
        }

        // Add usage info
        if (class_exists('BoostBot_Usage_Tracker')) {
            $settings['usage'] = BoostBot_Usage_Tracker::get_usage();
            $settings['usage_percentage'] = BoostBot_Usage_Tracker::get_percentage();
        }

        return $this->success($settings);
    }

    /**
     * Update settings.
     *
     * @since 1.0.0
     * @param WP_REST_Request $request The REST request object.
     * @return WP_REST_Response|WP_Error The response or error.
     */
    public function update_settings($request)
    {
        BoostBot_Logger::debug('Updating settings');

        // Allowed settings to update
        $allowed_settings = [
            // Credits backend (Week 26)
            'backend_site_id'     => 'string',
            'backend_site_api_key' => 'string',
            'bot_name'         => 'string',
            'welcome_message'  => 'string',
            'primary_color'    => 'color',
            'accent_color'     => 'color',
            'position'         => 'string',
            'is_active'        => 'bool',
            // Setup wizard
            'onboarding_completed'    => 'bool',
            'wizard_progress'         => 'json',
            'floating_wizard_enabled' => 'bool',
            'debug_mode'       => 'bool',
            'direction_mode'   => 'string',
            'show_on_mobile'   => 'bool',
            'auto_open_delay'  => 'int',
            'show_on_pages'    => 'string',
            'widgets_enabled'  => 'array',

            // Mobile layout settings (vw/vh based)
            'mobile_layout_width_vw'           => 'int',
            'mobile_layout_height_vh'          => 'int',
            'mobile_layout_margin_top_vh'      => 'int',
            'mobile_layout_margin_bottom_vh'   => 'int',

            // Week 28: Character caps
            'visitor_input_char_limit_enabled' => 'bool',
            'visitor_input_char_limit'         => 'int',
            'bot_output_char_limit_global'     => 'int',

            // Trace logs feature archived — see boostbot/_archive/trace-logs/

            // Week 27.6: BrandCard (global)
            'brand_card_global_json'           => 'string',
            'brand_card_global_version'        => 'int',

            // Week 27.7: ServiceCatalog overlay (global)
            'service_catalog_overrides_json'    => 'string',
            'service_catalog_overrides_version' => 'int',

            // Global rules & forbidden topics (apply to all bots)
            'global_default_welcome_text' => 'string',
            'global_rules'            => 'string',
            'global_forbidden_topics' => 'string',

            // Low-credits alert
            'low_credits_threshold'       => 'int',
            'low_credits_email_enabled'   => 'bool',

            // Per-visitor message rate limiting
            'visitor_message_limit_enabled' => 'bool',
            'visitor_messages_per_hour'     => 'int',
            'visitor_messages_per_day'      => 'int',
            'visitor_cooldown_enabled'      => 'bool',
            'spam_alert_enabled'            => 'bool',
            'spam_alert_email_enabled'      => 'bool',

            // Smart auto-indexing
            'auto_deep_index_enabled'       => 'bool',
            'stale_index_days'              => 'int',

            // Multilingual
            'enabled_languages'             => 'json',
            'primary_language'              => 'string',

            // Page transition triggers
            'page_transition_triggers_enabled' => 'bool',

            // Watermark opt-in (WP.org compliance — Guideline 10)
            'show_watermark'                => 'bool',

            // Cloud service opt-in (WP.org compliance)
            'cloud_consent'                 => 'bool',
        ];

        // Per-language settings: when a `language` param is sent, per-language keys
        // are saved scoped to that language instead of the global (unscoped) option.
        $request_language = '';
        if ( $request->has_param( 'language' ) ) {
            $request_language = BoostBot_Language::sanitize( $request->get_param( 'language' ) );
        }

        $updated = [];
        $errors = [];

        foreach ($allowed_settings as $key => $type) {
            if ($request->has_param($key)) {
                $value = $request->get_param($key);

                // Credits backend site key: prevent accidental clearing or masked overwrites.
                if ( $key === 'backend_site_api_key' ) {
                    // Do not allow empty value to clear the stored key via bulk "save settings".
                    if ( empty( $value ) ) {
                        continue;
                    }

                    // If UI sent a masked placeholder (e.g. "abcdefghij...wxyz"), ignore it.
                    if ( is_string( $value ) && strpos( $value, '...' ) !== false ) {
                        $trimmed = trim( $value );
                        if ( preg_match( '/^.{10}\.\.\..{4}$/', $trimmed ) ) {
                            continue;
                        }
                    }
                }

                // Validate primary_language against enabled languages.
                if ( 'primary_language' === $key && '' !== $value ) {
                    $lang_check = BoostBot_Language::validate_enabled( $value );
                    if ( is_wp_error( $lang_check ) ) {
                        $errors[ $key ] = $lang_check->get_error_message();
                        continue;
                    }
                }

                // Validate and sanitize based on type
                $sanitized = $this->sanitize_setting($key, $value, $type);

                if (is_wp_error($sanitized)) {
                    $errors[$key] = $sanitized->get_error_message();
                    continue;
                }

                // Route per-language keys through language-scoped storage.
                if ( ! empty( $request_language ) && BoostBot_Settings::is_per_language( $key ) ) {
                    BoostBot_Settings::set_for_language( $key, $request_language, $sanitized );
                } else {
                    BoostBot_Settings::set($key, $sanitized);
                }
                $updated[$key] = $sanitized;

                if ( 'primary_language' === $key || 'enabled_languages' === $key ) {
                    if ( class_exists( 'BoostBot_Language' ) ) {
                        BoostBot_Language::clear_cache();
                    }
                    self::invalidate_language_scoped_caches();
                }
            }
        }

        if (!empty($errors)) {
            return $this->validation_error($errors);
        }

        if (empty($updated)) {
            return $this->error(__('No settings to update', 'boostbot'), 400);
        }

        BoostBot_Logger::info('Settings updated', [
            'keys' => array_keys($updated),
        ]);

        return $this->success([
            'message' => __('Settings updated successfully', 'boostbot'),
            'updated' => array_keys($updated),
        ]);
    }

    /**
     * Clear analytics transients that include language in their cache key.
     *
     * Called when primary_language or enabled_languages changes so that
     * analytics dashboards reflect the new language context immediately.
     */
    private static function invalidate_language_scoped_caches(): void {
        global $wpdb;
        $patterns = array(
            '_transient_boostbot_dashboard_stats%',
            '_transient_boostbot_trends_%',
            '_transient_boostbot_analytics_sources%',
            '_transient_boostbot_analytics_widgets%',
            '_transient_boostbot_analytics_funnel_%',
            '_transient_boostbot_analytics_bots%',
            '_transient_timeout_boostbot_dashboard_stats%',
            '_transient_timeout_boostbot_trends_%',
            '_transient_timeout_boostbot_analytics_sources%',
            '_transient_timeout_boostbot_analytics_widgets%',
            '_transient_timeout_boostbot_analytics_funnel_%',
            '_transient_timeout_boostbot_analytics_bots%',
        );
        foreach ( $patterns as $pattern ) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $wpdb->query( $wpdb->prepare(
                // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
                "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
                $pattern
            ) );
        }
    }

    /**
     * Reset settings to defaults.
     *
     * @since 1.0.0
     * @param WP_REST_Request $request The REST request object.
     * @return WP_REST_Response|WP_Error The response or error.
     */
    public function reset_settings($request)
    {
        BoostBot_Logger::debug('Resetting settings');

        // Get confirmation
        $confirm = (bool) $request->get_param('confirm');
        if (!$confirm) {
            return $this->error(
                __('Please confirm reset by setting confirm=true', 'boostbot'),
                400
            );
        }

        // BYOK FUNCTIONALITY - FOR FUTURE DELETION
        // The following code preserved BYOK API keys during reset.
        // Now commented out as BYOK is no longer supported.
        // $api_key = BoostBot_Settings::get('api_key');

        // Delete all settings
        BoostBot_Settings::delete_all();

        // Set defaults
        BoostBot_Settings::set_defaults();

        // BYOK FUNCTIONALITY - FOR FUTURE DELETION
        // Restore API key if it was set (no longer needed)
        // if (!empty($api_key)) {
        //     BoostBot_Settings::set('api_key', $api_key);
        // }

        BoostBot_Logger::info('Settings reset to defaults');

        return $this->success([
            'message' => __('Settings reset to defaults', 'boostbot'),
        ]);
    }

    // =========================================================================
    // BYOK FUNCTIONALITY - FOR FUTURE DELETION
    // The following methods were used for Bring Your Own Key (BYOK) model
    // where users provided their own Claude/OpenAI API keys.
    // Now all AI calls go through the credits backend (Week 26+).
    // These methods are not registered as routes and are orphan code.
    // =========================================================================

    /*
    // BYOK FUNCTIONALITY - FOR FUTURE DELETION
    public function test_api_key($request)
    {
        BoostBot_Logger::debug('Testing API key');

        $api_key = sanitize_text_field($request->get_param('api_key'));
        if (empty($api_key)) {
            $api_key = BoostBot_Settings::get('api_key');
        }

        if (empty($api_key)) {
            return $this->error(__('No API key provided', 'boostbot'), 400);
        }

        if (!$this->validate_api_key_format($api_key)) {
            return $this->success([
                'valid'   => false,
                'message' => __('מפתח ה-API לא תקין. מפתח צריך להתחיל ב-"sk-ant-"', 'boostbot'),
            ]);
        }

        try {
            $is_valid = BoostBot_Claude_Client::validate_api_key($api_key);

            if ($is_valid) {
                return $this->success([
                    'valid'   => true,
                    'message' => __('מפתח ה-API תקין ומחובר בהצלחה! ✅', 'boostbot'),
                ]);
            } else {
                return $this->success([
                    'valid'   => false,
                    'message' => __('מפתח ה-API לא תקין או שפג תוקפו.', 'boostbot'),
                ]);
            }
        } catch (Exception $e) {
            BoostBot_Logger::error('API key test failed', [
                'error' => $e->getMessage(),
            ]);

            return $this->success([
                'valid'   => false,
                'message' => sprintf(__('שגיאה בבדיקת המפתח: %s', 'boostbot'), $e->getMessage()),
            ]);
        }
    }

    // BYOK FUNCTIONALITY - FOR FUTURE DELETION
    public function test_openai_api_key($request)
    {
        BoostBot_Logger::debug('Testing OpenAI API key');

        $api_key = sanitize_text_field($request->get_param('openai_api_key'));
        if (empty($api_key)) {
            $api_key = BoostBot_Settings::get('openai_api_key');
        }

        if (empty($api_key)) {
            return $this->error(__('No OpenAI API key provided', 'boostbot'), 400);
        }

        try {
            $is_valid = BoostBot_OpenAI_Client::validate_api_key($api_key);

            return $this->success([
                'valid'   => (bool) $is_valid,
                'message' => $is_valid
                    ? __('OpenAI API key is valid and connected successfully! ✅', 'boostbot')
                    : __('OpenAI API key is invalid or expired.', 'boostbot'),
            ]);
        } catch (Exception $e) {
            return $this->success([
                'valid'   => false,
                'message' => sprintf(__('Error testing OpenAI key: %s', 'boostbot'), $e->getMessage()),
            ]);
        }
    }

    // BYOK FUNCTIONALITY - FOR FUTURE DELETION
    public function verify_api_key($request)
    {
        BoostBot_Logger::info('🔑 Starting API key verification');

        $api_key = BoostBot_Settings::get('api_key');
        $key_length = strlen($api_key ?? '');
        $key_prefix = $key_length > 10 ? substr($api_key, 0, 10) . '...' : 'EMPTY';
        BoostBot_Logger::info('🔑 Stored key: length=' . $key_length . ', prefix=' . $key_prefix);

        if (empty($api_key)) {
            BoostBot_Logger::warning('❌ No API key found in settings');
            return $this->success([
                'valid'   => false,
                'message' => __('No API key configured', 'boostbot'),
            ]);
        }

        if (!$this->validate_api_key_format($api_key)) {
            BoostBot_Logger::warning('❌ API key format invalid');
            return $this->success([
                'valid'   => false,
                'message' => __('Invalid API key format', 'boostbot'),
            ]);
        }

        BoostBot_Logger::info('✓ API key format valid, testing with Claude API...');

        try {
            $is_valid = BoostBot_Claude_Client::validate_api_key($api_key);
            BoostBot_Logger::info('🔑 Claude API test result: ' . ($is_valid ? 'VALID' : 'INVALID'));

            return $this->success([
                'valid'   => $is_valid,
                'message' => $is_valid 
                    ? __('API key is valid', 'boostbot')
                    : __('API key is invalid or expired', 'boostbot'),
            ]);
        } catch (Exception $e) {
            BoostBot_Logger::error('❌ API key verification exception: ' . $e->getMessage());
            return $this->success([
                'valid'   => false,
                'message' => $e->getMessage(),
            ]);
        }
    }

    // BYOK FUNCTIONALITY - FOR FUTURE DELETION
    public function verify_openai_api_key($request)
    {
        $api_key = BoostBot_Settings::get('openai_api_key');

        if (empty($api_key)) {
            return $this->success([
                'valid'   => false,
                'message' => __('No OpenAI API key configured', 'boostbot'),
            ]);
        }

        try {
            $is_valid = BoostBot_OpenAI_Client::validate_api_key($api_key);
            return $this->success([
                'valid'   => (bool) $is_valid,
                'message' => $is_valid
                    ? __('OpenAI API key is valid', 'boostbot')
                    : __('OpenAI API key is invalid or expired', 'boostbot'),
            ]);
        } catch (Exception $e) {
            return $this->success([
                'valid'   => false,
                'message' => $e->getMessage(),
            ]);
        }
    }

    // BYOK FUNCTIONALITY - FOR FUTURE DELETION
    public function get_models($request)
    {
        $models = BoostBot_Claude_Client::get_available_models();
        $current_model = BoostBot_Settings::get('claude_model', 'claude-3-5-sonnet-latest');

        return $this->success([
            'models'        => array_values($models),
            'current_model' => $current_model,
            'count'         => count($models),
        ]);
    }

    // BYOK FUNCTIONALITY - FOR FUTURE DELETION
    public function refresh_models($request)
    {
        BoostBot_Claude_Client::clear_models_cache();
        $models = BoostBot_Claude_Client::get_available_models(true);
        $current_model = BoostBot_Settings::get('claude_model', 'claude-3-5-sonnet-latest');

        return $this->success([
            'models'        => array_values($models),
            'current_model' => $current_model,
            'count'         => count($models),
            'refreshed'     => true,
            'message'       => sprintf(__('Loaded %d models from Anthropic', 'boostbot'), count($models)),
        ]);
    }

    // BYOK FUNCTIONALITY - FOR FUTURE DELETION
    public function get_openai_models($request)
    {
        $models = BoostBot_OpenAI_Client::get_available_models();
        $current_model = BoostBot_Settings::get('openai_model', 'gpt-4o-mini');

        return $this->success([
            'models'        => array_values($models),
            'current_model' => $current_model,
            'count'         => count($models),
        ]);
    }

    // BYOK FUNCTIONALITY - FOR FUTURE DELETION
    public function refresh_openai_models($request)
    {
        BoostBot_OpenAI_Client::clear_models_cache();
        $models = BoostBot_OpenAI_Client::get_available_models(true);
        $current_model = BoostBot_Settings::get('openai_model', 'gpt-4o-mini');

        return $this->success([
            'models'        => array_values($models),
            'current_model' => $current_model,
            'count'         => count($models),
            'refreshed'     => true,
            'message'       => sprintf(__('Loaded %d models from OpenAI', 'boostbot'), count($models)),
        ]);
    }
    */
    // END BYOK FUNCTIONALITY

    /**
     * Sanitize a setting value based on type.
     *
     * @since 1.0.0
     * @param string $key   Setting key.
     * @param mixed  $value Setting value.
     * @param string $type  Expected type.
     * @return mixed|WP_Error Sanitized value or error.
     */
    private function sanitize_setting($key, $value, $type)
    {
        switch ($type) {
            case 'string':
                return sanitize_text_field($value);

            case 'color':
                // Validate hex color
                if (!preg_match('/^#[a-fA-F0-9]{6}$/', $value)) {
                    return new WP_Error(
                        'invalid_color',
                        /* translators: %s: setting key name */
                        sprintf(__('Invalid color format for %s', 'boostbot'), $key)
                    );
                }
                return sanitize_hex_color($value);

            case 'bool':
                return (bool) $value;

            case 'int':
                return absint($value);

            case 'json':
                // Accept object/array and encode to JSON string, or accept a JSON string directly
                if (is_array($value) || is_object($value)) {
                    return wp_json_encode($value);
                }
                if (is_string($value)) {
                    $decoded = json_decode($value, true);
                    if (json_last_error() !== JSON_ERROR_NONE) {
                        return new WP_Error(
                            'invalid_json',
                            /* translators: %s: setting key name */
                        sprintf(__('Invalid JSON format for %s', 'boostbot'), $key)
                        );
                    }
                    return wp_json_encode($decoded);
                }
                return '{}';

            case 'array':
                if (!is_array($value)) {
                    return new WP_Error(
                        'invalid_array',
                        /* translators: %s: setting key name */
                        sprintf(__('%s must be an array', 'boostbot'), $key)
                    );
                }
                return array_map('sanitize_text_field', $value);

            default:
                return sanitize_text_field($value);
        }
    }

    // =========================================================================
    // BYOK HELPER METHODS - FOR FUTURE DELETION
    // =========================================================================

    /*
    // BYOK FUNCTIONALITY - FOR FUTURE DELETION
    private function mask_api_key($api_key)
    {
        if (strlen($api_key) < 10) {
            return '****';
        }
        return substr($api_key, 0, 10) . '...' . substr($api_key, -4);
    }

    // BYOK FUNCTIONALITY - FOR FUTURE DELETION
    private function validate_api_key_format($api_key)
    {
        // Claude API keys start with "sk-ant-"
        return strpos($api_key, 'sk-ant-') === 0 && strlen($api_key) > 20;
    }
    */
    // END BYOK HELPER METHODS

    /**
     * Get CRM settings.
     *
     * @since 1.0.0
     * @param WP_REST_Request $request The REST request object.
     * @return WP_REST_Response The response.
     */
    public function get_crm_settings($request)
    {
        $api_key = get_option('boostbot_crm_api_key', '');

        return $this->success([
            // Export key (read-only CRM export endpoints)
            'export_api_key' => $api_key ? substr($api_key, 0, 8) . '...' : '',
            'export_has_key' => !empty($api_key),

            // Webhook config (outgoing)
            'webhook_enabled' => (bool) BoostBot_Settings::get( 'crm_webhook_enabled', false ),
            'webhook_url'     => (string) BoostBot_Settings::get( 'crm_webhook_url', '' ),
            'webhook_api_key' => (string) BoostBot_Settings::get( 'crm_webhook_api_key', '' ),
            'webhook_events'  => BoostBot_Settings::get( 'crm_webhook_events', array() ),
        ]);
    }

    /**
     * Generate a new CRM API key.
     *
     * @since 1.0.0
     * @param WP_REST_Request $request The REST request object.
     * @return WP_REST_Response The response.
     */
    public function generate_crm_key($request)
    {
        // Generate secure random key.
        $key = wp_generate_password(32, false);

        update_option('boostbot_crm_api_key', $key);

        BoostBot_Logger::info('CRM API key generated');

        return $this->success([
            'key'     => $key,
            'message' => __('API Key generated successfully', 'boostbot'),
        ]);
    }

    /**
     * Update CRM webhook settings.
     *
     * @param WP_REST_Request $request The REST request.
     * @return WP_REST_Response
     */
    public function update_crm_webhook_settings( $request ) {
        $enabled = (bool) $request->get_param( 'webhook_enabled' );
        $url     = trim( (string) $request->get_param( 'webhook_url' ) );
        $api_key = (string) $request->get_param( 'webhook_api_key' );
        $events  = $request->get_param( 'webhook_events' );

        // Validate URL if enabled
        if ( $enabled ) {
            if ( empty( $url ) ) {
                return $this->error( __( 'Webhook URL is required', 'boostbot' ), 400 );
            }
            $url = esc_url_raw( $url );
            if ( empty( $url ) || ! preg_match( '#^https?://#i', $url ) ) {
                return $this->error( __( 'Invalid webhook URL', 'boostbot' ), 400 );
            }
        } else {
            // Keep url stored even when disabled (so user can toggle on/off).
            $url = esc_url_raw( $url );
        }

        // Normalize events
        if ( ! is_array( $events ) ) {
            $events = array();
        }

        $normalized_events = array(
            'lead_created'         => isset( $events['lead_created'] ) ? (bool) $events['lead_created'] : true,
            'conversation_started' => isset( $events['conversation_started'] ) ? (bool) $events['conversation_started'] : true,
            'meeting_booked'       => isset( $events['meeting_booked'] ) ? (bool) $events['meeting_booked'] : true,
        );

        BoostBot_Settings::set( 'crm_webhook_enabled', $enabled );
        BoostBot_Settings::set( 'crm_webhook_url', $url );
        BoostBot_Settings::set( 'crm_webhook_api_key', $api_key );
        BoostBot_Settings::set( 'crm_webhook_events', $normalized_events );

        return $this->success( array(
            'message' => __( 'Webhook settings saved', 'boostbot' ),
        ) );
    }

    /**
     * Test CRM webhook.
     *
     * @return WP_REST_Response
     */
    public function test_crm_webhook( $request ) {
        if ( ! class_exists( 'BoostBot_CRM_Webhook_Service' ) ) {
            return $this->error( __( 'Webhook service not available', 'boostbot' ), 500 );
        }

        $service = new BoostBot_CRM_Webhook_Service();
        $result  = $service->test_connection();

        return $this->success( $result );
    }

    /**
     * GET /wp-json/boostbot/v1/settings/connection-status
     *
     * Returns the current backend connection status. Triggers a health check
     * and caches the result in a 5-minute transient.
     *
     * @param WP_REST_Request $request The REST request object.
     * @return WP_REST_Response
     */
    public function get_connection_status( $request ) {
        $site_id     = BoostBot_Settings::get( 'backend_site_id', '' );
        $backend_url = BoostBot_Settings::get( 'backend_base_url', '' );

        if ( empty( $site_id ) || empty( $backend_url ) ) {
            return $this->success( array(
                'status'      => 'no_config',
                'backend_url' => $backend_url,
                'site_id'     => '',
                'message'     => __( 'Backend is not configured or site is not registered.', 'boostbot' ),
            ) );
        }

        $response = wp_remote_get( $backend_url . '/api/health', array(
            'timeout'   => 5,
            'sslverify' => true,
        ) );

        if ( is_wp_error( $response ) ) {
            set_transient( 'boostbot_backend_reachable', 'no', 5 * MINUTE_IN_SECONDS );
            return $this->success( array(
                'status'      => 'unreachable',
                'backend_url' => $backend_url,
                'site_id'     => $site_id,
                'message'     => $response->get_error_message(),
            ) );
        }

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

        if ( $code !== 200 || empty( $body['data']['db_ok'] ) ) {
            set_transient( 'boostbot_backend_reachable', 'no', 5 * MINUTE_IN_SECONDS );
            return $this->success( array(
                'status'      => 'unreachable',
                'backend_url' => $backend_url,
                'site_id'     => $site_id,
                'message'     => __( 'Backend returned an error.', 'boostbot' ),
            ) );
        }

        set_transient( 'boostbot_backend_reachable', 'yes', 5 * MINUTE_IN_SECONDS );
        return $this->success( array(
            'status'      => 'connected',
            'backend_url' => $backend_url,
            'site_id'     => $site_id,
            'message'     => __( 'Connected successfully.', 'boostbot' ),
        ) );
    }
}
