<?php

/**
 * Class SG_Facebook
 */

class SG_Facebook extends GA_Integration {

	/**
	 * @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( 'sg_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 $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 $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'] ) ? $_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( $_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'] ) ? $_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'] ) ? $_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 = sg_get_form_fields( $giveaway_id );
        $posted_form = isset( $_POST['sg_form'] ) ? $_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 = sg_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'] ) ? $_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 sg_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 sg_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', $_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', $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'] ) ? $_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 $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'] ) ? $_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', 'sg_facebook_register' );

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

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

	return $integrations;
}