<?php

namespace WPD_Platform\Services;

use Exception;
use ActionScheduler;
use WPD_Platform\Plugin;
use WPD_Platform\Singleton;
use WPD_Platform\Utils\Logger;
use Coderatio\SimpleBackup\SimpleBackup;

/**
 * RemoteService class
 *
 * Manages the remote service and related operations
 *
 * @package WPD_Platform\Services
 */
class RemoteService extends Singleton
{
    /**
     * Store registered remote access actions and callbacks.
     *
     * @var array
     */
    protected $actions = [];

    /**
     * Stores request time for debug.
     *
     * @var int
     */
    protected $timer = 0;

    /**
     * Stores current processed action.
     *
     * @var string
     */
    protected $current_action = '';

    /**
     * Stores current action params being processed.
     *
     * @var array
     */
    protected $current_params = [];

    /**
     * Run the remote service
     *
     * @return void
     */
    public function run()
    {

        // don't continue if is not a remote request
        if (! $this->is_remote_request()) {
            return;
        }

        $this->register_actions();

        // Get the json data.

        // Get body.
        $raw_json = file_get_contents('php://input');

        // Get body.
        $body = json_decode($raw_json);

        // Validate request Key.
        $this->validate_request($raw_json);

        if (
            ! Plugin::instance()
                ->get_host()
                ->is_connected()
        ) {
            $this->send_json_error([
                'code' => 'not_connected',
                'message' => __('Site is not connected', 'platform'),
            ]);
        }

        // Action name is required.
        if (! isset($body->action)) {
            $this->send_json_error([
                'code' => 'invalid_params',
                'message' => __('The action parameter is missing', 'platform'),
            ]);
        }

        // Params are required.
        if (! isset($body->params)) {
            $this->send_json_error([
                'code' => 'invalid_params',
                'message' => __('The params object is missing', 'platform'),
            ]);
        }

        $this->timer = microtime(true);
        $this->current_action = $body->action;
        $this->current_params = $body->params;

        $this->process_action();
    }

    /**
     * Register the actions
     *
     * @return void
     */
    protected function register_actions()
    {
        $actions = [
            // 'sync'         => 'action_sync',
            'status' => 'action_status',
            'upgrade' => 'action_upgrade',
            'core_upgrade' => 'action_core_upgrade',
            'core_upgrade_async' => 'action_upgrade_async',
            'login_token' => 'action_login_token',
            'export_db' => 'action_export_db',
            'upgrade_async' => 'action_upgrade_async',
            'job_status' => 'action_get_job_status',
            'install_async' => 'action_install_async',
            'activate' => 'action_manage',
            'deactivate' => 'action_manage',
            'delete' => 'action_manage',
            'enable_autoupdate' => 'action_manage',
            'disable_autoupdate' => 'action_manage',
            'site_data' => 'action_site_data',
            'triggers_actions' => 'action_triggers_actions',
            'execute_action' => 'action_execute_trigger_action',
            'discover_abilities' => 'action_discover_abilities',
            'get_ability_info' => 'action_get_ability_info',
            'execute_ability' => 'action_execute_ability',
        ];
        $custom_actions = apply_filters('wpd_platform_register_hub_action', []);

        foreach ($actions as $action => $callback) {
            // Register action.
            $this->register_action($action, [$this, $callback]);
        }

        if (!empty($custom_actions)) {
            foreach ($actions as $action => $callback) {
                // Check action is not already registered and valid.
                if (!isset($this->actions[$action]) && is_callable($callback)) {
                    $this->register_action($action, $callback);
                }
            }
        }
    }

    /**
     * Register an action
     *
     * @param $action
     * @param $callback
     *
     * @return void
     */
    public function register_action($action, $callback)
    {
        $this->actions[$action] = $callback;
    }

    /**
     * Check if current request is for remote data.
     *
     * @access protected
     *
     * @return bool
     */
    protected function is_remote_request()
    {
        return ! empty($_GET['wpd-platform']); // phpcs:ignore
    }

    /**
     * Validate the request
     *
     * @param $data
     *
     * @return void
     */
    private function validate_request($data)
    {

        if (! isset($_SERVER['HTTP_AUTHORIZATION'])) {
            $this->send_error();
        }

        if (Plugin::instance()->get_host()->get_token() !== $_SERVER['HTTP_AUTHORIZATION']) {
            $this->send_error();
        }
    }

    /**
     * Send an error
     *
     * @return void
     */
    private function send_error()
    {
        header('HTTP/1.1 401 Unauthorized');
        exit();
    }

