<?php

namespace Simple_Giveaways;

/**
 * Class SG_Facebook
 */

class SG_Facebook extends GA_Integration {

	/**
	 * Get Categories
	 *
	 * @return string[]
	 */
	public function get_categories() {
		return [
			'social',
		];
	}

	/**
	 * @var string
	 */
	protected static $url = 'https://graph.facebook.com/v3.3/';

	/**
	 * Setting initial params
	 */
	public function __construct() {

		$this->title       = __( 'Facebook', 'giveasap' );
		$this->settings_id = 'sg_facebook';
		$this->image       = untrailingslashit( GASAP_URI ) . '/includes/integrations/assets/facebook.png';
		$this->desc        = __( 'This enables logging with Facebook and other features. Configure it through settings.', 'giveasap' );

		parent::__construct();

		add_action( 'sg_process_registration', array( $this, 'process_facebook_token' ) );
		add_action( 'giveasap_register_user', array( $this, 'save_token' ) );
		add_action( 'sg_form_before_button', array( $this, 'show_facebook_button' ), 90, 3 );
		add_action( 'wp_ajax_nopriv_sg_facebook_login', array( $this, 'login_with_facebook' ) );
		add_action( 'wp_ajax_sg_facebook_login', array( $this, 'login_with_facebook' ) );
		add_filter( 'sg_localized_array', array( $this, 'add_to_assets' ) );
		add_filter( 'sg_process_captcha', array( $this, 'disable_captcha_if_fb_access' ) );
		add_filter( 'sg_hidden_subscriber_meta', array( $this, 'hide_fb_subscriber_data' ) );
		add_action( 'giveasap_form_fields_table_tbody_columns', array( $this, 'add_form_field_column_body' ), 20, 3 );
	}


	/**
	 * Add the Field column.
	 *
	 * @param array   $form_field Current Form Field.
	 * @param integer $index Loop index.
	 * @param array   $field The Settings Field configuration.
	 */
	public function add_form_field_column_body( $form_field, $index, $field ) {
		$merge_field = isset( $form_field['facebook'] ) ? $form_field['facebook'] : '';
		?>
		<tr>
			<th><label for="sg-field-facebook-<?php echo esc_attr( $index ); ?>"><?php esc_html_e( 'Facebook Field', 'giveasap' ); ?></label></th>
			<td>
				<?php
				if ( ! $form_field || $form_field['name'] !== 'user_email' ) {
					?>
						<select id="sg-field-facebook-<?php echo esc_attr( $index ); ?>" name="<?php echo esc_attr( $field['name'] ); ?>[<?php echo esc_attr( $index ); ?>][facebook]" class="widefat">
							<option value=""><?php esc_html_e( 'Choose a Facebook Field', 'giveasap' ); ?></option>
							<option <?php selected( 'name', $merge_field, true ); ?> value="name"><?php esc_html_e( 'Full Name', 'giveasap' ); ?></option>
							<option <?php selected( 'first_name', $merge_field, true ); ?> value="first_name"><?php esc_html_e( 'First Name', 'giveasap' ); ?></option>
							<option <?php selected( 'last_name', $merge_field, true ); ?> value="last_name"><?php esc_html_e( 'Last Name', 'giveasap' ); ?></option>
						</select>
						<p class="description"><?php esc_html_e( 'If no field is selected, it will remain empty for the user to edit', 'giveasap' ); ?></p>
						<?php
				} else {
					?>
					<input type="hidden" name="<?php echo esc_attr( $field['name'] ); ?>[<?php echo esc_attr( $index ); ?>][facebook]" value="email" />
					<?php
					echo esc_html( 'EMAIL' );
				}
				?>
			</td>
		</tr>
		<?php
	}

	/**
	 * @param $data
	 *
	 * @return mixed
	 */
	public function hide_fb_subscriber_data( $data = array() ) {
		$data[] = '_fb_access_token';
		$data[] = '_fb_user_id';
		return $data;
	}

	/**
	 * Returning active status to the subscriber. We don't need activation since it is a real user.
	 *
	 * @param $status
	 *
	 * @return string
	 */
	public function set_active_status( $status ) {
		return 'active';
	}

