<?php

/**
 * Helper functions for third-party services such as YouTube, Vimeo, Dailymotion, Facebook, etc.
 *
 * @link    https://plugins360.com
 * @since   3.8.4
 *
 * @package All_In_One_Video_Gallery
 */

// Exit if accessed directly
if ( ! defined( 'WPINC' ) ) {
	die;
}

/**
 * Create a HH:MM:SS from a timestamp.
 * Given a number of seconds, the function returns a readable duration formatted as HH:MM:SS
 *
 * @since  3.8.4
 * @param  int    $seconds Number of seconds.
 * @return string          The formatted time.
 */
function aiovg_convert_seconds_to_human_time( $seconds ) {
	$seconds = absint( $seconds );
	
	if ( $seconds <= 0 ) {
		return '';
	}

	$h = floor( $seconds / 3600 );
	$m = floor( $seconds % 3600 / 60 );
	$s = floor( $seconds %3600 % 60 );

	return ( ( $h > 0 ? $h . ":" : "" ) . ( ( $m < 10 ? "0" : "" ) . $m . ":" ) . ( $s < 10 ? "0" : "" ) . $s );
}

/**
 * Extract iframe src from the given HTML string.
 *
 * @since  1.0.0
 * @param  string $html HTML string.
 * @return string $src  Iframe URL.
 */
function aiovg_extract_iframe_src( $html ) {
	$src = '';

	if ( ! empty( $html ) && strpos( $html, '<iframe' ) !== false ) {
		preg_match( '/src="([^"]+)"/', $html, $matches );
		if ( $matches ) {
			$src = $matches[1];
		}
	}

	return $src;
}

/**
 * Get the embed URL for a Bunny Stream video.
 *
 * @since  4.2.0 
 * @param  string       $url      The original Bunny Stream HLS video URL.
 * @param  int          $video_id Bunny Stream Video ID.
 * @return string|false           The signed Bunny Stream embed URL or false if not applicable.
 */
function aiovg_get_bunny_stream_embed_url( $url, $video_id ) {
	$settings = aiovg_get_option( 'aiovg_bunny_stream_settings' );

	if ( empty( $settings['library_id'] ) ) {
		return false;
	}

	// Sanitize video ID and retrieve library ID from settings
	$video_id   = sanitize_text_field( $video_id );
	$library_id = intval( $settings['library_id'] );

	// Construct the base embed URL
	$embed_url = sprintf(
		'https://iframe.mediadelivery.net/embed/%d/%s',
		$library_id,
		$video_id
	);

	// If token authentication is enabled, generate a signed token
	if ( ! empty( $settings['enable_token_authentication'] ) &&	! empty( $settings['token_authentication_key'] ) ) {
		// Generate the token using SHA256 hash of key + video_id + expiry
		$security_key    = sanitize_text_field( $settings['token_authentication_key'] );
		$expiration_time = ! empty( $settings['token_expiry'] ) ? absint( $settings['token_expiry'] ) : 3600;
		$expires         = time() + $expiration_time;
		$token           = hash( 'sha256', $security_key . $video_id . $expires );

		// Append token and expiry to the embed URL
		$embed_url = add_query_arg( 'token', $token, $embed_url );
		$embed_url = add_query_arg( 'expires', $expires, $embed_url );
	}

	// Allow developers to modify the embed URL via filter
	return apply_filters( 'aiovg_bunny_stream_embed_url', $embed_url, $url, $video_id );
}

/**
 * Get the signed file URL for a Bunny Stream video.
 *
 * @since  4.2.0
 * @param  string $url      The original Bunny Stream video / image URL.
 * @param  int    $video_id Bunny Stream video ID.
 * @return string           Signed Bunny Stream URL with token and restrictions appended.
 */
