<?php
/**
 * Single init hook: dispatches ?wpps_auth= / legacy admin-ajax OAuth callbacks.
 *
 * @package WP_PowerSuite\OAuth
 */

namespace WP_PowerSuite\OAuth;

use WP_PowerSuite\OAuth\Helpers\UrlHelper;

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

final class CallbackHandler {

	private static ?self $instance = null;

	/** @var array<string, AbstractProvider> */
	private array $providers = [];

	/** @var list<string> */
	private array $legacy_actions = [];

	private bool $hook_added = false;

	public static function instance(): self {
		if ( self::$instance === null ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	public function register( AbstractProvider $provider ): void {
		$this->providers[ $provider->getProviderSlug() ] = $provider;
		$legacy = $provider->getLegacyAction();
		if ( $legacy !== '' ) {
			$this->legacy_actions[] = $legacy;
		}
		if ( ! $this->hook_added ) {
			$this->hook_added = true;
			add_action( 'init', [ $this, 'dispatch' ], 0 );
		}
	}

	/**
	 * @return array<string, AbstractProvider>
	 */
	public function getProviders(): array {
		return $this->providers;
	}

	public function getProvider( string $slug ): ?AbstractProvider {
		$slug = sanitize_key( $slug );
		return $this->providers[ $slug ] ?? null;
	}

	public function dispatch(): void {
		if ( $this->providers === [] || ! $this->looksLikeOAuthCallbackRequest() ) {
			return;
		}
		foreach ( $this->providers as $provider ) {
			if ( $provider->isThisCallbackRequest() ) {
				$provider->handleQueryCallback();
				return;
			}
		}
	}

	/**
	 * Cheap gate so non-callback requests skip provider iteration.
	 */
	private function looksLikeOAuthCallbackRequest(): bool {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( isset( $_GET[ UrlHelper::AUTH_QUERY_PARAM ] ) ) {
			return true;
		}
		if ( $this->legacy_actions === [] ) {
			return false;
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( ! isset( $_GET['action'] ) ) {
			return false;
		}
		$action = (string) wp_unslash( (string) $_GET['action'] );
		return in_array( $action, $this->legacy_actions, true );
	}
}