    /**
     * Run request.
     *
     * @return void
     */
    private function process_action()
    {
        // Continue only if valid action.
        if (isset($this->actions[$this->current_action])) {
            // Execute request action.
            call_user_func($this->actions[$this->current_action], $this->current_params, $this->current_action, $this);
        } else {
            // Invalid action.
            wp_send_json_error([
                'code' => 'unregistered_action',
                'message' => 'This action is not registered',
            ]);
        }
    }

    /**
     * @param $params
     * @param $action
     *
     * @return void
     */
    protected function action_manage($params, $action)
    {
        $result = [
            'plugins' => [],
            'themes' => [],
        ];

        include_once ABSPATH . 'wp-admin/includes/file.php'; // For delete functions

        if (isset($params->themes)) {
            include_once ABSPATH . 'wp-admin/includes/theme.php';

            $params->themes = ! is_array($params->themes) ? explode(',', $params->themes) : $params->themes;

            foreach ($params->themes as $slug) {
                if ($action === 'activate') {
                    switch_theme($slug);
                } elseif ($action === 'delete') {
                    delete_theme($slug);
                } elseif ($action === 'enable_autoupdate') {
                    $themes = get_option('auto_update_themes', []);
                    if (! in_array($slug, $themes)) {
                        $themes[] = $slug;
                        update_option('auto_update_themes', $themes);
                    }
                } elseif ($action === 'disable_autoupdate') {
                    $themes = get_option('auto_update_themes', []);
                    if (( $key = array_search($slug, $themes) ) !== false) {
                        unset($themes[$key]);
                        update_option('auto_update_themes', $themes);
                    }
                }

                $result['themes'][$slug] = [
                    'success' => true,
                    'message' => 'Theme action ran successfully.',
                ];
            }
        }

        if (isset($params->plugins)) {
            include_once ABSPATH . 'wp-admin/includes/plugin.php';

            $params->plugins = ! is_array($params->plugins) ? explode(',', $params->plugins) : $params->plugins;

            foreach ($params->plugins as $slug) {
                $plugin_path = UpdateService::instance()->get_full_plugin_path($slug);

                if ($action === 'activate') {
                    $state = activate_plugin($plugin_path);
                    $result['plugins'][$slug] = [
                        'success' => ! is_wp_error($state),
                        'message' => is_wp_error($state) ? $state->get_error_message() : 'Plugin activated successfully.',
                    ];
                } elseif ($action === 'deactivate') {
                    deactivate_plugins($plugin_path);
                } elseif ($action === 'delete') {
                    delete_plugins([ $plugin_path ]);
                } elseif ($action === 'enable_autoupdate') {
                    $plugins = get_option('auto_update_plugins', []);
                    if (! in_array($plugin_path, $plugins)) {
                        $plugins[] = $plugin_path;
                        update_option('auto_update_plugins', $plugins);
                    }
                } elseif ($action === 'disable_autoupdate') {
                    $plugins = get_option('auto_update_plugins', array());
                    if (( $key = array_search($plugin_path, $plugins) ) !== false) {
                        unset($plugins[ $key ]);
                        update_option('auto_update_plugins', $plugins);
                    }
                } else {
                    $this->send_json_error([ 'message' => 'Invalid action specified for plugin.' ]);
                }

                $result['plugins'][$slug] = [
                    'success' => true,
                    'message' => 'Plugin action ran successfully.',
                ];
            }
        }

        // Update options.
        if (isset($params->options)) {
            if (is_array($params->options)) {
                foreach ($params->options as $key => $value) {
                    update_option($key, $value);
                    do_action('wpd_platform/after/option_updated', $key, $value);
                }
                $result['options'] = 'Options updated successfully.';
            }
        }

        $this->send_json_success($result);
    }

    /**
     * Gets the login token.
     *
     * @param $params
     * @param $action
     *
     * @return void
     */
    protected function action_login_token($params, $action)
    {
        $username = $params->username ?? null;
        $token = LoginService::instance()->get_login_token($username);

        if (empty($token)) {
            $this->send_json_error([
                'errors' => ['No user found'],
            ]);

            return;
        }

        $this->send_json_success([
            'token' => $token,
            'Token' => $token,
        ]);
    }

    /**
     * Gets the wp data for the site.
     *
     * @param $params
     * @param $action
     *
     * @return void
     */
    protected function action_status($params, $action)
    {
        $full = !empty($params->full);

        $this->send_json_success(StatsService::instance()->get($full));
    }

    /**
     * Get custom site data.
     *
     * @param $params
     * @param $action
     */
    protected function action_site_data($params, $action)
    {
        $data = [
            'default' => [
                'url' => site_url(),
                'site_name' => get_bloginfo('name'),
             ],
        ];

        $data = apply_filters('wpd_site_data', $data);

        if (! empty($params->slug) && array_key_exists($params->slug, $data)) {
            $this->send_json_success($data[$params->slug]);
            return;
        }

        $this->send_json_success($data);
    }