function aiovg_get_bunny_stream_signed_url( $url, $video_id ) {
	$settings = aiovg_get_option( 'aiovg_bunny_stream_settings' );

	if ( empty( $settings['enable_token_authentication'] ) || empty( $settings['token_authentication_key'] ) ) {
		return $url;
	}

	// Get the security key and expiry settings
	$security_key       = sanitize_text_field( $settings['token_authentication_key'] );
	$expiration_time    = ! empty( $settings['token_expiry'] ) ? absint( $settings['token_expiry'] ) : 3600;
	$expires            = time() + $expiration_time;
	$is_directory_token = true; // Indicates we're signing by directory path, not full file path
	$path_allowed       = '/' . sanitize_text_field( $video_id ) . '/';

	// Optional restrictions (not used currently, but placeholder for future config)
	$user_ip            = '';
	$countries_allowed  = '';
	$countries_blocked  = '';
	$referers_allowed   = '';

	// Append optional query parameters for geo and referrer restrictions
	if ( ! empty( $countries_allowed ) ) {
		$url = add_query_arg( 'token_countries', $countries_allowed, $url );
	}

	if ( ! empty( $countries_blocked ) ) {
		$url = add_query_arg( 'token_countries_blocked', $countries_blocked, $url );
	}

	if ( ! empty( $referers_allowed ) ) {
		$url = add_query_arg( 'token_referer', $referers_allowed, $url );		
	}

	// Parse the URL components
	$parsed = parse_url( $url );
	if ( ! is_array( $parsed ) ) {
		return $url;
	}

	$url_scheme = isset( $parsed['scheme'] ) ? $parsed['scheme'] : 'https';
	$url_host   = isset( $parsed['host'] ) ? $parsed['host'] : '';
	$url_path   = isset( $parsed['path'] ) ? $parsed['path'] : '';
	$url_query  = isset( $parsed['query'] ) ? $parsed['query'] : '';

	// Collect all query parameters for the signature
	$parameters = array();
	if ( ! empty( $url_query ) ) {
		parse_str( $url_query, $parameters );
	}

	// Adjust the token path if directory-based tokenization is used
	$signature_path = $url_path;
	if ( ! empty( $path_allowed ) ) {
		$signature_path = $path_allowed;
		$parameters['token_path'] = $signature_path;
	}

	// Sort parameters alphabetically for consistent hashing
	ksort( $parameters );

	// Build parameter strings for hashing and for final URL
	$parameter_data     = '';
	$parameter_data_url = '';

	foreach ( $parameters as $key => $value ) {
		if ( $parameter_data !== '' ) {
			$parameter_data .= '&';
		}
		$parameter_data_url .= '&';

		$parameter_data     .= $key . '=' . $value;
		$parameter_data_url .= $key . '=' . urlencode( $value );
	}

	// Create the base string for token generation
	$hashable_base = $security_key . $signature_path . $expires;
	
	if ( ! empty( $user_ip ) ) {
		$hashable_base .= $user_ip;
	}
	
	$hashable_base .= $parameter_data;

	// Generate the token using SHA-256 and encode it
	$token = hash( 'sha256', $hashable_base, true );
	$token = base64_encode( $token );
	$token = strtr( $token, '+/', '-_' );
	$token = str_replace( '=', '', $token );

	// Build the final signed URL based on token type
	if ( $is_directory_token ) {
		$signed_url = "{$url_scheme}://{$url_host}/bcdn_token={$token}&expires={$expires}{$parameter_data_url}{$url_path}";
	} else {
		$signed_url = "{$url_scheme}://{$url_host}{$url_path}?token={$token}{$parameter_data_url}&expires={$expires}";
	}

	// Allow customization via filter and return final signed URL
	return apply_filters( 'aiovg_bunny_stream_signed_url', $signed_url, $url, $video_id );
}

/**
 * Get Dailymotion ID from URL.
 *
 * @since  1.5.0
 * @param  string $url Dailymotion video URL.
 * @return string $id  Dailymotion video ID.
 */
function aiovg_get_dailymotion_id_from_url( $url ) {	
	$id = '';
	
	if ( preg_match( '!^.+dailymotion\.com/(video|hub)/([^_]+)[^#]*(#video=([^_&]+))?|(dai\.ly/([^_]+))!', $url, $m ) ) {
        if ( isset( $m[6] ) ) {
            $id = $m[6];
        }
		
        if ( isset( $m[4] ) ) {
            $id = $m[4];
        }
		
        $id = $m[2];
    }

	return $id;	
}