	/**
	 * Login with Facebook.
	 */
	public function login_with_facebook() {
		if ( ! isset( $_POST['sg_fb_access_token'] ) ) {
			return;
		}

		$giveaway_id = isset( $_POST['sg_giveaway_id'] ) ? absint( $_POST['sg_giveaway_id'] ) : 0;
		if ( ! $giveaway_id ) {
			wp_send_json_error(
				array(
					'code'    => 'no-giveaway',
					'message' => __( 'No Giveaway Information.', 'giveasap' ),
				)
			);
			wp_die();
		}

		$token = self::exchange_token( sanitize_text_field( $_POST['sg_fb_access_token'] ), $this->get_app_id(), $this->get_app_secret() );

		if ( is_wp_error( $token ) ) {
			wp_send_json_error(
				array(
					'code'    => $token->get_error_code(),
					'message' => $token->get_error_message(),
				)
			);
			wp_die();
		}

		$_POST['sg_fb_access_token_body'] = $token;
		$access_token                     = $token['access_token'];

		$request = self::get(
			'me',
			array(
				'fields' => 'name,first_name,last_name,email',
			),
			$access_token
		);

		if ( 200 !== absint( wp_remote_retrieve_response_code( $request ) ) ) {
			wp_send_json_error(
				array(
					'code'    => wp_remote_retrieve_response_code( $request ),
					'message' => wp_remote_retrieve_response_message( $request ),
				)
			);
			wp_die();
		}

		$fields = json_decode( wp_remote_retrieve_body( $request ), true );
		$id     = isset( $fields['id'] ) ? $fields['id'] : false;

		if ( ! $id ) {
			wp_send_json_error(
				array(
					'code'    => 'no-id',
					'message' => __( 'User not found on Facebook.', 'giveasap' ),
				)
			);
			wp_die();
		}

		$subscriber = $this->find_subscriber_by_fb_id_on_giveaway( $id, $giveaway_id );
		if ( false !== $subscriber ) {
			$this->save_token( $subscriber->get_id() );
			$this->save_fb_user_id( $subscriber->get_id(), $id );
			$from_page = isset( $_POST['sg_from_page'] ) ? esc_url_raw( $_POST['sg_from_page'] ) : '';
			wp_send_json_success(
				array(
					'redirect' => $subscriber->get_giveaway_link( $from_page ),
				)
			);
			wp_die();
		}

		$email = isset( $fields['email'] ) ? $fields['email'] : false;

		if ( ! $email ) {
			wp_send_json_error(
				array(
					'code'    => 'no-email',
					'message' => __( 'No email information provided by Facebook.', 'giveasap' ),
				)
			);
			wp_die();
		}

		$subscriber = $this->find_subscriber_by_email_on_giveaway( $email, $giveaway_id );
		if ( false !== $subscriber ) {
			$this->save_token( $subscriber->get_id() );
			$this->save_fb_user_id( $subscriber->get_id(), $id );
			$from_page = isset( $_POST['sg_from_page'] ) ? esc_url_raw( $_POST['sg_from_page'] ) : '';
			wp_send_json_success(
				array(
					'redirect' => $subscriber->get_giveaway_link( $from_page ),
				)
			);
			wp_die();
		}

		// Let's fill the sg_form from FB data.
		$form_fields = giveasap_get_form_fields( $giveaway_id );
		$posted_form = isset( $_POST['sg_form'] ) ? wp_kses_post_deep( wp_unslash( $_POST['sg_form'] ) ) : array();
		$fields_keys = array_keys( $fields );

		foreach ( $form_fields as $field_key => $form_field ) {
			if ( isset( $form_field['facebook'] ) && $form_field['facebook'] ) {
				if ( isset( $fields[ $form_field['facebook'] ] ) && $fields[ $form_field['facebook'] ] ) {
					$posted_form[ $field_key ] = $fields[ $form_field['facebook'] ];
				}
			} else {
				foreach ( $fields_keys as $fb_field_key ) {
					if ( false !== strpos( $field_key, $fb_field_key ) ) {
						$posted_form[ $field_key ] = $fields[ $fb_field_key ];
						break;
					}
				}
			}
		}

		$_POST['sg_form'] = $posted_form;

		add_filter( 'giveasap_register_user_status', array( $this, 'set_active_status' ) );
		add_filter( 'sg_skip_form_fields_validation', '__return_true' );
		$front = new \GiveASAP_Front( get_post( $giveaway_id ), false );
		$front->creating_steps( false );
		remove_filter( 'sg_skip_form_fields_validation', '__return_true' );
		remove_filter( 'giveasap_register_user_status', array( $this, 'set_active_status' ) );

		if ( $front->errors->get_error_codes() ) {
			wp_send_json_error(
				array(
					'code'    => $front->errors->get_error_code(),
					'message' => $front->errors->get_error_message(),
				)
			);
			wp_die();
		}

		if ( null === $front->user ) {
			wp_send_json_error(
				array(
					'code'    => 'no-user',
					'message' => __( 'Something went wrong. Try again later.', 'giveasap' ),
				)
			);
			wp_die();
		}

		$subscriber = giveasap_get_subscriber( $front->user );
		$this->save_token( $subscriber->get_id() );
		$this->save_fb_user_id( $subscriber->get_id(), $id );
		$from_page = isset( $_POST['sg_from_page'] ) ? esc_url_raw( $_POST['sg_from_page'] ) : '';

		wp_send_json_success(
			array(
				'redirect' => $front->redirect_link ? $front->redirect_link : $subscriber->get_giveaway_link( $from_page ),
			)
		);
		wp_die();
	}