    /**
     * Install an async action
     *
     * @param $params
     * @param $action
     *
     * @return void
     */
    protected function action_install_async($params, $action)
    {
        $actions = [];

        // Process plugins.
        if (isset($params->plugins)) {
            $params->plugins = ! is_array($params->plugins) ? explode(',', $params->plugins) : $params->plugins;

            if (is_array($params->plugins)) {
                foreach ($params->plugins as $plugin) {
                    $actions[ $plugin ] = as_enqueue_async_action(
                        'install_call_async',
                        [
                            'item' => $plugin,
                            'type' => 'plugin',
                        ],
                        'platform_upgrades'
                    );
                }
            }
        }

        // Process themes.
        if (isset($params->themes)) {
            $params->themes = ! is_array($params->themes) ? explode(',', $params->themes) : $params->themes;

            if (is_array($params->themes)) {
                foreach ($params->themes as $theme) {
                    $actions[ $theme ] = as_enqueue_async_action(
                        'install_call_async',
                        [
                            'item' => $theme,
                            'type' => 'theme',
                        ],
                        'platform_upgrades'
                    );
                }
            }
        }

        $this->send_json_success($actions);
    }

    /**
     * Install a call async
     *
     * @param $item
     * @param $type
     *
     * @return void
     */
    public function install_call_async($item, $type = 'plugin')
    {

        $success = UpdateService::instance()->install($item, $type);
        $response = [
            'job_type' => 'install',
            'installed' => '',
            'error' => '',
        ];

        if ($success) {
            $response['installed'] = [
                'file' => $item,
                'log' => UpdateService::instance()->get_log(),
                'new_version' => UpdateService::instance()->get_version(),
            ];
        } else {
            $error = UpdateService::instance()->get_error();
            $response['error'] = [
                'file' => $item,
                'code' => $error['code'],
                'message' => $error['message'],
                'log' => UpdateService::instance()->get_log(),
            ];
        }

        $this->save_job_progress($response);
    }

    /**
     * Action that runs the async upgrade.
     *
     * @param object $params
     * @param string $action
     * @return void
     */
    protected function action_upgrade_async($params, $action)
    {

        $actions = [];

        if ($action === 'core_upgrade_async') {
            $actions[ 'core' ] = as_enqueue_async_action(
                'upgrade_call_async',
                [
                    'item' => '',
                    'type' => 'core',
                ],
                'platform_upgrades'
            );
            $this->send_json_success($actions);
            return;
        }

        // Process plugins.
        if (isset($params->plugins)) {
            $params->plugins = ! is_array($params->plugins) ? explode(',', $params->plugins) : $params->plugins;

            if (is_array($params->plugins)) {
                foreach ($params->plugins as $plugin) {
                    $actions[ $plugin ] = as_enqueue_async_action(
                        'upgrade_call_async',
                        [
                            'item' => $plugin,
                            'type' => 'plugin',
                        ],
                        'platform_upgrades'
                    );
                }
            }
        }

        // Process themes.
        if (isset($params->themes)) {
            $params->themes = ! is_array($params->themes) ? explode(',', $params->themes) : $params->themes;

            if (is_array($params->themes)) {
                foreach ($params->themes as $theme) {
                    $actions[ $theme ] = as_enqueue_async_action(
                        'upgrade_call_async',
                        [
                            'item' => $theme,
                            'type' => 'theme',
                        ],
                        'platform_upgrades'
                    );
                }
            }
        }

        $this->send_json_success($actions);
    }

    /**
     * Run the Upgrade call action for action scheduler.
     *
     * @param string $item
     * @param string $type
     * @return void
     */
    public function upgrade_call_async($item, $type = 'plugin')
    {

        $response = [
            'job_type' => 'upgrade',
            'upgraded' => '',
            'error' => '',
        ];

        // Upgrade core WP.
        if ($type === 'core') {
            $success = UpdateService::instance()->upgrade_core();
        } else {
            $pid = "{$type}:{$item}";
            $success = UpdateService::instance()->upgrade($pid);
        }

        if ($success) {
            $response['upgraded'] = [
                'file' => $item,
                'log' => UpdateService::instance()->get_log(),
                'new_version' => UpdateService::instance()->get_version(),
            ];
        } else {
            $error = UpdateService::instance()->get_error();
            $response['error'] = [
                'file' => $item,
                'code' => $error['code'],
                'message' => $error['message'],
                'log' => UpdateService::instance()->get_log(),
            ];
        }

        $this->save_job_progress($response);
    }