/**
 * Get Dailymotion image from URL.
 *
 * @since  1.5.0
 * @param  string $url           Dailymotion video URL.
 * @param  bool   $force_refresh Skip the cache and fetch fresh data. Default false.
 * @return string                Dailymotion image URL.
 */
function aiovg_get_dailymotion_image_url( $url, $force_refresh = false ) {
	$data = aiovg_get_dailymotion_oembed_data( $url, $force_refresh );
	return $data['thumbnail_url'];
}

/**
 * Get Dailymotion data using oEmbed.
 *
 * @since  3.8.4
 * @param  string $url           Dailymotion URL.
 * @param  bool   $force_refresh Skip the cache and fetch fresh data. Default false.
 * @return string $response      Dailymotion oEmbed response data.
 */
function aiovg_get_dailymotion_oembed_data( $url, $force_refresh = false ) {
	$response = array(
		'thumbnail_url' => '',
		'duration'      => ''
	);

	$cache_key = 'aiovg_' . md5( $url );

	if ( ! $force_refresh ) {
		$cache_value = get_transient( $cache_key );

		if ( is_array( $cache_value ) ) {
			$response = array_merge( $response, $cache_value );
			return $response;
		}
	}

	$id = aiovg_get_dailymotion_id_from_url( $url );

	if ( ! empty( $id ) ) {
		$api_response = wp_remote_get( 'https://api.dailymotion.com/video/' . $id . '?fields=thumbnail_large_url,thumbnail_medium_url,duration', array( 'sslverify' => false ) );

		if ( ! is_wp_error( $api_response ) ) {
			$api_response = json_decode( $api_response['body'] );

			if ( isset( $api_response->thumbnail_large_url ) ) {
				$response['thumbnail_url'] = $api_response->thumbnail_large_url;
			} else {
				$response['thumbnail_url'] = $api_response->thumbnail_medium_url;
			}

			if ( isset( $api_response->duration ) ) {
				$response['duration'] = $api_response->duration;
			}
		} else {
			// error_log( $api_response->get_error_message() );
		}
	}

	if ( ! empty( $response['thumbnail_url'] ) ) {
		set_transient( $cache_key, $response, DAY_IN_SECONDS );
	}
	
	return $response;
}

/**
 * Get Dailymotion video duration from URL.
 *
 * @since  3.8.4
 * @param  string $url Dailymotion video URL.
 * @return string      Video duration.
 */
function aiovg_get_dailymotion_video_duration( $url ) {	
	$data = aiovg_get_dailymotion_oembed_data( $url );		
	return $data['duration'];
}

/**
 * Get video duration from the Third-Party Player Code.
 *
 * @since  3.8.4
 * @param  string $embedcode Player Code.
 * @return string $duration  Video duration.
 */
function aiovg_get_embedcode_video_duration( $embedcode ) {
	$duration = '';

	$iframe_src = aiovg_extract_iframe_src( $embedcode );
	if ( $iframe_src ) {
		// Vimeo
		if ( false !== strpos( $iframe_src, 'vimeo.com' ) ) {
			$duration = aiovg_get_vimeo_video_duration( $iframe_src );
		}

		// Dailymotion
		elseif ( false !== strpos( $iframe_src, 'dailymotion.com' ) ) {
			$duration = aiovg_get_dailymotion_video_duration( $iframe_src );
		}

		// Rumble
		elseif ( false !== strpos( $iframe_src, 'rumble.com' ) ) {
			$duration = aiovg_get_rumble_video_duration( $iframe_src );
		}
	}
    	
	// Return
	return $duration;	
}

/**
 * Get image from the Third-Party Player Code.
 *
 * @since  1.0.0
 * @param  string $embedcode     Player Code.
 * @param  bool   $force_refresh Skip the cache and fetch fresh data. Default false.
 * @return string $url           Image URL.
 */
