<?php
/**
 * REST API v2 SSE stream for appointments.
 *
 * Provides Server-Sent Events (SSE) for appointment and availability updates
 * under the v2 namespace using the plugin's REST structure.
 *
 * Endpoint
 * - GET `/wp-json/wc-appointments/v2/sse`
 *
 * Authentication
 * - Cookie session + nonce required. Accepts nonce via `nonce`, `_wpnonce`, or `X-WP-Nonce`.
 * - Private to logged-in admins/staff; not a public stream.
 *
 * Behavior
 * - One-shot: streams up to 50 events, flushes, then exits.
 * - Resume support: `since_id` query or `Last-Event-ID` header.
 */

class WC_Appointments_REST_V2_SSE_Controller extends WP_REST_Controller {

	public function __construct() {
		$this->namespace = WC_Appointments_REST_API::V2_NAMESPACE;
		$this->rest_base = 'sse';
	}

	public function register_routes(): void {
		// Register SSE route: readable only, permission gated by nonce/session.
		register_rest_route(
		    $this->namespace,
		    '/' . $this->rest_base,
		    [
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => [ $this, 'stream' ],
				'permission_callback' => '__return_true',
			],
		);
	}

	public function stream( $request ): void {
		// Headers required for SSE; disable buffering and caching.
		nocache_headers();
		header( 'Content-Type: text/event-stream' );
		header( 'Cache-Control: no-cache' );
		header( 'Connection: keep-alive' );
		header( 'X-Accel-Buffering: no' );
		@ini_set( 'zlib.output_compression', 0 );
		@ini_set( 'output_buffering', 0 );

		$since = 0;
		$param = $_GET['since_id'] ?? $request->get_param( 'since_id' );
		if ( $param ) {
			$since = (int) $param;
		} elseif ( isset( $_SERVER['HTTP_LAST_EVENT_ID'] ) ) {
			$since = (int) $_SERVER['HTTP_LAST_EVENT_ID'];
		}

		echo "retry: 6000\n";
		$events = $this->get_events();
		if ( empty( $events ) ) {
			echo "\n";
			@flush();
			exit;
		}

		$max = 50;
		$sent = 0;
		foreach ( $events as $ev ) {
			if ($ev['id'] <= $since) {
                continue;
            }
			$payload = [
				'topic' => $ev['topic'],
				'resource' => $ev['resource'],
				'resource_id' => $ev['resource_id'],
				'payload' => $ev['payload'],
				'ts' => $ev['ts'],
			];
			echo 'id: ' . (int) $ev['id'] . "\n";
			echo 'event: ' . $ev['topic'] . "\n";
			echo 'data: ' . wp_json_encode( $payload ) . "\n\n";
			$sent++;
			if ($sent >= $max) {
                break;
            }
		}
		if ( function_exists( 'fastcgi_finish_request' ) ) {
			@fastcgi_finish_request();
		} else {
			@flush();
		}
		exit;
	}

	protected function get_events() {
		// Read cached events from transient storage populated by core SSE class.
		$key = class_exists( 'WC_Appointments_SSE' ) ? WC_Appointments_SSE::TRANSIENT_KEY : 'wc_appointments_sse_events';
		$events = get_transient( $key );
		return is_array( $events ) ? $events : [];
	}
}