	/**
	 * Find Subscriber by FB ID and Giveaway ID
	 *
	 * @param string $id FB user ID.
	 * @return false|SG_Subscriber
	 */
	public function find_subscriber_by_fb_id_on_giveaway( $id, $giveaway_id ) {
		global $wpdb;

		$sql           = 'SELECT giveasap_id FROM ' . $wpdb->giveasapmeta . ' sg_meta';
		$sql          .= ' INNER JOIN ' . $wpdb->giveasap_entries . ' as subscribers ON subscribers.id = sg_meta.giveasap_id';
		$sql          .= ' WHERE sg_meta.meta_key=%s AND sg_meta.meta_value=%s AND subscribers.post_id=%d';
		$subscriber_id = $wpdb->get_var( $wpdb->prepare( $sql, '_fb_user_id', $id, $giveaway_id ) );
		if ( null === $subscriber_id ) {
			return false;
		}

		return giveasap_get_subscriber( $subscriber_id );
	}

	/**
	 * Find Subscriber by FB ID and Giveaway ID
	 *
	 * @param string $email Email.
	 * @return false|SG_Subscriber
	 */
	public function find_subscriber_by_email_on_giveaway( $email, $giveaway_id ) {
		global $wpdb;

		$subscriber = giveasap_get_user_by_email( $email, $giveaway_id );

		if ( null === $subscriber ) {
			return false;
		}

		return giveasap_get_subscriber( $subscriber );
	}

	/**
	 * Save the FB token if exists.
	 *
	 * @param int $entry_id Subscriber ID.
	 */
	public function save_token( $entry_id ) {
		if ( isset( $_POST['sg_fb_access_token_body'] ) ) {
			giveasap_update_meta( $entry_id, '_fb_access_token', Helpers::unslash_and_clean( $_POST['sg_fb_access_token_body'] ) );
		}
	}

	/**
	 * Save the FB token if exists.
	 *
	 * @param int $entry_id Subscriber ID.
	 */
	public function save_fb_user_id( $entry_id, $user_id ) {
		giveasap_update_meta( $entry_id, '_fb_user_id', sanitize_text_field( $user_id ) );
	}

	/**
	 * If we have an FB Access Token, we don't need Captcha.
	 *
	 * @param $bool
	 *
	 * @return boolean
	 */
	public function disable_captcha_if_fb_access( $bool ) {
		if ( $bool ) {

			$fb_access_token = isset( $_POST['sg_fb_access_token'] ) ? sanitize_text_field( $_POST['sg_fb_access_token'] ) : false;

			if ( ! $fb_access_token ) {
				return $bool;
			}

			return false;
		}
		return $bool;
	}

	/**
	 * Get the App secret.
	 *
	 * @return bool|string
	 */
	public function get_app_secret() {
		$settings = $this->get_settings();
		return isset( $settings['fb_app_secret'] ) ? $settings['fb_app_secret'] : false;
	}

	/**
	 * Get the App ID.
	 *
	 * @return bool|string
	 */
	public function get_app_id() {
		$settings = $this->get_settings();
		return isset( $settings['fb_app_id'] ) ? $settings['fb_app_id'] : false;
	}

	/**
	 * Add App ID to assets object.
	 *
	 * @param $array
	 *
	 * @return mixed
	 */
	public function add_to_assets( $array ) {
		$array['fb_app_id'] = $this->get_app_id();
		return $array;
	}

	/**
	 * Setting Fields
	 */
	public function set_fields() {
		$this->fields = apply_filters(
			'integration_fields_' . $this->settings_id,
			array(
				'fb_app_id'      => array(
					'type'    => 'text',
					'name'    => 'fb_app_id',
					'title'   => __( 'APP ID', 'giveasap' ),
					'default' => '',
				),
				'fb_app_secret'  => array(
					'type'    => 'text',
					'name'    => 'fb_app_secret',
					'title'   => __( 'APP Secret Key', 'giveasap' ),
					'default' => '',
				),
				'oauth_callback' => array(
					'type'    => 'custom',
					'name'    => 'oauth_callback_url',
					'title'   => __( 'Callback URL', 'giveasap' ),
					'default' => '',
					'render'  => array( $this, 'oauth_callback_url_field' ),
				),
				'fb_locale'      => array(
					'type'    => 'text',
					'name'    => 'fb_locale',
					'title'   => __( 'Facebook Login Locale', 'giveasap' ),
					'default' => 'en_US',
					'desc'    => '<a href="https://developers.facebook.com/docs/internationalization#locales" target="_blank">' . __( 'Learn about localizing Facebook Social Login', 'giveasap' ) . '</a>',
				),
			)
		);
	}