function aiovg_get_embedcode_image_url( $embedcode, $force_refresh = false ) {
	$url = '';

	$iframe_src = aiovg_extract_iframe_src( $embedcode );
	if ( $iframe_src ) {
		// YouTube
		if ( false !== strpos( $iframe_src, 'youtube.com' ) || false !== strpos( $iframe_src, 'youtu.be' ) ) {
			$url = aiovg_get_youtube_image_url( $iframe_src );
		}

		// Vimeo
		elseif ( false !== strpos( $iframe_src, 'vimeo.com' ) ) {
			$url = aiovg_get_vimeo_image_url( $iframe_src, $force_refresh );
		}

		// Dailymotion
		elseif ( false !== strpos( $iframe_src, 'dailymotion.com' ) ) {
			$url = aiovg_get_dailymotion_image_url( $iframe_src, $force_refresh );
		}

		// Rumble
		elseif ( false !== strpos( $iframe_src, 'rumble.com' ) ) {
			$url = aiovg_get_rumble_image_url( $iframe_src, $force_refresh );
		}
	}

	// Return image url
	return $url;
}

/**
 * Get Rumble image from URL.
 *
 * @since  3.8.4
 * @param  string $url           Rumble video URL.
 * @param  bool   $force_refresh Skip the cache and fetch fresh data. Default false.
 * @return string                Rumble image URL.
 */
function aiovg_get_rumble_image_url( $url, $force_refresh = false ) {
	$data = aiovg_get_rumble_oembed_data( $url, $force_refresh );
	return $data['thumbnail_url'];
}

/**
 * Get Rumble data using oEmbed.
 *
 * @since  2.6.3
 * @param  string $url           Rumble URL.
 * @param  bool   $force_refresh Skip the cache and fetch fresh data. Default false.
 * @return string $response      Rumble oEmbed response data.
 */
function aiovg_get_rumble_oembed_data( $url, $force_refresh = false ) {
	$response = array(
		'thumbnail_url' => '',
		'duration'      => '',
		'html'          => ''
	);

	$cache_key = 'aiovg_' . md5( $url );

	if ( ! $force_refresh ) {
		$cache_value = get_transient( $cache_key );

		if ( is_array( $cache_value ) ) {
			$response = array_merge( $response, $cache_value );
			return $response;
		}
	}

	$api_response = wp_remote_get( 'https://rumble.com/api/Media/oembed.json?url=' . urlencode( $url ) );

	if ( is_array( $api_response ) && ! is_wp_error( $api_response ) ) {
		$api_response = json_decode( $api_response['body'] );

		if ( isset( $api_response->thumbnail_url ) ) {
			$response['thumbnail_url'] = $api_response->thumbnail_url;
		}

		if ( isset( $api_response->duration ) ) {
			$response['duration'] = $api_response->duration;
		}

		if ( isset( $api_response->html ) ) {
			$response['html'] = $api_response->html;
		}
	}

	if ( ! empty( $response['thumbnail_url'] ) ) {
		set_transient( $cache_key, $response, DAY_IN_SECONDS );
	}
	
	return $response;
}

/**
 * Get Rumble video duration from URL.
 *
 * @since  3.8.4
 * @param  string $url Rumble video URL.
 * @return string      Video duration.
 */
function aiovg_get_rumble_video_duration( $url ) {	
	$data = aiovg_get_rumble_oembed_data( $url );		
	return $data['duration'];
}

/**
 * Get Vimeo ID from URL.
 *
 * @since  3.5.0
 * @param  string $url Vimeo video URL.
 * @return string $id  Vimeo video ID.
 */
function aiovg_get_vimeo_id_from_url( $url ) {
	$id = '';

	// Use regexp to programmatically parse the ID. So, we can avoid an oEmbed API request
	if ( strpos( $url, 'player.vimeo.com' ) !== false ) {
		if ( preg_match( '#(?:https?://)?(?:www.)?(?:player.)?vimeo.com/(?:[a-z]*/)*([0-9]{6,11})[?]?.*#', $url, $matches ) ) {
			$id = $matches[1];
		}
	}

	// Let us ask the Vimeo itself using their oEmbed API
	if ( empty( $id ) ) {
		$oembed = aiovg_get_vimeo_oembed_data( $url );
		$id = $oembed['video_id'];
	}

	return $id;
}

