<?php
/**
 * Facebook OAuth2 provider
 *
 * @package FacebookSignIn
 */

namespace FacebookSignIn;

use WP_PowerSuite\Core\Contracts\ModuleSettingsRepository;
use WP_PowerSuite\OAuth\AbstractProvider;
use WP_PowerSuite\OAuth\Helpers\UrlHelper;
use WP_PowerSuite\OAuth\StateManager;
use WP_PowerSuite\OAuth\TokenHandler;
use WP_PowerSuite\OAuth\UI\ButtonRenderer;
use WP_PowerSuite\OAuth\Accounts\AccountLinkSettings;
use WP_PowerSuite\OAuth\UI\ButtonStyleHelper;

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

final class Provider extends AbstractProvider {

	public const USER_META = 'facebook_sign_in_id';

	/** @var array<string, mixed>|null Parsed module settings cache. */
	private ?array $settings_cache = null;

	public function __construct( ModuleSettingsRepository $settings, ?StateManager $state = null, ?TokenHandler $token = null ) {
		parent::__construct( $settings );
		if ( $state ) {
			$this->state = $state;
		}
		if ( $token ) {
			$this->tasks = $token;
		}
	}

	public function getProviderSlug(): string {
		return 'facebook';
	}

	public function getModuleId(): string {
		return 'facebook-sign-in';
	}

	public function getRedirectUri(): string {
		return UrlHelper::callbackUrl( $this->getProviderSlug() );
	}

	public function getLegacyAction(): string {
		return '';
	}

	protected function errorQueryArg(): string {
		return 'wpps_facebook_error';
	}

	/**
	 * @return array<string, mixed>
	 */
	public function getSettings(): array {
		if ( $this->settings_cache !== null ) {
			return $this->settings_cache;
		}
		$raw = $this->settings->all( [] );
		$this->settings_cache = [
			'app_id'               => trim( (string) ( $raw['app_id'] ?? '' ) ),
			'app_secret'           => trim( (string) ( $raw['app_secret'] ?? '' ) ),
			'redirect_after_login' => trim( (string) ( $raw['redirect_after_login'] ?? '' ) ),
			'allow_registration'          => ! empty( $raw['allow_registration'] ),
			'bypass_registration_setting' => ! empty( $raw['bypass_registration_setting'] ),
			'default_role'                => in_array( $raw['default_role'] ?? 'subscriber', [ 'subscriber', 'contributor', 'author', 'editor' ], true ) ? ( $raw['default_role'] ?? 'subscriber' ) : 'subscriber',
			'button_style'         => ButtonStyleHelper::sanitize( (string) ( $raw['button_style'] ?? 'default' ) ),
			'button_display'       => ButtonStyleHelper::sanitizeDisplay( (string) ( $raw['button_display'] ?? 'label' ) ),
			'button_label_inline'  => ButtonStyleHelper::sanitizeLabelInline( $raw['button_label_inline'] ?? false ),
			'woo_login'              => ! empty( $raw['woo_login'] ),
		];
		return $this->settings_cache;
	}

	public function getAuthorizationUrl( string $redirect_after = '', int $link_user_id = 0 ): string {
		$s     = $this->getSettings();
		$appid = (string) ( $s['app_id'] ?? '' );
		if ( $appid === '' ) {
			return '';
		}
		$st = $this->state->createState( $this->getStateStorageKey(), $redirect_after, $link_user_id );
		$q  = [
			'client_id'     => (string) ( $s['app_id'] ?? '' ),
			'redirect_uri'  => $this->getRedirectUri(),
			'state'         => $st['state'],
			'scope'         => 'email,public_profile',
			'response_type' => 'code',
		];
		$url = 'https://www.facebook.com/' . Config::API_VERSION . '/dialog/oauth?' . http_build_query( $q, '', '&', PHP_QUERY_RFC3986 );
		return $url;
	}

