<?php
/**
 * Support Session Endpoint for BoostBot REST API.
 *
 * Manages the client-side of the reverse-tunnel support session:
 * - Start: gathers config snapshot, sends it to the backend
 * - Status: returns current session state and executes pending commands
 * - End: terminates the session
 *
 * @package BoostBot
 * @since   1.2.1
 */

// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class BoostBot_Support_Endpoint extends BoostBot_Base_Endpoint {

    protected $rest_base = 'support';

    public function register() {
        $this->register_route(
            '/start',
            'POST',
            [ $this, 'start_session' ],
            [ $this, 'admin_access' ]
        );

        $this->register_route(
            '/poll',
            'POST',
            [ $this, 'poll_and_execute' ],
            [ $this, 'admin_access' ]
        );

        $this->register_route(
            '/end',
            'POST',
            [ $this, 'end_session' ],
            [ $this, 'admin_access' ]
        );

        $this->register_route(
            '/status',
            'GET',
            [ $this, 'get_status' ],
            [ $this, 'admin_access' ]
        );
    }

    /**
     * Start a support session by gathering a snapshot and sending it to the backend.
     */
    public function start_session( $request ) {
        $mode = $request->get_param( 'mode' ) ?: 'configure';
        if ( 'full' === $mode ) {
            $mode = 'configure';
        }
        if ( ! in_array( $mode, [ 'provision', 'configure' ], true ) ) {
            return $this->error( 'invalid_mode', 'Mode must be provision or configure.', 400 );
        }

        $backend_url = \BoostBot_Settings::get( 'backend_base_url' );
        $site_id     = \BoostBot_Settings::get( 'backend_site_id' );
        $api_key     = \BoostBot_Settings::get( 'backend_site_api_key' );

        if ( empty( $backend_url ) || empty( $site_id ) || empty( $api_key ) ) {
            return $this->error( 'not_configured', 'Backend connection is not configured.', 400 );
        }

        $snapshot = $this->gather_snapshot();

        $response = wp_remote_post(
            "{$backend_url}/api/v1/sites/{$site_id}/support",
            [
                'timeout' => 15,
                'headers' => [
                    'Content-Type'  => 'application/json',
                    'Authorization' => "Bearer {$api_key}",
                ],
                'body' => wp_json_encode( [
                    'snapshot' => $snapshot,
                    'mode'     => $mode,
                ] ),
            ]
        );

        if ( is_wp_error( $response ) ) {
            return $this->error(
                'backend_error',
                'Failed to reach backend: ' . $response->get_error_message(),
                502
            );
        }

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

        if ( $status_code !== 200 || empty( $body['success'] ) ) {
            $msg = $body['error']['message'] ?? 'Backend returned an error';
            return $this->error( 'backend_error', $msg, $status_code ?: 502 );
        }

        $session_data = $body['data'];

        update_option( 'boostbot_support_session', [
            'token'      => $session_data['sessionToken'],
            'session_id' => $session_data['sessionId'],
            'expires_at' => $session_data['expiresAt'],
            'mode'       => $mode,
            'started_at' => current_time( 'c' ),
        ], false );

        return $this->success( [
            'sessionId'  => $session_data['sessionId'],
            'expiresAt'  => $session_data['expiresAt'],
            'mode'       => $mode,
        ] );
    }

    /**
     * Poll the backend for pending commands, execute them locally, and return results.
     */
    public function poll_and_execute( $request ) {
        $session = get_option( 'boostbot_support_session' );
        if ( empty( $session ) || empty( $session['token'] ) ) {
            return $this->error( 'no_session', 'No active support session.', 400 );
        }

        $backend_url = \BoostBot_Settings::get( 'backend_base_url' );
        $site_id     = \BoostBot_Settings::get( 'backend_site_id' );
        $token       = $session['token'];

        // Fetch pending commands from backend
        $poll_response = wp_remote_get(
            "{$backend_url}/api/v1/sites/{$site_id}/support?token={$token}",
            [ 'timeout' => 10 ]
        );

        if ( is_wp_error( $poll_response ) ) {
            return $this->error( 'poll_error', $poll_response->get_error_message(), 502 );
        }

        $poll_body = json_decode( wp_remote_retrieve_body( $poll_response ), true );
        $poll_code = wp_remote_retrieve_response_code( $poll_response );

        if ( $poll_code === 404 || ( isset( $poll_body['error']['code'] ) && $poll_body['error']['code'] === 'invalid_session' ) ) {
            delete_option( 'boostbot_support_session' );
            return $this->success( [ 'session_ended' => true, 'commands_executed' => 0 ] );
        }

        if ( $poll_code !== 200 || empty( $poll_body['success'] ) ) {
            $msg = $poll_body['error']['message'] ?? 'Poll failed';
            return $this->error( 'poll_error', $msg, $poll_code ?: 502 );
        }

        $commands = $poll_body['data']['commands'] ?? [];
        if ( empty( $commands ) ) {
            return $this->success( [ 'commands_executed' => 0 ] );
        }

        // Execute each command locally via the WP REST API
        $results = [];
        foreach ( $commands as $cmd ) {
            $results[] = $this->execute_local_command( $cmd );
        }

        // Send results back to backend
        $result_response = wp_remote_post(
            "{$backend_url}/api/v1/sites/{$site_id}/support?token={$token}",
            [
                'timeout' => 10,
                'headers' => [ 'Content-Type' => 'application/json' ],
                'body'    => wp_json_encode( [ 'results' => $results ] ),
            ]
        );

        $commands_executed = count( $results );

        return $this->success( [
            'commands_executed' => $commands_executed,
            'results'          => $results,
        ] );
    }

    /**
     * End the active support session.
     */
    public function end_session( $request ) {
        $session = get_option( 'boostbot_support_session' );
        if ( empty( $session ) || empty( $session['token'] ) ) {
            return $this->success( [ 'ended' => true, 'was_active' => false ] );
        }

        $backend_url = \BoostBot_Settings::get( 'backend_base_url' );
        $site_id     = \BoostBot_Settings::get( 'backend_site_id' );
        $token       = $session['token'];

        wp_remote_request(
            "{$backend_url}/api/v1/sites/{$site_id}/support?token={$token}",
            [
                'method'  => 'DELETE',
                'timeout' => 10,
            ]
        );

        delete_option( 'boostbot_support_session' );

        return $this->success( [ 'ended' => true, 'was_active' => true ] );
    }

    /**
     * Get current support session status.
     */
    public function get_status( $request ) {
        $session = get_option( 'boostbot_support_session' );

        if ( empty( $session ) || empty( $session['token'] ) ) {
            return $this->success( [ 'active' => false ] );
        }

        $expires = strtotime( $session['expires_at'] );
        if ( $expires && $expires < time() ) {
            delete_option( 'boostbot_support_session' );
            return $this->success( [ 'active' => false, 'reason' => 'expired' ] );
        }

        return $this->success( [
            'active'     => true,
            'session_id' => $session['session_id'],
            'mode'       => $session['mode'],
            'expires_at' => $session['expires_at'],
            'started_at' => $session['started_at'],
        ] );
    }

    // ── Private helpers ─────────────────────────────────────────────

    /**
     * Gather a configuration snapshot reusing the backup export logic.
     */
    private function gather_snapshot() {
        global $wpdb;

        $snapshot = [
            'plugin_version' => defined( 'BOOSTBOT_VERSION' ) ? BOOSTBOT_VERSION : '1.0.0',
            'site_url'       => get_site_url(),
            'gathered_at'    => current_time( 'c' ),
        ];

        // Settings
        $snapshot['settings'] = $this->get_boostbot_options();

        // Configuration tables
        $tables = [
            'bots'                   => 'boostbot_bots',
            'personalities'          => 'boostbot_personalities',
            'tones'                  => 'boostbot_tones',
            'widgets'                => 'boostbot_widgets',
            'appearance_presets'     => 'boostbot_appearance_presets',
            'opening_screen_presets' => 'boostbot_opening_screen_presets',
            'contact_lists'          => 'boostbot_contact_lists',
        ];

        foreach ( $tables as $key => $table_suffix ) {
            $table_name = $wpdb->prefix . $table_suffix;
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $rows = $wpdb->get_results( "SELECT * FROM `{$table_name}`", ARRAY_A );
            $snapshot[ $key ] = is_array( $rows ) ? $rows : [];
        }

        return $snapshot;
    }

    /**
     * Get all boostbot_ options for the snapshot.
     */
    private function get_boostbot_options() {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        $rows = $wpdb->get_results(
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            "SELECT option_name, option_value FROM {$wpdb->options} WHERE option_name LIKE 'boostbot_%'",
            ARRAY_A
        );

        $options = [];
        // Exclude every credential/secret from the support snapshot, matching the
        // exclusion list used by the backup endpoint — previously only the site API key
        // and session were skipped, leaking license/AI/Google/management keys off-site.
        $exclude = [
            'boostbot_backend_site_api_key',
            'boostbot_support_session',
            'boostbot_api_key',
            'boostbot_openai_api_key',
            'boostbot_gemini_api_key',
            'boostbot_voyage_api_key',
            'boostbot_license_key',
            'boostbot_crm_webhook_api_key',
            'boostbot_crm_api_key',
            'boostbot_google_access_token',
            'boostbot_google_refresh_token',
            'boostbot_management_key_plaintext',
            'boostbot_management_key_hash',
        ];

        foreach ( $rows as $row ) {
            if ( in_array( $row['option_name'], $exclude, true ) ) {
                continue;
            }
            $value = maybe_unserialize( $row['option_value'] );
            $options[ $row['option_name'] ] = $value;
        }

        return $options;
    }

    /**
     * Execute a single management command via the local WP REST API.
     */
    private function execute_local_command( $cmd ) {
        $action_id = $cmd['actionId'] ?? $cmd['id'] ?? 'unknown';
        $method    = strtoupper( $cmd['method'] ?? 'GET' );
        $endpoint  = $cmd['endpoint'] ?? '';
        $body      = $cmd['body'] ?? null;

        $session = get_option( 'boostbot_support_session' );
        if ( $session && isset( $session['mode'] ) && 'provision' === $session['mode'] ) {
            if ( ! in_array( $method, [ 'GET', 'POST' ], true ) ) {
                return [
                    'actionId' => $action_id,
                    'method'   => $method,
                    'endpoint' => $endpoint,
                    'status'   => 'failed',
                    'result'   => [
                        'code'    => 'provision_mode',
                        'message' => 'Provision mode only allows reading and creating — not editing or deleting.',
                    ],
                ];
            }
        }

        $query_params = [];
        $path = $endpoint;
        if ( strpos( $endpoint, '?' ) !== false ) {
            list( $path, $qs ) = explode( '?', $endpoint, 2 );
            parse_str( $qs, $query_params );
        }

        $request = new \WP_REST_Request( $method, "/boostbot/v1/{$path}" );

        foreach ( $query_params as $key => $value ) {
            $request->set_param( $key, $value );
        }

        if ( $body && is_array( $body ) && in_array( $method, [ 'POST', 'PUT' ], true ) ) {
            $request->set_header( 'Content-Type', 'application/json' );
            foreach ( $body as $key => $value ) {
                $request->set_param( $key, $value );
            }
        }

        // Execute internally — this skips HTTP and goes directly through WP REST infrastructure
        $response = rest_do_request( $request );
        $data     = $response->get_data();
        $status   = $response->get_status();

        return [
            'actionId' => $action_id,
            'method'   => $method,
            'endpoint' => $endpoint,
            'status'   => ( $status >= 200 && $status < 300 ) ? 'completed' : 'failed',
            'result'   => $data,
        ];
    }
}
