<?php
/**
 * Auth — bearer token check for the MCP endpoint.
 *
 * In v0.3+ the only token type we validate locally is the static "plugin
 * token" the relay holds. The relay does the heavy lifting (OAuth with the
 * AI client, JWT issuance, audience checks) and forwards already-authenticated
 * requests to us with this bearer attached.
 *
 * The token is generated on activation, can be rotated, and is sent to the
 * relay during the pair-site handshake. WordPress capability checks still run
 * on every tool call so a stolen token can't exceed the linked user's
 * permissions.
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class PCD_PC_Auth {

	const OPT_TOKEN = 'pcd_pc_mcp_token';
	const OPT_USER  = 'pcd_pc_mcp_user_id';

	public static function on_activate(): void {
		if ( ! get_option( self::OPT_TOKEN ) ) {
			update_option( self::OPT_TOKEN, self::generate_token() );
		}
		if ( ! get_option( self::OPT_USER ) ) {
			update_option( self::OPT_USER, get_current_user_id() ?: 1 );
		}
	}

	public static function get_token(): string {
		$token = get_option( self::OPT_TOKEN );
		if ( ! $token ) {
			$token = self::generate_token();
			update_option( self::OPT_TOKEN, $token );
		}
		return (string) $token;
	}

	public static function rotate_token(): string {
		$token = self::generate_token();
		update_option( self::OPT_TOKEN, $token );
		return $token;
	}

	public static function generate_token(): string {
		return 'wpc_' . wp_generate_password( 48, false );
	}

	public static function get_linked_user_id(): int {
		return (int) get_option( self::OPT_USER, 1 );
	}

	public static function set_linked_user_id( int $user_id ): void {
		update_option( self::OPT_USER, $user_id );
	}

	/**
	 * Verify the incoming MCP request — bearer must match the plugin token.
	 */
	public static function verify( WP_REST_Request $request ) {
		$header = $request->get_header( 'authorization' );
		if ( ! $header || stripos( $header, 'bearer ' ) !== 0 ) {
			return new WP_Error( 'no_auth', 'Missing bearer token.', [ 'status' => 401 ] );
		}

		$presented = trim( substr( $header, 7 ) );
		if ( ! $presented ) {
			return new WP_Error( 'no_auth', 'Missing bearer token.', [ 'status' => 401 ] );
		}

		$expected = self::get_token();
		if ( ! $expected || ! hash_equals( $expected, $presented ) ) {
			return new WP_Error( 'bad_token', 'Invalid bearer token.', [ 'status' => 401 ] );
		}

		$user_id = self::get_linked_user_id();
		if ( ! $user_id || ! get_userdata( $user_id ) ) {
			return new WP_Error( 'no_user', 'Linked user does not exist.', [ 'status' => 500 ] );
		}

		wp_set_current_user( $user_id );
		return $user_id;
	}
}