	/**
	 * @return array<string, mixed>|\WP_Error
	 */
	public function exchangeCodeForProfile( string $code, string $redirect_uri_used ): array|\WP_Error {
		$s = $this->getSettings();
		$data = $this->tasks->postForm(
			'https://graph.facebook.com/' . Config::API_VERSION . '/oauth/access_token',
			[
				'client_id'     => (string) ( $s['app_id'] ?? '' ),
				'client_secret' => (string) ( $s['app_secret'] ?? '' ),
				'redirect_uri'  => $redirect_uri_used,
				'code'          => $code,
			]
		);
		if ( is_wp_error( $data ) ) {
			return $data;
		}
		$at = (string) ( $data['access_token'] ?? '' );
		if ( $at === '' ) {
			return new \WP_Error( 'token', __( 'Could not get access token from Facebook.', 'wp-powersuite' ) );
		}
		$me_url = 'https://graph.facebook.com/' . Config::API_VERSION . '/me?' . http_build_query(
			[ 'fields' => 'id,name,email' ],
			'',
			PHP_QUERY_RFC3986
		);
		$me = $this->tasks->getJson(
			$me_url,
			[ 'Authorization' => 'Bearer ' . $at ],
			15
		);
		if ( is_wp_error( $me ) ) {
			return $me;
		}
		if ( empty( $me['id'] ) ) {
			return new \WP_Error( 'profile', __( 'Could not read Facebook profile.', 'wp-powersuite' ) );
		}
		$em = (string) ( $me['email'] ?? '' );
		$em = is_email( $em ) ? sanitize_email( $em ) : '';
		if ( $em === '' ) {
			return new \WP_Error( 'no_email', __( 'Facebook did not return an email. Add the email permission in your Facebook app.', 'wp-powersuite' ) );
		}
		/**
		 * Facebook Graph only returns email when the user granted the email permission.
		 * Treat it as verified for auto-link unless a site explicitly opts out.
		 *
		 * @param bool   $verified Default true when email is present.
		 * @param array  $me       Graph /me payload.
		 * @param string $email    Sanitized email.
		 */
		$verified = (bool) apply_filters( 'wpps_facebook_treat_email_as_verified', true, $me, $em );
		return [
			'id'             => (string) ( $me['id'] ),
			'email'          => $em,
			'email_verified' => $verified,
			'display_name'   => (string) ( $me['name'] ?? '' ),
		];
	}

	/**
	 * @return array<string, mixed>
	 */
	public function getUserResolverOptions(): array {
		$s  = $this->getSettings();
		$el = AccountLinkSettings::get()['email_on_login'] ?? 'auto';
		return [
			'user_meta_key'         => self::USER_META,
			'auto_register'         => (bool) ( $s['allow_registration'] ?? false ),
			'bypass_registration'  => (bool) ( $s['bypass_registration_setting'] ?? false ),
			'default_role'          => (string) ( $s['default_role'] ?? 'subscriber' ),
			'store_avatar'         => false,
			'provider'              => 'facebook',
			'email_on_login'        => 'auto' === $el ? 'auto' : 'manual',
		];
	}

	/**
	 * @param array<string, mixed> $a
	 */
	public function renderButtonMarkup( array $a ): string {
		$url = $this->getAuthorizationUrl( (string) ( $a['redirect'] ?? '' ), 0 );
		if ( $url === '' ) {
			return '';
		}
		$s     = $this->getSettings();
		$a     = ButtonStyleHelper::applyFromModuleSettings( $a, $s );
		$label = ! empty( $a['label'] ) ? (string) $a['label'] : __( 'Sign in with Facebook', 'wp-powersuite' );
		$a['provider'] = 'facebook';
		return ButtonRenderer::render( $label, $url, self::iconSvg(), $a );
	}

	public static function iconSvg(): string {
		return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="currentColor" aria-hidden="true" focusable="false"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>';
	}
}
