<?php
/**
 * Fatal-error shield for the SailWP Co-pilot REST namespace.
 *
 * Why: when a tool-handler triggers a PHP fatal (E_ERROR, undefined
 * function, etc.) WordPress falls back to its generic "There has been a
 * critical error on this website" HTML page. That HTML lands in the
 * Co-pilot chat UI as raw text — confusing, scary, useless for debugging.
 *
 * What this does: registers a shutdown handler that fires only on REST
 * requests to /sailwp-copilot/v1/*. If the request died on a fatal, it
 * emits a clean JSON error and writes the fatal to wp-content/debug.log
 * (regardless of WP_DEBUG_LOG) so the deploy log captures it.
 */
if (!defined('ABSPATH')) exit;

class SailWP_Copilot_Fatal_Shield {

    public function __construct() {
        // rest_api_init fires only on REST requests, so the shutdown
        // handler is wired only for our REST traffic — no overhead on
        // page renders, admin screens, etc.
        add_action('rest_api_init', [$this, 'arm']);
    }

    public function arm() {
        if (!$this->is_our_namespace()) return;
        register_shutdown_function([$this, 'catch_fatal']);
    }

    private function is_our_namespace() {
        $route = isset($_SERVER['REQUEST_URI']) ? (string) $_SERVER['REQUEST_URI'] : '';
        return strpos($route, '/wp-json/sailwp-copilot/v1/') !== false
            || strpos($route, '/sailwp-copilot/v1/') !== false;
    }

    public function catch_fatal() {
        $err = error_get_last();
        if (!$err) return;

        $fatal_types = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR];
        if (!in_array($err['type'], $fatal_types, true)) return;

        // Drop any partial output the dying handler produced so we own
        // the response body cleanly.
        if (!headers_sent()) {
            while (ob_get_level() > 0) { @ob_end_clean(); }
            http_response_code(500);
            header('Content-Type: application/json; charset=utf-8');
        }

        $payload = [
            'ok'      => false,
            'code'    => 'plugin_fatal',
            'message' => 'The Co-pilot plugin hit an unexpected error. Try again, and if it keeps happening let Joost know.',
            'detail'  => [
                'error'   => $err['message'],
                'file'    => $this->relpath((string) $err['file']),
                'line'    => (int) $err['line'],
                'version' => defined('SAILWP_COPILOT_VERSION') ? SAILWP_COPILOT_VERSION : null,
            ],
        ];

        // Always log so deploy/post-mortem has a paper trail, even when
        // WP_DEBUG_LOG is off.
        error_log(
            '[sailwp-copilot] PHP fatal in REST: '
            . $err['message'] . ' in ' . $err['file'] . ':' . $err['line']
        );

        echo wp_json_encode($payload);
    }

    private function relpath($abs) {
        if (!defined('SAILWP_COPILOT_DIR')) return $abs;
        $dir = SAILWP_COPILOT_DIR;
        if (strpos($abs, $dir) === 0) return substr($abs, strlen($dir));
        return $abs;
    }
}