    /**
     * Get the current job ID that is running.
     *
     * @return int
     */
    public function get_action_scheduler_job()
    {
        global $as_current_action_id;
        return $as_current_action_id;
    }

    /**
     * Add log to the action sheduler job
     *
     * @param [type] $data
     * @return void
     */
    private function save_job_progress($data)
    {
        if (! empty($this->get_action_scheduler_job())) {
            $wpd_jobs = Plugin::instance()->get_data('jobs', []);
            $wpd_jobs[ $this->get_action_scheduler_job() ] = $data;

            // clean the array and leave only the latest max 100 entries.
            $wpd_jobs = array_slice($wpd_jobs, -100, 100, true);

            Plugin::instance()->set_data('jobs', $wpd_jobs);

            ActionScheduler::logger()->log($this->get_action_scheduler_job(), 'plaform: ' . json_encode($data));
        }
    }

    /**
     * Get the status of a scheduled job by it's ID
     *
     * @param object $params
     * @param string $action
     * @return void
     */
    protected function action_get_job_status($params, $action)
    {

        // force run.
        ActionScheduler::runner()->run();

        $ids = $params->ids;
        $response = [];

        if (! is_array($params->ids)) {
            $ids = explode(',', $params->ids);
        }

        $wpd_jobs = Plugin::instance()->get_data('jobs', []);

        foreach ($ids as $id) {
            if (isset($wpd_jobs[ $id ])) {
                $data = $wpd_jobs[ $id ];
                $response[ $id ] = $data;

                if (isset($data['error']) && ! empty($data['error'])) {
                    $response[ $id ]['status'] = 'failed';
                    if (isset($data['error']['message'])) {
                        $response[ $id ]['message'] = $data['error']['message'];
                    }
                    if (isset($data['error']['log'])) {
                        $response[ $id ]['log'] = $data['error']['log'];
                    }
                } else {
                    $response[ $id ]['status'] = ActionScheduler::store()->get_status($id);
                }

                continue;
            }

            // deprecated. left for backward compatibility.
            try {
                $response[ $id ] = [
                    'status' => ActionScheduler::store()->get_status($id),
                    'log' => array_map(
                        function ($value) {
                            $data = $value->get_message();

                            if (strpos($data, 'plaform: ') !== false) {
                                  $data = @json_decode(str_replace('plaform: ', '', $data));
                            }
                            return $data;
                        },
                        ActionScheduler::logger()->get_logs($id)
                    ),
                ];
            } catch (Exception $e) {
                $response[ $id ] = [
                    'status' => 'missing',
                    'log' => 'Job ID was not found',
                ];
            }
        }

        $this->send_json_success($response);
    }

    /**
     * Upgrade plugin/theme action.
     *
     * @param [type] $params
     * @param [type] $action
     * @return void
     */
    protected function action_upgrade($params, $action)
    {
        $upgraded = [];
        $errors = [];

        // Process plugins.
        if (isset($params->plugins)) {
            $params->plugins = ! is_array($params->plugins) ? explode(' ', $params->plugins) : $params->plugins;

            if (is_array($params->plugins)) {
                foreach ($params->plugins as $plugin) {
                    $upgrade_data = $this->upgrade_call($plugin, 'plugin');
                    $upgraded[] = $upgrade_data['upgraded'];
                    $errors[] = $upgrade_data['error'];
                }
            }
        }

        // Process themes.
        if (isset($params->themes)) {
            $params->themes = !is_array($params->themes) ? explode(' ', $params->themes) : $params->themes;

            if (is_array($params->themes)) {
                foreach ($params->themes as $theme) {
                    $upgrade_data = $this->upgrade_call($theme, 'theme');
                    $upgraded[] = $upgrade_data['upgraded'];
                    $errors[] = $upgrade_data['error'];
                }
            }
        }

        if (!empty($upgraded)) {
            $this->send_json_success(compact('upgraded', 'errors'));
        } else {
            $this->send_json_error(compact('upgraded', 'errors'));
        }
    }


    /**
     * Run the upgrade call and prepare result.
     *
     * @param $item
     * @param $type
     *
     * @return string[]
     */
    protected function upgrade_call($item, $type = 'plugin')
    {
        $pid = "{$type}:{$item}";
        $success = UpdateService::instance()->upgrade($pid);
        $response = [
            'upgraded' => '',
            'error' => '',
        ];

        if ($success) {
            $response['upgraded'] = [
                'file' => $item,
                'log' => UpdateService::instance()->get_log(),
                'new_version' => UpdateService::instance()->get_version(),
            ];
        } else {
            $error = UpdateService::instance()->get_error();
            $response['error'] = [
                'file' => $item,
                'code' => $error['code'],
                'message' => $error['message'],
                'log' => UpdateService::instance()->get_log(),
            ];
        }

        return $response;
    }