	/**
	 * @param $field
	 */
	public function oauth_callback_url_field( $field ) {
		echo '<tr>';

		echo '<th>' . $field['title'] . '</th>';

		echo '<td>';

		echo '<code>' . get_site_url() . '</code>';
		echo '<p>' . esc_html__( 'Use this URL when setting up the Facebook App details as a Callback URL.', 'giveapsa' ) . '</p>';
		echo '</td>';

		echo '</tr>';
	}

	/**
	 * Show Facebook button.
	 *
	 * @since 2.23.0
	 */
	function show_facebook_button() {
		if ( ! $this->get_app_id() ) {
			return;
		}

		if ( ! $this->get_app_secret() ) {
			return;
		}

		$settings = $this->get_settings();
		$locale   = isset( $settings['fb_locale'] ) && $settings['fb_locale'] ? $settings['fb_locale'] : 'en_US';
		?>
		<div class="sg-facebook-login-button">
			<fb:login-button scope="public_profile,email"
							 data-size="large"
							 data-button-type="continue_with"
							 data-use-continue-as="true"
							 onlogin="sgCheckFBLoginState();">
			</fb:login-button>
		</div>
		<script>
			window.sg_fb_locale = '<?php echo esc_html( $locale ); ?>';
		</script>
		<?php
	}

	/**
	 * Process the captcha and add error if wrong.
	 *
	 * @param \GiveASAP_Front $front
	 */
	public function process_facebook_token( $front ) {
		if ( isset( $_POST['sg_fb_access_token_body'] ) ) {
			return;
		}

		$fb_access_token = isset( $_POST['sg_fb_access_token'] ) ? sanitize_text_field( $_POST['sg_fb_access_token'] ) : false;

		// No FB Token posted. No need to process FB.
		if ( ! $fb_access_token ) {
			return;
		}

		$token = self::exchange_token( $fb_access_token, $this->get_app_id(), $this->get_app_secret() );

		if ( is_wp_error( $token ) ) {
			$front->add_error( $token->get_error_code(), $token->get_error_message() );
			return;
		}

		$_POST['sg_fb_access_token_body'] = $token;
	}

	/**
	 * Exchange a temporary access token for a long lasting one.
	 *
	 * @param $token
	 * @param $app_id
	 * @param $app_secret
	 *
	 * @return array|mixed|object|string|\WP_Error
	 */
	public static function exchange_token( $token, $app_id, $app_secret ) {
		$url = 'https://graph.facebook.com/oauth/access_token';
		$url = add_query_arg(
			array(
				'grant_type'        => 'fb_exchange_token',
				'client_id'         => $app_id,
				'client_secret'     => $app_secret,
				'fb_exchange_token' => $token,
				'access_token'      => $token,
			),
			$url
		);

		$response = wp_remote_get( $url );
		$body     = wp_remote_retrieve_body( $response );
		$body     = json_decode( $body, true );

		if ( isset( $body['error'] ) ) {
			return new \WP_Error( 'fb-code-' . $body['error']['code'], $body['error']['message'] );
		}

		return $body;
	}

	/**
	 * Return the array with facebook token.
	 *
	 * @param $subscriber_id
	 *
	 * @return array|null
	 */
	public static function get_subscriber_token( $subscriber_id ) {
		return giveasap_get_meta( $subscriber_id, '_fb_access_token', true );
	}

	/**
	 * @param $path
	 * @param $data
	 *
	 * @return array|bool|\WP_Error
	 */
	public static function get( $path, $data, $access_token ) {
		return self::request( $path, $data, $access_token, 'get' );
	}

	/**
	 * @param $path
	 * @param $data
	 *
	 * @return array|bool|\WP_Error
	 */
	public static function post( $path, $data, $access_token ) {
		return self::request( $path, $data, $access_token, 'post' );
	}

	/**
	 * Request
	 *
	 * @param        $path
	 * @param array  $data
	 * @param string $method
	 */
	public static function request( $path, $data = array(), $access_token = '', $method = 'get' ) {
		$url  = self::$url . $path;
		$url  = add_query_arg( 'access_token', $access_token, $url );
		$data = array( 'body' => $data );

		if ( 'get' === $method ) {
			return wp_remote_get( $url, $data );
		} elseif ( 'post' === $method ) {
			return wp_remote_post( $url, $data );
		}

		return false;
	}
}

add_filter( 'giveasap_integrations', '\Simple_Giveaways\sg_facebook_register' );

/**
 * Registering Math Captcha
 *
 * @return array
 */
function sg_facebook_register( $integrations ) {

	$integrations['sg_facebook'] = '\Simple_Giveaways\SG_Facebook';

	return $integrations;
}
