<?php
/**
 * Route handler for logging generation events.
 *
 * @package    100Prints
 */

class Hundred_Prints_Route_Log {

	/**
	 * Register routes.
	 */
	public function register_routes() {
		register_rest_route( '100prints/v1', '/log-generation', [
			[
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => [ $this, 'log_generation' ],
				'permission_callback' => [ $this, 'permission_check' ],
			],
		] );
	}

	/**
	 * Permission check callback.
	 */
	public function permission_check( $request ) {
		$params = $request->get_json_params();
		if ( empty( $params ) ) {
			$params = json_decode( $request->get_body(), true );
		}
		
		$template_id = isset( $params['templateId'] ) ? $params['templateId'] : '';
		$expires     = $request->get_param( 'expires' );
		$signature   = $request->get_param( 'sig' );

		if ( empty( $template_id ) || empty( $expires ) || empty( $signature ) ) {
			return new WP_Error( '100prints_unauthorized', 'Missing signature or template ID.', [ 'status' => 403 ] );
		}

		if ( time() > (int) $expires ) {
			return new WP_Error( '100prints_expired', 'Request expired.', [ 'status' => 403 ] );
		}

		$expected = hash_hmac( 'sha256', $template_id . '|' . $expires . '|log', wp_salt( 'auth' ) );
		if ( ! hash_equals( $expected, $signature ) ) {
			return new WP_Error( '100prints_forbidden', 'Invalid signature.', [ 'status' => 403 ] );
		}

		// Rate limiting by IP — fixed-window (60 s window, max 30 requests).
		// Using a fixed window ensures the block always expires within one window
		// period, even if a scanner hammers the endpoint continuously.
		$ip            = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : 'unknown';
		$transient_key = '100p_limit_log_' . md5( $ip );
		$window_size   = MINUTE_IN_SECONDS; // 60 seconds
		$limit         = 30;
		$now           = time();

		$data = get_transient( $transient_key );

		// If no data or the window has expired naturally, start a fresh window.
		if ( ! is_array( $data ) || ( $now - $data['start'] ) >= $window_size ) {
			$data = [
				'start' => $now,
				'count' => 0,
			];
		}

		if ( $data['count'] >= $limit ) {
			// Tell the client exactly how many seconds remain in this window.
			$retry_after = $window_size - ( $now - $data['start'] );
			return new WP_REST_Response(
				[
					'code'    => '100prints_rate_limit',
					'message' => 'Too many requests. Please wait before trying again.',
				],
				429,
				[ 'Retry-After' => (string) max( 1, $retry_after ) ]
			);
		}

		// Increment the counter and save with a TTL that expires at window end,
		// not at "now + 60s", so repeated hits cannot extend the block.
		$data['count']++;
		$remaining_ttl = $window_size - ( $now - $data['start'] );
		set_transient( $transient_key, $data, max( 1, $remaining_ttl ) );

		return true;
	}

	/**
	 * Log a generation event.
	 */
	public function log_generation( $request ) {
		$params = $request->get_json_params();
		if ( empty( $params ) ) {
			$params = json_decode( $request->get_body(), true );
		}
		if ( ! is_array( $params ) ) {
			$params = [];
		}

		$settings = hundred_prints_get_settings();
		if ( isset( $settings['log_enabled'] ) && ! $settings['log_enabled'] ) {
			return rest_ensure_response( [ 'success' => true, 'logged' => false ] );
		}

		$template_id = isset( $params['templateId'] ) ? hundred_prints_sanitize_template_id( $params['templateId'] ) : '';
		if ( empty( $template_id ) ) {
			return new WP_Error( '100prints_bad_request', 'Missing template ID', [ 'status' => 400 ] );
		}

		$visitor_ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';

		$args = [
			'template_id'   => $template_id,
			'template_name' => isset( $params['templateName'] ) ? sanitize_text_field( $params['templateName'] ) : '',
			'page_id'       => isset( $params['pageId'] ) ? absint( $params['pageId'] ) : 0,
			'format'        => isset( $params['format'] ) ? sanitize_key( $params['format'] ) : 'pdf',
			'status'        => isset( $params['status'] ) ? sanitize_key( $params['status'] ) : 'success',
			'quality'       => isset( $params['quality'] ) ? sanitize_key( $params['quality'] ) : 'high',
			'variables'     => isset( $params['variables'] ) && is_array( $params['variables'] ) ? $params['variables'] : [],
			'visitor_ip'    => $visitor_ip,
		];

		$analytics_service = new Hundred_Prints_Analytics_Service();
		$logged = $analytics_service->log_generation( $args );

		return rest_ensure_response( [ 'success' => true, 'logged' => (bool) $logged ] );
	}
}
