<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
require __DIR__ . '/../vendor/autoload.php';
use Firebase\JWT\JWT;

class W2PShopUtil {

	/**
	 * Normalize W2PShop product data.
	 * Accepts an array or a JSON string and returns a normalized array.
	 * Returns null if the value is empty or cannot be decoded to an array.
	 *
	 * @param mixed $w2pshop_product_data
	 * @return array|null
	 */
	public static function normalize_product_data( mixed $w2pshop_product_data ): ?array {
		if ( is_string( $w2pshop_product_data ) ) {
			$trim = trim( $w2pshop_product_data );
			if ( '' === $trim || '[]' === $trim ) {
				return null;
			}
			$decoded = json_decode( $w2pshop_product_data );

			if ( JSON_ERROR_NONE !== json_last_error() || ! is_array( $decoded ) ) {
				return null;
			}

			return $decoded;
		}
		return is_array( $w2pshop_product_data ) ? $w2pshop_product_data : null;

	}
	/**
	 * Sanitize variable
	 *
	 * @param $var mixed
	 *
	 * @return mixed
	 */
	public static function sanitize_variable( mixed $var ) : mixed {
		if ( empty( $var ) ) {
			return '';
		}
		if ( is_array( $var ) ) {
			foreach ( $var as $key => $value ) {
				$var[ $key ] = self::sanitize_variable( $value );
			}
		} else {
			$var = sanitize_text_field( $var );
		}
		return $var;
	}
	/**
	 * Get web response from URL and optional post data
	 *
	 * @param $url      string Request URL
	 * @param array|string $post_data array|string (optional) Post Data
	 * @param $headers  array (optional) HTTP Headers
	 * @param array $additional_args
	 *
	 * @return string
	 */
	public static function get_web_response(
		string $url,
		string|array $post_data = '',
		array $headers = array(),
		array $additional_args = array()
	): string {
		if ( ! str_starts_with( $url, 'http' ) ) {
			return '';
		}

		$timeout = ini_get( 'max_execution_time' );
		$args    = array(
			'body'      => $post_data,
			'timeout'   => $timeout,
			'headers'   => $headers,
			'sslverify' => true,
		);

		// Merge with defaults
		$args = array_merge( $args, $additional_args );

		if ( '' !== $post_data ) {
			$request = wp_remote_post( $url, $args );
		} else {
			$request = wp_remote_get( $url, $args );
		}

		return wp_remote_retrieve_body( $request );
	}
	/**
	 * Downloads a file from URL and saves it to the specified path.
	 *
	 * @param $url  string URL to download
	 * @param $path string Path to save the file
	 *
	 * @return bool True on success
	 */
	public static function download_file( string $url, string $path ): bool {
		//Remove any spaces that may be present
		$url     = preg_replace( '/\s/', '%20', $url );
		$timeout = ini_get( 'max_execution_time' );
		$args    = array(
			'filename' => $path,
			'stream'   => true,
			'timeout'  => $timeout,
		);

		$response = wp_remote_get( $url, $args );

		return is_array( $response ) && ! is_wp_error( $response );
	}
	/**
	 * Create attachment image from URL and return attachment ID.
	 * Optionally, if the post ID is specified, the image will be saved to that post
	 *
	 * @param $preview_url string URL to download
	 *
	 * @return WP_Error|int Attachment ID or WP_Error
	 */
	public static function create_attachment_image( string $preview_url, int $post_id = 0 ) : WP_Error|int {
		if ( empty( $preview_url ) ) {
			return new WP_Error( 'empty_preview_url' );
		}

		// Get the path to the upload directory.
		$wp_upload_dir = wp_upload_dir();

		// Update the preview URL to add http protocol if not in the original URL.
		if ( ! W2PShopUtil::starts_with( $preview_url, 'http' ) ) {

			$server_port = W2PShopUtil::getServerPort();
            if (isset($_SERVER['REQUEST_SCHEME']) && isset($_SERVER['SERVER_NAME'])) {
                $preview_url = sanitize_text_field(wp_unslash($_SERVER['REQUEST_SCHEME'])) . '://' .
                    sanitize_text_field(wp_unslash($_SERVER['SERVER_NAME'])) . $server_port . $preview_url;
            }
		}

		// Return previous attachment if exists.
		$basename_preview_url = basename( $preview_url );
		if ( empty( pathinfo( $basename_preview_url )['extension'] ) ) {
			$basename_preview_url .= '.png';
		}

		$_previous_attach_id = W2PShopUtil::get_attachment_from_name( 'w2pshop_preview_' . $basename_preview_url );
		if ( $_previous_attach_id > 0 ) {
			if ( $post_id > 0 ) {
				set_post_thumbnail( $post_id, $_previous_attach_id );
			}
			return $_previous_attach_id;
		}

		// Specify physical path to file.
		$filename = $wp_upload_dir['path'] . '/w2pshop_preview_' . $basename_preview_url;

		// Download image based on http url.
		W2PShopUtil::download_file( $preview_url, $filename );

		// Check the type of tile. We'll use this as the 'post_mime_type'.
		$filetype = wp_check_filetype( basename( $filename ), null );

		// Prepare an array of post data for the attachment.
		$attachment = array(
			'guid'           => $wp_upload_dir['url'] . '/' . basename( $filename ),
			'post_mime_type' => $filetype['type'],
			'post_title'     => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
			'post_content'   => '',
			'post_status'    => 'inherit',
		);

		// Insert the attachment.
		$attach_id = wp_insert_attachment( $attachment, $filename, $post_id );

		// Make sure that this file is included, as wp_generate_attachment_metadata() depends on it.
		include_once ABSPATH . 'wp-admin/includes/image.php';

		// Generate the metadata for the attachment, and update the database record.
		$attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
		wp_update_attachment_metadata( $attach_id, $attach_data );

		return $attach_id;
	}
	/**
	 * Get attachment ID from name of attachment
	 *
	 * @param $name string Name of attachment
	 *
	 * @return int Attachment ID or 0 if not found
	 */
	public static function get_attachment_from_name( string $name ): int {
		$args        = array(
			'post_type'   => 'attachment',
			'numberposts' => -1,
			'post_status' => null,
			'post_parent' => null, // any parent
		);
		$attachments = get_posts( $args );
		if ( $attachments ) {
			foreach ( $attachments as $post ) {
				if ( strtolower( $name ) === $post->post_name . '.jpg' ) {
					return $post->ID;
				}
				if ( strtolower( $name ) === $post->post_name . '.png' ) {
					return $post->ID;
				}
			}
		}
		return 0;
	}
	/**
	 * Check if string starts with $needle in $haystack or not
	 *
	 * @param $haystack string
	 * @param $needle   string
	 *
	 * @return bool True if string starts with $needle
	 */
	public static function starts_with( string $haystack, string $needle ): bool {
		return '' === $needle || strncmp( $haystack, $needle, strlen( $needle ) ) === 0;
	}

