<?php
namespace SabaiApps\Directories\Component\FrontendSubmit\Helper;

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Exception;

class OauthHelper {

	public function isEnabled( Application $application ) {
		return (bool) $application->getComponent( 'FrontendSubmit' )->getConfig( 'login', 'oauth', 'enable' );
	}

	public function providers( Application $application, $activeOnly = true, $labelOnly = false ) {
		$providers = $application->Filter(
			'frontendsubmit_oauth_providers',
			array(
				'facebook' => array(
					'label' => 'Facebook',
					'color' => '#4267B2',
					'icon'  => 'fa-brands fa-facebook',
				),
				'google'   => array(
					'label' => 'Google',
					'color' => '#DB4437',
					'icon'  => 'fa-brands fa-google',
				),
				'linkedin' => array(
					'label' => 'LinkedIn',
					'color' => '#0A66C2',
					'icon'  => 'fa-brands fa-linkedin',
				),
				'github'   => array(
					'label' => 'GitHub',
					'color' => '#171515',
					'icon'  => 'fa-brands fa-github',
				),
			)
		);
		if ( $activeOnly ) {
			$active_providers = $application->getComponent( 'FrontendSubmit' )->getConfig( 'login', 'oauth', 'providers' );
			if ( ! empty( $active_providers['default'] ) ) {
				$_providers = array();
				foreach ( $active_providers['default'] as $active_provider ) {
					if ( isset( $providers[ $active_provider ] ) ) {
						$_providers[ $active_provider ]          = $providers[ $active_provider ];
						$_providers[ $active_provider ]['label'] = $active_providers['options'][ $active_provider ];
					}
				}
				$providers = $_providers;
			} else {
				$providers = array();
			}
		}
		if ( $labelOnly ) {
			foreach ( array_keys( $providers ) as $provider_name ) {
				$providers[ $provider_name ] = $providers[ $provider_name ]['label'];
			}
		}

		return $providers;
	}

	public function isValidProvider( Application $application, $providerName, $activeOnly = true ) {
		$providers = $this->providers( $application, $activeOnly );
		return isset( $providers[ $providerName ] );
	}

	public function provider( Application $application, $providerName, $redirectUrl ) {
		if ( $this->isValidProvider( $application, $providerName ) ) {
			$settings         = $application->getComponent( 'FrontendSubmit' )->getConfig( 'login', 'oauth', 'provider_settings', $providerName );
			$provider_options = array(
				'clientId'     => isset( $settings['client_id'] ) ? $settings['client_id'] : '',
				'clientSecret' => isset( $settings['client_secret'] ) ? $settings['client_secret'] : '',
				'redirectUri'  => $redirectUrl,
			);
			switch ( $providerName ) {
				case 'facebook':
					$provider = new \League\OAuth2\Client\Provider\Facebook(
						$provider_options + array(
							'graphApiVersion' => 'v2.10',
						)
					);
					$scopes   = array( 'email' );
					break;
				case 'github':
					$provider = new \League\OAuth2\Client\Provider\Github( $provider_options );
					$scopes   = array( 'user', 'user:email' );
					break;
				case 'google':
					$provider = new \League\OAuth2\Client\Provider\Google( $provider_options );
					$scopes   = array( 'openid', 'profile', 'email' );
					break;
				case 'linkedin':
					$provider = new \League\OAuth2\Client\Provider\LinkedIn( $provider_options );
					$scopes   = array( 'r_liteprofile', 'r_emailaddress' );
					break;
				default:
					$provider = $application->Filter( 'frontendsubmit_oauth_provider', null, array( $providerName, $settings, $redirectUrl ) );
			}
		}

		if ( empty( $provider ) ) {
			throw new Exception\InvalidArgumentException( sprintf( 'Invalid login provider: %s', $providerName ) );
		}

		if ( ! isset( $scopes ) ) {
			$scopes = $provider->getDefaultScopes();
		}

		return array( $provider, $scopes );
	}