    /**
     * Upgrades to the latest WP core version, major or minor.
     *
     * @param object $params Parameters passed in json body.
     * @param string $action The action name that was called.
     *
     * @return void
     */
    protected function action_core_upgrade($params, $action)
    {
        // Upgrade core WP.
        $success = UpdateService::instance()->upgrade_core();
        if ($success) {
            $this->send_json_success([
                'log' => UpdateService::instance()->get_log(),
                'new_version' => UpdateService::instance()->get_version(),
            ]);
        } else {
            $error = UpdateService::instance()->get_error();
            $this->send_json_error([
                'code' => $error['code'],
                'message' => $error['message'],
                'data' => ['log' => UpdateService::instance()->get_log()],
            ]);
        }
    }

    /**
     * Exports the full db.
     *
     * @param $params
     * @param $action
     *
     * @return void
     */
    protected function action_export_db($params, $action)
    {
        $path = $params->path ?? null;
        $filename = $params->filename ?? null;
        $core_only = $params->core_only ?? false;
        $include_tables = $params->include_tables ?? [];

        if (empty($path) || empty($filename)) {
            $this->send_json_error([
                'errors' => ['Path and filename are required'],
            ]);

            return;
        }

        try {
            // Define WordPress core tables
            $wp_core_tables = [
                'wp_posts', 'wp_postmeta', 'wp_comments', 'wp_commentmeta',
                'wp_terms', 'wp_termmeta', 'wp_term_taxonomy', 'wp_term_relationships',
                'wp_users', 'wp_usermeta', 'wp_options'
            ];

            // Initialize SimpleBackup
            $simpleBackup = SimpleBackup::start()
                ->setDbName(DB_NAME)
                ->setDbUser(DB_USER)
                ->setDbPassword(DB_PASSWORD)
                ->setDbHost(DB_HOST);

            // If the core_only flag is set to true, include only core tables
            if ($core_only) {
                if (!empty($include_tables)) {
                    $wp_core_tables = array_merge($wp_core_tables, $include_tables);
                }
                    $simpleBackup->includeOnly($wp_core_tables);
            }


            // Set the directory where the backup will be stored
            $dir = trailingslashit(WP_CONTENT_DIR) . trailingslashit($path);
            $full_path = $dir . $filename;

            $simpleBackup->then()->storeAfterExportTo($dir, $filename);

            $exportedName = trailingslashit($dir) . $filename;
            $response = $simpleBackup->getResponse();

            // Check if the export was successful
            if ($response->message === 'Export finished successfully.') {
                // Gzip the exported file
                $gzipped = gzencode(file_get_contents($exportedName . '.sql'), 9);
                $gzippedFileName = $exportedName . '.wpress';

                $writeStatus = file_put_contents($gzippedFileName, $gzipped);

                // Delete the original .sql file
                if (file_exists($exportedName . '.sql')) {
                    unlink($exportedName . '.sql');
                }

                //Delete export in 5 minutes
                $this->schedule_db_export_deletion($gzippedFileName);

                // Send JSON success response with path to the gzipped file
                $this->send_json_success([
                    'path' => trailingslashit(WP_CONTENT_URL) . trailingslashit($path) . basename($gzippedFileName)
                ]);
            } else {
                $this->send_json_error([
                    'errors' => ['Failed to export database: ' . $response->message],
                ]);
            }
        } catch (Exception $e) {
            $this->send_json_error([
                'errors' => ['An error occurred: ' . $e->getMessage()],
            ]);
        }
    }


    /**
         * Schedules the database export file for deletion
         *
         * @param string $exportedFilePath The full path of the exported file.
         */
    protected function schedule_db_export_deletion($exportedFilePath)
    {
        $time = time() + 300; // 5 minutes from now
        as_schedule_single_action($time, 'delete_db_export', array($exportedFilePath));
    }

        /**
         * Deletes the database export file
         *
         * @param string $exportedFilePath The full path of the exported file.
         */
    public static function delete_db_export($exportedFilePath)
    {
        if (file_exists($exportedFilePath)) {
            unlink($exportedFilePath);
            Logger::debug("Deleted database export at {$exportedFilePath}", 'Remote');
        } else {
            Logger::error("Could not find database export at {$exportedFilePath} to delete", 'Remote');
        }
    }