/**
 * Get Vimeo image from URL.
 *
 * @since  3.5.0
 * @param  string $url           Vimeo video URL.
 * @param  bool   $force_refresh Skip the cache and fetch fresh data. Default false.
 * @return string                Vimeo image URL.
 */
function aiovg_get_vimeo_image_url( $url, $force_refresh = false ) {
	$data = aiovg_get_vimeo_oembed_data( $url, $force_refresh );

	if ( empty( $data['video_id'] ) ) {
		return $data['thumbnail_url'];
	}

	$cache_key = 'aiovg_vimeo_image_' . $data['video_id'];

	if ( ! $force_refresh ) {
		$cached_image = get_transient( $cache_key );
		if ( false !== $cached_image ) {
			return add_query_arg( 'isnew', 1, $cached_image );
		}
	}

	// Find large thumbnail using the Vimeo API v2
	$api_response = wp_remote_get( 'https://vimeo.com/api/v2/video/' . $data['video_id'] . '.php' );

	if ( ! is_wp_error( $api_response ) ) {
		$api_response = maybe_unserialize( $api_response['body'] );

		if ( is_array( $api_response ) && isset( $api_response[0]['thumbnail_large'] ) ) {
			$data['thumbnail_url'] = $api_response[0]['thumbnail_large'];
		}
	}

	// Get images from private videos
	if ( empty( $data['thumbnail_url'] ) ) {
		$api_settings = aiovg_get_option( 'aiovg_api_settings' );

		if ( isset( $api_settings['vimeo_access_token'] ) && ! empty( $api_settings['vimeo_access_token'] ) ) {
			$args = array(
				'headers' => array(
					'Authorization' => 'Bearer ' . sanitize_text_field( $api_settings['vimeo_access_token'] )
				)
			);

			$api_response = wp_remote_get( 'https://api.vimeo.com/videos/' . $data['video_id'] . '/pictures', $args );

			if ( is_array( $api_response ) && ! is_wp_error( $api_response ) ) {
				$api_response = json_decode( $api_response['body'] );

				if ( isset( $api_response->data ) ) {
					$bypass = false;

					foreach ( $api_response->data as $item ) {
						foreach ( $item->sizes as $picture ) {
							$data['thumbnail_url'] = $picture->link;

							if ( $picture->width >= 400 ) {
								$bypass = true;
								break;
							}
						}

						if ( $bypass ) break;
					}
				}
			}
		}
	}

	if ( ! empty( $data['thumbnail_url'] ) ) {
		set_transient( $cache_key, $data['thumbnail_url'], DAY_IN_SECONDS );
		$data['thumbnail_url'] = add_query_arg( 'isnew', 1, $data['thumbnail_url'] );
	}

	return $data['thumbnail_url'];
}

/**
 * Get Vimeo data using oEmbed.
 *
 * @since  1.6.6
 * @param  string $url           Vimeo URL.
 * @param  bool   $force_refresh Skip the cache and fetch fresh data. Default false.
 * @return string $response      Vimeo oEmbed response data.
 */
function aiovg_get_vimeo_oembed_data( $url, $force_refresh = false ) {
	$response = array(
		'video_id'      => '',
		'thumbnail_url' => '',
		'duration'      => '',
		'html'          => ''
	);

	$cache_key = 'aiovg_' . md5( $url );

	if ( ! $force_refresh ) {
		$cache_value = get_transient( $cache_key );

		if ( is_array( $cache_value ) ) {
			$response = array_merge( $response, $cache_value );
			return $response;
		}
	}

	$api_response = wp_remote_get( 'https://vimeo.com/api/oembed.json?url=' . urlencode( $url ) );

	if ( is_array( $api_response ) && ! is_wp_error( $api_response ) ) {
		$api_response = json_decode( $api_response['body'] );

		if ( isset( $api_response->video_id ) ) {
			$response['video_id'] = $api_response->video_id;
		}

		if ( isset( $api_response->thumbnail_url ) ) {
			$response['thumbnail_url'] = $api_response->thumbnail_url;
		}

		if ( isset( $api_response->duration ) ) {
			$response['duration'] = $api_response->duration;
		}

		if ( isset( $api_response->html ) ) {
			$response['html'] = $api_response->html;
		}
	}

	// Fallback to our old method to get the Vimeo ID
	if ( empty( $response['video_id'] ) ) {
		$is_vimeo = preg_match( '/vimeo\.com/i', $url );
		if ( $is_vimeo ) {
			$response['video_id'] = preg_replace( '/[^\/]+[^0-9]|(\/)/', '', rtrim( $url, '/' ) );
		}
	}

	if ( ! empty( $response['video_id'] ) ) {
		set_transient( $cache_key, $response, DAY_IN_SECONDS );
	}
	
	return $response;
}

