<?php

/**
 * Plugin glomex_oEmbed
 *
 * @package   glomex_oEmbed
 * @author    glomex <info@glomex.com>
 * @copyright 2022 glomex
 * @license   Apache-2.0
 * @link      https://glomex.com
 */

namespace glomex_oEmbed\Internals;

use glomex_oEmbed\Engine\Base;

/**
 * Internal glomex oEmbed integration wrapper
 */
class OembedExtender extends Base {

	/**
	 * @var string
	 */
	public $integrationId = '';

	/**
	 * @var array
	 */
	private $parsedUrl = array();

	/**
	 * @var array
	 */
	private $reqQuery = array();

	/**
	 * @var string
	 */
	private $errorString = '';

	/**
	 * This is the url passed in a WP editor for embedding
	 *
	 * @var string
	 */
	private $url = '';

	/**
	 * @var array
	 */
	private $json = array();

	/**
	 * OembedExtender construct
	 */
	public function __construct() {
		parent::initialize();
	}

	/**
	 * This function is intended to run various hooks upon initialization
	 */
	public function run_hooks(): void {
		if ( ! isset( $this->settings['includeScriptEverywhere'] ) ) {
			return;
		}

		/**
		 * Let's set up only one permanent glomex player js on all pages
		 */
		\add_action(
			'wp_head',
			function () {
				// phpcs:ignore
				\wp_enqueue_script(
					'glomex-player',
					'//player.glomex.com/integration/1/glomex-player.js',
					array( 'jquery' ),
					GLOMEX_OEMBED_VERSION,
					true
				);
			},
			20
		);

		/**
		 * Let's filter out all unneeded instances of glomex-player.js on page. No need to download and instantiate it
		 * multiple times on the frontend
		 */
		\add_filter(
			'the_content',
			function ( string $content ) {
				return \str_replace(
					\sprintf(
						// phpcs:ignore
						'<script src="%s"></script><glomex-player',
						\esc_url_raw( 'https://player.glomex.com/integration/1/glomex-player.js' )
					),
					'<glomex-player',
					$content
				);
			}
		);

		/**
		 * Set up async loading for the script
		 */
		\add_filter(
			'script_loader_tag',
			function ( string $tag, string $handle ) {
				if ( $handle !== 'glomex-player' ) {
					return $tag;
				}

				return \str_replace( '></script>', ' async></script>', $tag );
			},
			10,
			2
		);
	}

	/**
	 * Main init function
	 *
	 * @param array        $matches Contains all matches of regexp.
	 * @param array        $attr Contains attribute.
	 * @param string       $url The url for the embed.
	 * @param array|string $rawattr Raw attribute.
	 */
	public function init( array $matches, array $attr, string $url, $rawattr ): string {
		return $this->handle_glomex_oembed_url( $url );
	}

	/**
	 * Set Url
	 *
	 * @param string $url The url for the embed.
	 * @return $this
	 */
	public function set_url( string $url ): self {
		$this->url = \esc_url_raw($url);

		$parsedUrl = \wp_parse_url( $url );

		if ( ! \is_array( $parsedUrl ) || ! isset( $parsedUrl['host'] ) || ! isset( $parsedUrl['path'] ) ) {
			return $this;
		}

		$this->parsedUrl = $parsedUrl;

		return $this;
	}

	/**
	 * Get Oembed Url
	 */
	public function get_oembed_url(): string {
		return $this->buildUrl();
	}

	/**
	 * Handles our oEmbed functionality
	 *
	 * @param string $url The url for the embed.
	 */
	public function handle_glomex_oembed_url( string $url ): string {
		if ( \is_null( $this->generate_oembed_data( $url ) ) ) {
			return \sprintf(
				'<p><a href="%s">%s %s</a></p>',
				\esc_url_raw( $this->url ),
				\__( "We could not parse the URL you've passed -", 'glomex-oembed' ),
				\esc_html( $this->url )
			);
		}

		$this->handleRequest();

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

		return $this->json['html'];
	}

	/**
	 * Generate oembed data
	 *
	 * @param string $url The url for the embed.
	 */
	public function generate_oembed_data( string $url ): ?bool {
		$this->set_url( $url );

		if ( empty( $this->parsedUrl ) ) {
			return null;
		}

		$this->setReqQuery()
		     ->setIntegrationId()
		     ->setVideoPrefix();

		$this->parsedUrl['query'] = \http_build_query(
			array( 'integrationId' => $this->integrationId )
		);

		return true;
	}