    /**
     * Return success results for API to the hub
     *
     * @param mixed $data Data to encode as JSON, then print and die.
     * @param int   $status_code The HTTP status code to output, defaults to 200.
     *
     * @return void
     */
    protected function send_json_success($data = null, $status_code = null)
    {
        // Log it if turned on.
        if ($this->is_remote_request() && defined('WPD_API_DEBUG') && WPD_API_DEBUG) {
            $req_time = round(microtime(true) - $this->timer, 4) . 's';
            $req_status = is_null($status_code) ? 200 : $status_code;
            $log = '[WPD API call response] %s %s %s %s';
            $log .= "\n   Response: (success) %s\n";
            $msg = sprintf(
                $log,
                $_GET['wpd-platform'], // phpcs:ignore
                $this->current_action,
                $req_status,
                $req_time,
                wp_json_encode($data, JSON_PRETTY_PRINT),
            );
            error_log($msg); // phpcs:ignore
        }

        wp_send_json_success($data, $status_code);
    }

    /**
     * Return error results for API to the hub.
     *
     * @param mixed $data Data to encode as JSON, then print and die.
     * @param int   $status_code The HTTP status code to output, defaults to 200.
     *
     * @return void
     */
    protected function send_json_error($data = null, $status_code = null)
    {
        // Log it if turned on.
        if ($this->is_remote_request() && defined('WPD_API_DEBUG') && WPD_API_DEBUG) {
            $req_time = round(microtime(true) - $this->timer, 4) . 's';
            $req_status = is_null($status_code) ? 200 : $status_code;
            $log = '[WPD API call response] %s %s %s %s';
            $log .= "\n   Response: (error) %s\n";
            $msg = sprintf(
                $log,
                $_GET['wpd-platform'], // phpcs:ignore
                $this->current_action,
                $req_status,
                $req_time,
                wp_json_encode($data, JSON_PRETTY_PRINT),
            );
            error_log($msg); // phpcs:ignore
        }

        wp_send_json_error($data, $status_code);
    }

    /**
     * Get the memory limit in bytes
     *
     * @return int
     */
    private function get_memory_limit()
    {
        $limit = ini_get('memory_limit');
        if (strpos($limit, 'M') !== false) {
            $limit = intval($limit) * 1024 * 1024;
        } elseif (strpos($limit, 'K') !== false) {
            $limit = intval($limit) * 1024;
        } else {
            $limit = intval($limit);
        }
        return $limit;
    }

    /**
     * Get all registered triggers from SDK
     *
     * @return array
     */
    private function get_sdk_triggers()
    {
        return apply_filters('dollie_trigger_register_trigger', []);
    }

    /**
     * Get all registered actions from SDK
     *
     * @return array
     */
    private function get_sdk_actions()
    {
        return apply_filters('dollie_trigger_register_action', []);
    }

    /**
     * Get all registered integrations from SDK
     *
     * @return array
     */
    private function get_sdk_integrations()
    {
        if (!class_exists('\Dollie\SDK\Controllers\IntegrationsController')) {
            return [];
        }

        return \Dollie\SDK\Controllers\IntegrationsController::get_integrations();
    }