/**
 * Get Vimeo video duration from URL.
 *
 * @since  3.8.4
 * @param  string $url Vimeo video URL.
 * @return string      Video duration.
 */
function aiovg_get_vimeo_video_duration( $url ) {	
	$data = aiovg_get_vimeo_oembed_data( $url );		
	return $data['duration'];
}

/**
 * Get YouTube ID from URL.
 *
 * @since  1.0.0
 * @param  string $url YouTube video URL.
 * @return string $id  YouTube video ID.
 */
function aiovg_get_youtube_id_from_url( $url ) {	
	$id  = '';
    $url = parse_url( $url );
		
    if ( 0 === strcasecmp( $url['host'], 'youtu.be' ) ) {
       	$id = substr( $url['path'], 1 );
    } elseif ( 0 === strcasecmp( $url['host'], 'www.youtube.com' ) || 0 === strcasecmp( $url['host'], 'youtube.com' ) ) {
       	if ( isset( $url['query'] ) ) {
       		parse_str( $url['query'], $url['query'] );
           	if ( isset( $url['query']['v'] ) ) {
           		$id = $url['query']['v'];
           	}
       	}
			
       	if ( empty( $id ) ) {
           	$url['path'] = explode( '/', substr( $url['path'], 1 ) );
           	if ( in_array( $url['path'][0], array( 'e', 'embed', 'v', 'shorts', 'live' ) ) ) {
               	$id = $url['path'][1];
           	}
       	}
    }
    	
	return $id;	
}

/**
 * Get YouTube image from URL.
 *
 * @since  1.0.0
 * @param  string $url YouTube video URL.
 * @return string $url YouTube image URL.
 */
function aiovg_get_youtube_image_url( $url ) {	
	$id  = aiovg_get_youtube_id_from_url( $url );
	$url = '';

	if ( ! empty( $id ) ) {
		$url = "https://img.youtube.com/vi/$id/maxresdefault.jpg";
		$response = wp_remote_get( $url );

		if ( 200 != wp_remote_retrieve_response_code( $response ) ) {
			$url = "https://img.youtube.com/vi/$id/mqdefault.jpg"; 
		}
	}
	   	
	return $url;	
}

/**
 * Check if Bunny Stream hosting is enabled and return settings.
 *
 * @since  4.2.0
 * @return array|false Returns the Bunny Stream settings array if all conditions are met; otherwise, false.
 */
function aiovg_has_bunny_stream_enabled() {
	$settings = aiovg_get_option( 'aiovg_bunny_stream_settings' );

	// Basic Bunny Stream setup check
	if (
		empty( $settings['enable_bunny_stream'] ) ||
		empty( $settings['api_key'] ) ||
		empty( $settings['library_id'] ) ||
		empty( $settings['cdn_hostname'] )
	) {
		return false;
	}

	return $settings;
}

/**
 * Resolve YouTube URLs.
 *
 * @since  2.5.6
 * @param  string $url YouTube URL.
 * @return string $url Resolved YouTube URL.
 */
function aiovg_resolve_youtube_url( $url ) {
	if ( false !== strpos( $url, '/shorts/' ) || false !== strpos( $url, '/live/' ) ) {
		$id = aiovg_get_youtube_id_from_url( $url );

		if ( ! empty( $id ) ) {
			$url = 'https://www.youtube.com/watch?v=' . $id;
		}
	}

	return $url;
}