	/**
	 * Generate Authentication Token
	 * Creates a JWT token based on supplied information.
	 *
	 * @param  $api_key      string pricematrix Api Key
	 * @param  $api_secret   string pricematrix Api Secret Key
	 * @param  $user_session string Any unique value ( ie: user session )
	 * @param  $is_admin     bool If admin, the designer will load in with admin privileges
	 * @return string
	 */
	public function generate_auth_token( string $api_key, string $api_secret, string $user_session, bool $is_admin = false ): string {
		$user_session = ( $is_admin ) ? 'admin_' . $user_session : $user_session;
		$payload      = array(
			'iss' => $api_key,
			'sub' => $user_session, // This is any session value to identify your user.
			'axs' => ( $is_admin ) ? 'admin' : 'user', // Access. Can be either "user" or "admin".
			'iat' => time(),
			'exp' => time() + 28800, // 8 Hour expiration.
		);
		return JWT::encode( $payload, $api_secret, 'HS256' );
	}
	public function get_session_id(): string {
		// Check if session is active or disabled.
		// If disabled, return a unique session id.
		if ( PHP_SESSION_DISABLED === session_status() ) {
			return uniqid( 'w2pshop' );
		}

		// Check if user is logged in - return a more persistent session id
		if ( is_user_logged_in() ) {
			$current_user = wp_get_current_user();
			return md5( $current_user->ID . '_' . $current_user->user_nicename . '_' . $current_user->user_email );
		}

		// If user is not logged in, we will just return a unique session id which will eventually expire
		$session_id = session_id();
		return ( empty( $session_id ) ) ? uniqid( 'w2pshop' ) : $session_id;
	}
	/**
	 * Remove special characters from string
	 *
	 * @retun string
	 */
	public static function remove_special_characters( string $string ): string {
		return str_replace( array( '\'', '"', ',', ';', '<', '>', '\\' ), ' ', $string );
	}
	/**
	 * Checks if a given string is a valid base64 string.
	 *
	 * @param string $string The string to be checked.
	 * @return bool Returns true if the string is a valid base64 string, false otherwise.
	 */
	public static function is_base64( string $string ): bool {
		return (bool) preg_match( '/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $string );
	}
	/**
	 * Generates a unique ID using the md5 hash of a combination of the current time and a random number.
	 *
	 * @return string The generated unique ID.
	 */
	public static function generate_unique_id(): string {
		return md5( uniqid( wp_rand() , true ) );
	}
	/* Returns an associative array of Plugin Names -> Active or Inactive Status
	 *
	 */
	public static function getActivePlugins(): array {
		include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
		$all_plugins = get_plugins();
		$plugin_status = [];
		foreach ($all_plugins as $plugin_path => $plugin_data) {
			$name = $plugin_data['Name'];
			$is_active = is_plugin_active($plugin_path);
			$plugin_status[$name] = $is_active ? 'Active' : 'Inactive';
		}
		return $plugin_status;
	}

	private static function getServerPort(): string {
		if ( isset( $_SERVER['SERVER_PORT'] ) ) {
			if ( 80 !== intval( $_SERVER['SERVER_PORT'] ) || intval( 443 !== $_SERVER['SERVER_PORT'] ) ) {
				return ':' . sanitize_text_field(wp_unslash($_SERVER['SERVER_PORT']));
			}
		}
		return "";
	}
	public static function normalize_rest_country_code( $response ): array {
		$order_data = $response->data;

		$order_data['shipping']['country'] =
			self::normalize_country_code( $order_data['shipping']['country'] ?? null );

		$order_data['billing']['country'] =
			self::normalize_country_code( $order_data['billing']['country'] ?? null );

		return $order_data;
	}

	private static function normalize_country_code( ?string $country ): ?string {
		return $country === 'US' ? 'USA' : $country;
	}
}