    /**
     * Get all available triggers and actions from SDK
     *
     * @param object $params Parameters passed in json body.
     * @param string $action The action name that was called.
     *
     * @return void
     */
    protected function action_triggers_actions($params, $action)
    {
        try {
            // Determine what to retrieve based on params
            $type = isset($params->type) ? $params->type : 'all';

            // Get registered triggers and actions via SDK filters
            $triggers = $this->get_sdk_triggers();
            $actions = $this->get_sdk_actions();
            $integrations = $this->get_sdk_integrations();

            $data = [];

            // Build response based on registered triggers/actions grouped by integration
            $all_integration_ids = array_unique(array_merge(array_keys($triggers), array_keys($actions)));

            foreach ($all_integration_ids as $integration_id) {
                $integration_data = [
                    'id' => $integration_id,
                    'name' => $integration_id,
                ];

                // Get integration name if available
                if (isset($integrations[$integration_id]) && method_exists($integrations[$integration_id], 'get_name')) {
                    $integration_data['name'] = $integrations[$integration_id]->get_name();
                }

                switch ($type) {
                    case 'triggers':
                        if (!empty($triggers[$integration_id])) {
                            $integration_data['triggers'] = $this->format_triggers($triggers[$integration_id]);
                            $data[] = $integration_data;
                        }
                        break;

                    case 'actions':
                        if (!empty($actions[$integration_id])) {
                            $integration_data['actions'] = $this->format_actions($actions[$integration_id]);
                            $data[] = $integration_data;
                        }
                        break;

                    case 'all':
                    default:
                        $integration_data['triggers'] = isset($triggers[$integration_id])
                            ? $this->format_triggers($triggers[$integration_id])
                            : [];
                        $integration_data['actions'] = isset($actions[$integration_id])
                            ? $this->format_actions($actions[$integration_id])
                            : [];
                        $data[] = $integration_data;
                        break;
                }
            }

            $this->send_json_success([
                'type' => $type,
                'data' => $data,
                'count' => count($data),
            ]);

        } catch (Exception $e) {
            $this->send_json_error([
                'code' => 'trigger_actions_error',
                'message' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Format triggers array for API response
     *
     * @param array $triggers Raw triggers array
     * @return array Formatted triggers
     */
    private function format_triggers($triggers)
    {
        $formatted = [];
        foreach ($triggers as $trigger_id => $trigger_config) {
            $formatted[] = [
                'id' => $trigger_id,
                'label' => $trigger_config['label'] ?? $trigger_id,
                'action' => $trigger_config['action'] ?? $trigger_id,
            ];
        }
        return $formatted;
    }

    /**
     * Format actions array for API response
     *
     * @param array $actions Raw actions array
     * @return array Formatted actions
     */
    private function format_actions($actions)
    {
        $formatted = [];
        foreach ($actions as $action_id => $action_config) {
            $formatted[] = [
                'id' => $action_id,
                'label' => $action_config['label'] ?? $action_id,
            ];
        }
        return $formatted;
    }

    /**
     * Execute a trigger action remotely using SDK
     *
     * @param object $params Parameters passed in json body.
     * @param string $action The action name that was called.
     *
     * @return void
     */
    protected function action_execute_trigger_action($params, $action)
    {
        // Validate required parameters
        if (!isset($params->action_name) || empty($params->action_name)) {
            $this->send_json_error([
                'code' => 'missing_action_name',
                'message' => __('The action_name parameter is required', 'platform'),
            ]);
            return;
        }

        try {
            // Get parameters with defaults
            $action_name = sanitize_text_field($params->action_name);
            $user_id = isset($params->user_id) ? absint($params->user_id) : 0;
            $automation_id = isset($params->automation_id) ? absint($params->automation_id) : 0;

            // Convert fields and options from stdClass to arrays recursively
            $fields = isset($params->fields) ? json_decode(json_encode($params->fields), true) : [];
            $options = isset($params->options) ? json_decode(json_encode($params->options), true) : [];

            // Log the action execution for debugging
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('Remote Action Execution: ' . $action_name);
                error_log('Options: ' . print_r($options, true));
            }

            // Create a response capture mechanism
            $action_response = null;
            $action_hook = 'dollie_trigger_action_' . $action_name;

            // Add a filter to capture the response
            add_filter('dollie_trigger_action_response', function($response) use (&$action_response) {
                $action_response = $response;
                return $response;
            }, 10, 1);

            // Execute the action hook
            do_action(
                $action_hook,
                $user_id,
                $automation_id,
                $fields,
                $options
            );

            // Check if we got a response from the action
            if ($action_response !== null) {
                $this->send_json_success([
                    'message' => __('Action executed successfully', 'platform'),
                    'action' => $action_name,
                    'response' => $action_response,
                ]);
            } else {
                // Action executed but no response captured
                $this->send_json_success([
                    'message' => __('Action executed successfully', 'platform'),
                    'action' => $action_name,
                ]);
            }

        } catch (Exception $e) {
            $this->send_json_error([
                'code' => 'action_execution_failed',
                'message' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);
        }
    }

    /**
     * Discover all registered WordPress abilities (via WP Abilities API).
     *
     * Only returns abilities with mcp.public=true metadata.
     * This replaces triggers_actions for the new Abilities system.
     *
     * @param object $params Parameters (unused).
     * @param string $action The action name.
     */
    /**
     * Ensure an admin user is set for the current request.
     *
     * SDK API calls authenticate via token but don't set a WordPress user context.
     * Abilities require a logged-in user for permission checks, so we set the
     * first administrator as the current user.
     */
    private function ensure_admin_user_context()
    {
        if (get_current_user_id() > 0) {
            return;
        }

        $admins = get_users([
            'role' => 'administrator',
            'number' => 1,
            'orderby' => 'ID',
            'order' => 'ASC',
        ]);

        if (!empty($admins)) {
            wp_set_current_user($admins[0]->ID);
        }
    }

    protected function action_discover_abilities($params, $action)
    {
        $this->ensure_admin_user_context();

        try {
            if (!function_exists('wp_get_abilities')) {
                $this->send_json_success([
                    'abilities' => [],
                    'count' => 0,
                    'message' => 'WordPress Abilities API not available',
                ]);
                return;
            }

            $abilities = wp_get_abilities();
            $ability_list = [];

            foreach ($abilities as $ability) {
                $meta = $ability->get_meta();
                $is_mcp_public = $meta['mcp']['public'] ?? false;

                if (!$is_mcp_public) {
                    continue;
                }

                // Only include tool-type abilities
                $mcp_type = $meta['mcp']['type'] ?? 'tool';
                if ($mcp_type !== 'tool') {
                    continue;
                }

                $ability_data = [
                    'name' => $ability->get_name(),
                    'label' => $ability->get_label(),
                    'description' => $ability->get_description(),
                    'category' => $ability->get_category(),
                ];

                // Include annotations if available
                $annotations = $meta['annotations'] ?? null;
                if (!empty($annotations)) {
                    $ability_data['annotations'] = $annotations;
                }

                $ability_list[] = $ability_data;
            }

            $this->send_json_success([
                'abilities' => $ability_list,
                'count' => count($ability_list),
            ]);

        } catch (Exception $e) {
            $this->send_json_error([
                'code' => 'discover_abilities_error',
                'message' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Get detailed info about a specific WordPress ability.
     *
     * Returns full input/output schema and metadata.
     *
     * @param object $params Parameters containing ability_name.
     * @param string $action The action name.
     */
    protected function action_get_ability_info($params, $action)
    {
        $this->ensure_admin_user_context();

        if (!isset($params->ability_name) || empty($params->ability_name)) {
            $this->send_json_error([
                'code' => 'missing_ability_name',
                'message' => 'The ability_name parameter is required',
            ]);
            return;
        }

        try {
            if (!function_exists('wp_get_ability')) {
                $this->send_json_error([
                    'code' => 'abilities_not_available',
                    'message' => 'WordPress Abilities API not available',
                ]);
                return;
            }

            $ability_name = sanitize_text_field($params->ability_name);
            $ability = wp_get_ability($ability_name);

            if (!$ability) {
                $this->send_json_error([
                    'code' => 'ability_not_found',
                    'message' => sprintf('Ability "%s" not found', $ability_name),
                ]);
                return;
            }

            $meta = $ability->get_meta();

            $ability_info = [
                'name' => $ability->get_name(),
                'label' => $ability->get_label(),
                'description' => $ability->get_description(),
                'category' => $ability->get_category(),
                'input_schema' => $ability->get_input_schema(),
            ];

            $output_schema = $ability->get_output_schema();
            if (!empty($output_schema)) {
                $ability_info['output_schema'] = $output_schema;
            }

            if (!empty($meta)) {
                $ability_info['meta'] = $meta;
            }

            $this->send_json_success($ability_info);

        } catch (Exception $e) {
            $this->send_json_error([
                'code' => 'get_ability_info_error',
                'message' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Execute a WordPress ability with provided parameters.
     *
     * Calls the ability's execute callback directly via the WP Abilities API.
     *
     * @param object $params Parameters containing ability_name and parameters.
     * @param string $action The action name.
     */
    protected function action_execute_ability($params, $action)
    {
        $this->ensure_admin_user_context();

        if (!isset($params->ability_name) || empty($params->ability_name)) {
            $this->send_json_error([
                'code' => 'missing_ability_name',
                'message' => 'The ability_name parameter is required',
            ]);
            return;
        }

        try {
            if (!function_exists('wp_get_ability')) {
                $this->send_json_error([
                    'code' => 'abilities_not_available',
                    'message' => 'WordPress Abilities API not available',
                ]);
                return;
            }

            $ability_name = sanitize_text_field($params->ability_name);
            $ability = wp_get_ability($ability_name);

            if (!$ability) {
                $this->send_json_error([
                    'code' => 'ability_not_found',
                    'message' => sprintf('Ability "%s" not found', $ability_name),
                ]);
                return;
            }

            // Convert parameters from stdClass to array
            $parameters = isset($params->parameters)
                ? json_decode(json_encode($params->parameters), true)
                : [];

            // Check permissions
            $permission_result = $ability->check_permissions($parameters);
            if (is_wp_error($permission_result)) {
                $this->send_json_error([
                    'code' => 'permission_denied',
                    'message' => $permission_result->get_error_message(),
                ]);
                return;
            }

            // Execute the ability
            $result = $ability->execute($parameters);

            if (is_wp_error($result)) {
                $this->send_json_error([
                    'code' => 'ability_execution_failed',
                    'message' => $result->get_error_message(),
                ]);
                return;
            }

            $this->send_json_success([
                'ability' => $ability_name,
                'result' => $result,
            ]);

        } catch (Exception $e) {
            $this->send_json_error([
                'code' => 'ability_execution_error',
                'message' => $e->getMessage(),
            ]);
        }
    }
}