	public function settingsForm( Application $application, array $settings, array $parents = array() ) {
		$providers              = $this->providers( $application, false, true );
		$provider_settings_form = array();
		foreach ( array_keys( $providers ) as $provider_name ) {
			$_provider_settings      = isset( $settings['provider_settings'][ $provider_name ] ) ? $settings['provider_settings'][ $provider_name ] : array();
			$_provider_settings_form = array(
				'client_id'     => array(
					'#type'          => 'textfield',
					'#title'         => __( 'Client ID', 'directories-pro' ),
					'#default_value' => isset( $_provider_settings['client_id'] ) ? $_provider_settings['client_id'] : null,
					'#horizontal'    => true,
					'#required'      => function ( $form ) use ( $provider_name, $parents ) {
						return ( $providers = $form->getValue( array_merge( $parents, array( 'providers' ) ) ) ) && in_array( $provider_name, $providers['default'] );
					},
				),
				'client_secret' => array(
					'#type'          => 'textfield',
					'#title'         => __( 'Client Secret', 'directories-pro' ),
					'#default_value' => isset( $_provider_settings['client_secret'] ) ? $_provider_settings['client_secret'] : null,
					'#horizontal'    => true,
					'#required'      => function ( $form ) use ( $provider_name, $parents ) {
						return ( $providers = $form->getValue( array_merge( $parents, array( 'providers' ) ) ) ) && in_array( $provider_name, $providers['default'] );
					},
				),
				'redirect_url'  => array(
					'#type'       => 'item',
					'#title'      => __( 'OAuth Redirect URL', 'directories-pro' ),
					'#markup'     => '<code class="' . DRTS_BS_PREFIX . 'user-select-all">' . $application->MainUrl(
						'/' . $application->getComponent( 'FrontendSubmit' )->getSlug( 'login' ),
						array(
							'oauth'    => 1,
							'provider' => $provider_name,
						)
					) . '</code>',
					'#horizontal' => true,
					'#disabled'   => true,
				),
			);
			switch ( $provider_name ) {
				case 'facebook':
					$_provider_settings_form['client_id']['#title']     = __( 'App ID', 'directories-pro' );
					$_provider_settings_form['client_secret']['#title'] = __( 'App Secret', 'directories-pro' );
					break;
				case 'github':
				case 'google':
				case 'linkedin':
					break;
				default:
					$_provider_settings_form = $application->Filter( 'frontendsubmit_oauth_provider_settings_form', $_provider_settings_form, array( $provider_name, $_provider_settings ) );
			}
			if ( ! empty( $_provider_settings_form ) ) {
				$provider_settings_form[ $provider_name ] = array(
					'#title'  => sprintf( __( 'Social Login Provider Settings (%s)', 'directories-pro' ), $providers[ $provider_name ] ),
					'#class'  => 'drts-form-label-lg',
					'#states' => array(
						'visible' => array(
							sprintf( '[name="%s[default][]"][data-option-value="%s"]', $application->Form_Form_fieldName( array( $parents, 'providers' ) ), $provider_name ) => array(
								'type'  => 'empty',
								'value' => false,
							),
						),
					),
				) + $_provider_settings_form;
			}
		}
		$form = array(
			'enable'    => array(
				'#type'          => 'checkbox',
				'#horizontal'    => true,
				'#title'         => __( 'Enable social login', 'directories-pro' ),
				'#default_value' => ! empty( $settings['enable'] ),
				'#weight'        => 1,
			),
			'providers' => array(
				'#type'                   => 'options',
				'#horizontal'             => true,
				'#title'                  => __( 'Social login providers', 'directories-pro' ),
				'#disable_add'            => true,
				'#disable_icon'           => true,
				'#disable_add_csv'        => true,
				'#multiple'               => true,
				'#options_value_disabled' => array_keys( $providers ),
				'#default_value'          => array(
					'options' => isset( $settings['providers']['options'] ) ? array_intersect_key( $settings['providers']['options'], $providers ) : $providers,
					'default' => isset( $settings['providers']['default'] ) ? $settings['providers']['default'] : array_keys( $providers ),
				),
				'#options_placeholder'    => $providers,
				'#weight'                 => 2,
				'#states'                 => array(
					'visible' => array(
						$enable_selector = 'input[name="' . $application->Form_Form_fieldName( array( $parents, 'enable' ) ) . '"]' => array(
							'type'  => 'checked',
							'value' => true,
						),
					),
				),
			),
		);
		if ( ! empty( $provider_settings_form ) ) {
			$form['provider_settings'] = array(
				'#weight' => 3,
				'#states' => array(
					'visible' => array(
						$enable_selector => array(
							'type'  => 'checked',
							'value' => true,
						),
					),
				),
			) + $provider_settings_form;
		}
		return $form;
	}