	/**
	 * Handle Request
	 */
	private function handleRequest(): void {
		if ( ! empty( $this->errorString ) ) {
			return;
		}

		$httpOptions = array(
			'headers' => array(
				'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',
			),
		);

		$da_response = \wp_remote_get( $this->buildUrl(), $httpOptions );

		if ( \is_wp_error( $da_response ) || 200 !== $da_response['response']['code'] ) {
			$this->errorString = \sprintf(
				'<p><a href="%s">%s</a></p>',
				\esc_url_raw( $this->url ),
				\__( 'View Video - faulty response from the service', 'glomex-oembed' )
			);
			return;
		}

		$this->json = (array) \json_decode( \wp_remote_retrieve_body( $da_response ), true );

		if ( \json_last_error() !== JSON_ERROR_NONE || empty( $this->json['html'] ) ) {
			$this->errorString = \sprintf(
				'<p><a href="%s">%s</a></p>',
				\esc_url_raw( $this->url ),
				\__( 'View Video - some error with response', 'glomex-oembed' )
			);
		}
	}

	/**
	 * Sets up query of the parsed url
	 */
	private function setReqQuery(): self {
		if ( ! empty( $this->errorString ) ) {
			return $this;
		}

		$req_query = array();

		if ( isset( $this->parsedUrl['query'] ) ) {
			\parse_str( $this->parsedUrl['query'], $req_query );
		}

		$this->reqQuery = $req_query;

		return $this;
	}

	/**
	 * Sets up video prefix
	 */
	private function setVideoPrefix(): self {
		if ( ! empty( $this->errorString ) ) {
			return $this;
		}

		$this->parsedUrl['path'] = $this->parsedUrl['path'] . '-wp';

		return $this;
	}

	/**
	 * Gets integration id from all available sources and sets it up for later usage
	 */
	private function setIntegrationId(): self {
		if ( ! empty( $this->errorString ) ) {
			return $this;
		}

		$integration_id = $this->reqQuery['integrationId'] ?? '';

		if ( empty( $integration_id ) ) {
			$integration_id = \getenv( 'GLOMEX_INTEGRATION_ID' );

			if ( empty( $integration_id ) ) {
				$options = \get_option( GLOMEX_OEMBED_TEXTDOMAIN . '-settings', '' );

				if ( ! empty( $options['integrationId'] ) ) {
					$integration_id = $options['integrationId'];
				}
			}
		}

		$this->integrationId = \is_string( $integration_id ) ? \esc_attr( $integration_id ) : '';

		// phpcs:ignore SlevomatCodingStandard.ControlStructures.EarlyExit
		if ( empty( $this->integrationId ) ) {
			$this->errorString = \sprintf(
				'<p><a href="%s">%s</a></p>',
				\esc_url_raw( $this->url ),
				\__( 'View Video - no integration ID provided', 'glomex-oembed' )
			);
		}

		return $this;
	}

	private function setIncludeStructuredData(): string {
		$structured_data = $this->reqQuery['includeStructuredData'] ?? '';

		if ( empty( $structured_data ) ) {
			$options = \get_option( GLOMEX_OEMBED_TEXTDOMAIN . '-settings' );

			if ( ! empty( $options['includeStructuredData'] ) ) {
				$structured_data = $options['includeStructuredData'];
			}

			// @phpstan-ignore-next-line
			$structured_data = \is_string( $structured_data ) ? \strtr( $structured_data, array( 'on' => 'true', 'off' => 'false' ) ) : 'false'; // phpcs:ignore
		}

		return $structured_data;
	}

	/**
	 * Build oembed url
	 */
	private function buildUrl(): string {
		return \sprintf(
			\esc_url_raw( 'https://embed.mes.glomex.cloud/oembed.json?includeStructuredData=%s&url=%s' ),
			$this->setIncludeStructuredData(),
			\rawurlencode(
				\sprintf(
					'%s://%s%s%s%s',
					\esc_attr( $this->parsedUrl['scheme'] ),
					\esc_attr( $this->parsedUrl['host'] ),
					! empty( $this->parsedUrl['path'] ) ? '' . \esc_attr( $this->parsedUrl['path'] ) : '',
					! empty( $this->parsedUrl['query'] ) ? '?' . \esc_attr( $this->parsedUrl['query'] ) : '',
					! empty( $this->parsedUrl['fragment'] ) ? '#' . \esc_attr( $this->parsedUrl['fragment'] ) : ''
				)
			)
		);
	}

}