	public function getUserData( Application $application, $providerName, \League\OAuth2\Client\Provider\ResourceOwnerInterface $resourceOwner ) {
		switch ( $providerName ) {
			case 'facebook':
				$data = array(
					'name'       => $resourceOwner->getName(),
					'first_name' => $resourceOwner->getFirstName(),
					'last_name'  => $resourceOwner->getLastName(),
					'email'      => $resourceOwner->getEmail(),
					'url'        => $resourceOwner->getLink(),
					'image_url'  => $resourceOwner->getPictureUrl(),
				);
				break;
			case 'github':
				$data = array(
					'name'  => $resourceOwner->getName(),
					'email' => $resourceOwner->getEmail(),
					'url'   => $resourceOwner->getUrl(),
				);
				break;
			case 'google':
				$data = array(
					'name'       => $resourceOwner->getName(),
					'first_name' => $resourceOwner->getFirstName(),
					'last_name'  => $resourceOwner->getLastName(),
					'email'      => $resourceOwner->getEmail(),
					'image_url'  => $resourceOwner->getAvatar(),
				);
				break;
			case 'linkedin':
				$data = array(
					'name'       => $resourceOwner->getName(),
					'first_name' => $resourceOwner->getFirstName(),
					'last_name'  => $resourceOwner->getLastName(),
					'email'      => $resourceOwner->getEmail(),
					'image_url'  => $resourceOwner->getImageUrl(),
				);
				break;
			default:
				$data = $application->Filter( 'frontendsubmit_oauth_user_data', array(), array( $providerName, $resourceOwner ) );
		}

		// Check data
		if ( empty( $data ) ) {
			throw new Exception\RuntimeException( sprintf( 'No user data returned from login provider: %s', $providerName ) );
		}
		foreach ( array( 'name', 'email' ) as $key ) {
			if ( empty( $data[ $key ] ) ) {
				throw new Exception\RuntimeException( sprintf( 'Required user data (%1$s) was not returned from login provider: %2$s', $key, $providerName ) );
			}
		}

		return $data;
	}

	public function buttons( Application $application, array $params = array(), $activeOnly = true ) {
		$html = array();
		foreach ( $this->providers( $application, $activeOnly ) as $provider_name => $provider ) {
			$html[] = $application->LinkTo(
				sprintf( __( 'Login with %s', 'directories-pro' ), $provider['label'] ),
				$application->Url(
					'/' . $application->getComponent( 'FrontendSubmit' )->getSlug( 'login' ),
					array(
						'oauth'    => 1,
						'provider' => $provider_name,
					) + $params
				),
				array(
					'icon' => $provider['icon'],
				),
				array(
					'class' => DRTS_BS_PREFIX . 'btn ' . DRTS_BS_PREFIX . 'btn-lg',
					'style' => 'color:#fff;background-color:' . $provider['color'],
				)
			);
		}
		return '<div class="' . DRTS_BS_PREFIX . 'd-grid ' . DRTS_BS_PREFIX . 'gap-2">' . implode( PHP_EOL, $html ) . '</div>';
	}
}
