<?php
/**
 * Starter Templates Importer - Module.
 *
 * This file is used to register and manage the Zip AI Modules.
 *
 * @package Starter Templates Importer
 */

namespace STImporter\Importer;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}


/**
 * The Module Class.
 */
class ST_Importer_Helper {

	/**
	 * Instance of this class.
	 *
	 * @since 1.0.0
	 * @var self Class object.
	 */
	private static $instance = null;



	/**
	 * Initiator of this class.
	 *
	 * @since 1.0.0
	 * @return self initialized object of this class.
	 */
	public static function get_instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Get theme install, active or inactive status.
	 *
	 * @since 1.0.0
	 *
	 * @return string Theme status
	 */
	public static function get_theme_status() {

		$theme = wp_get_theme();

		// Theme installed and activate.
		if ( 'Astra' === $theme->name || 'Astra' === $theme->parent_theme ) {
			return 'installed-and-active';
		}

		// Theme installed but not activate.
		foreach ( (array) wp_get_themes() as $theme_dir => $theme ) {
			if ( 'Astra' === $theme->name || 'Astra' === $theme->parent_theme ) {
				return 'installed-but-inactive';
			}
		}

		return 'not-installed';
	}

	/**
	 * Get the API URL.
	 *
	 * @since  1.0.0
	 *
	 * @return string
	 */
	public static function get_api_domain() {
		return defined( 'STARTER_TEMPLATES_REMOTE_URL' ) ? STARTER_TEMPLATES_REMOTE_URL : apply_filters( 'astra_sites_api_domain', 'https://websitedemos.net/' );
	}

	/**
	 * Get Hash Image.
	 *
	 * @since 1.0.0
	 * @param  string $attachment_url Attachment URL.
	 * @return string                 Hash string.
	 */
	public static function get_hash_image( $attachment_url ) {
		return sha1( $attachment_url );
	}

	/**
	 * Track Imported Post
	 *
	 * @param  int                   $post_id Post ID.
	 * @param array<string, string> $data Raw data imported for the post.
	 * @return void
	 */
	public static function track_post( $post_id = 0, $data = array() ) {

		update_post_meta( $post_id, '_astra_sites_imported_post', true );
		update_post_meta( $post_id, '_astra_sites_enable_for_batch', true );

		// Set the full width template for the pages.
		if ( isset( $data['post_type'] ) && 'page' === $data['post_type'] ) {
			$is_elementor_page = get_post_meta( $post_id, '_elementor_version', true );
			$theme_status      = ST_Importer_Helper::get_theme_status();
			if ( 'installed-and-active' !== $theme_status && $is_elementor_page ) {
				update_post_meta( $post_id, '_wp_page_template', 'elementor_header_footer' );
			}
		} elseif ( isset( $data['post_type'] ) && 'attachment' === $data['post_type'] ) {
			$remote_url          = isset( $data['guid'] ) ? $data['guid'] : '';
			$attachment_hash_url = ST_Importer_Helper::get_hash_image( $remote_url );
			if ( ! empty( $attachment_hash_url ) ) {
				update_post_meta( $post_id, '_astra_sites_image_hash', $attachment_hash_url );
				update_post_meta( $post_id, '_elementor_source_image_hash', $attachment_hash_url );
			}
		}

	}

	/**
	 * Download image from URL.
	 *
	 * @param array<string, string> $image Image data.
	 * @return int|\WP_Error Image ID or WP_Error.
	 * @since {{since}}
	 */
	public static function download_image( $image ) {

		$image_url = $image['url'];

		$id = $image['id'];

		$downloaded_ids = get_option( 'ast_sites_downloaded_images', array() );
		$downloaded_ids = ( is_array( $downloaded_ids ) ) ? $downloaded_ids : array();

		if ( array_key_exists( $id, $downloaded_ids ) ) {
			return $downloaded_ids[ $id ];
		}

		// Check if image is uploaded/downloaded already. If yes the update meta and mark it as downloaded.
		$site_domain = (string) wp_parse_url( get_home_url(), PHP_URL_HOST );

		if ( strpos( $image_url, $site_domain ) !== false ) {

			$downloaded_ids[ $id ] = $id;

			// Add our meta data for uploaded image.
			if ( '1' !== get_post_meta( intval( $downloaded_ids[ $id ] ), '_astra_sites_imported_post', true ) ) {
				update_post_meta( (int) $downloaded_ids[ $id ], '_astra_sites_imported_post', true );
			}

			update_option( 'ast_sites_downloaded_images', $downloaded_ids );

			return (int) $downloaded_ids[ $id ];
		}

		// Use parse_url to get the path component of the URL.
		$path = wp_parse_url( $image_url, PHP_URL_PATH );

		if ( empty( $path ) ) {
			return new \WP_Error( 'parse_url', 'Unable to parse URL' );
		}

		// Use basename to extract the file name from the path.
		$image_name = basename( $path );

		// Fallback name.
		$image_name = $image_name ? $image_name : sanitize_title( $id );

		// Use pathinfo to get the file name without the extension.
		$image_extension = pathinfo( $image_name, PATHINFO_EXTENSION );

		// If the extension is empty, default to jpg. Set image_name with the extension.
		if ( empty( $image_extension ) ) {
			$image_extension = 'jpeg';
			$image_name      = $image_name . '.' . $image_extension;
		}

		$description = $image['description'] ?? '';

		$new_attachment_id = self::create_image_from_url( $image_url, $image_name, $id, $description );

		// Mark image downloaded.
		$downloaded_ids[ $id ] = $new_attachment_id;
		update_option( 'ast_sites_downloaded_images', $downloaded_ids );

		return $new_attachment_id;
	}

	/**
	 * Create the image and return the new media upload id.
	 *
	 * @param String $url URL to pixabay image.
	 * @param String $name Name to pixabay image.
	 * @param String $photo_id Photo ID to pixabay image.
	 * @param String $description Description to pixabay image.
	 * @see http://codex.wordpress.org/Function_Reference/wp_insert_attachment#Example
	 *
	 * @return int|\WP_Error}
	 */
	public static function create_image_from_url( $url, $name, $photo_id, $description = '' ) {
		require_once ABSPATH . 'wp-admin/includes/media.php';
		require_once ABSPATH . 'wp-admin/includes/file.php';
		require_once ABSPATH . 'wp-admin/includes/image.php';
		$file_array         = array();
		$file_array['name'] = wp_basename( $name );

		// Download file to temp location.
		$file_array['tmp_name'] = download_url( $url );

		// If error storing temporarily, return the error.
		if ( is_wp_error( $file_array['tmp_name'] ) ) {
			return 0;
		}

		// Do the validation and storage stuff.
		$id = media_handle_sideload( $file_array, 0, null );

		// If error storing permanently, unlink.
		if ( is_wp_error( $id ) ) {
			@unlink( $file_array['tmp_name'] ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_unlink -- Deleting the file from temp location.
			return $id;
		}

		$alt = ( '' === $description ) ? $name : $description;

		// Store the original attachment source in meta.
		add_post_meta( $id, '_source_url', $url );

		update_post_meta( $id, 'astra-images', $photo_id );
		update_post_meta( $id, '_wp_attachment_image_alt', $alt );
		update_post_meta( $id, '_astra_sites_imported_post', true );
		return $id;
	}

	/**
	 * Get Business details.
	 *
	 * @since 4.0.0
	 * @param string $key options name.
	 * @return array<string, mixed>|array<int, string>|string|array<string>|array<string,string>
	 */
	public static function get_business_details( $key = '' ) {
		$details = get_option(
			'zipwp_user_business_details',
			array(
				'business_name'        => '',
				'business_address'     => '',
				'business_phone'       => '',
				'business_email'       => '',
				'business_category'    => '',
				'business_description' => '',
				'templates'            => array(),
				'language'             => 'en',
				'images'               => array(),
				'image_keyword'        => array(),
				'social_profiles'      => array(),
			)
		);

		$details = array(
			'business_name'        => ( ! empty( $details['business_name'] ) ) ? $details['business_name'] : '',
			'business_address'     => ( ! empty( $details['business_address'] ) ) ? $details['business_address'] : '',
			'business_phone'       => ( ! empty( $details['business_phone'] ) ) ? $details['business_phone'] : '',
			'business_email'       => ( ! empty( $details['business_email'] ) ) ? $details['business_email'] : '',
			'business_category'    => ( ! empty( $details['business_category'] ) ) ? $details['business_category'] : '',
			'business_description' => ( ! empty( $details['business_description'] ) ) ? $details['business_description'] : '',
			'templates'            => ( ! empty( $details['templates'] ) ) ? $details['templates'] : array(),
			'language'             => ( ! empty( $details['language'] ) ) ? $details['language'] : 'en',
			'images'               => ( ! empty( $details['images'] ) ) ? $details['images'] : array(),
			'social_profiles'      => ( ! empty( $details['social_profiles'] ) ) ? $details['social_profiles'] : array(),
			'image_keyword'        => ( ! empty( $details['image_keyword'] ) ) ? $details['image_keyword'] : array(),
		);

		if ( ! empty( $key ) ) {
			return isset( $details[ $key ] ) ? $details[ $key ] : array();
		}

		return $details;
	}

	/**
	 * Preserve JSON unicode escape sequences in block content before saving.
	 *
	 * WordPress's wp_insert_post() and wp_update_post() run wp_unslash() internally,
	 * which calls stripslashes(). This corrupts \uXXXX sequences (e.g. \u0022, \u003e)
	 * used in Gutenberg block comment JSON by stripping the backslash.
	 *
	 * This method double-escapes \uXXXX to \\uXXXX so that after stripslashes()
	 * runs, the original \uXXXX is restored.
	 *
	 * @since 1.1.28
	 *
	 * @param string $content Post content containing block markup.
	 * @return string Content with \uXXXX sequences preserved for safe saving.
	 */
	public static function preserve_block_unicode_escapes( $content ) {
		if ( ! $content ) {
			return $content;
		}
		// Negative lookbehind ensures already-escaped \\uXXXX is not escaped again,
		// making this function safe to call multiple times on the same content.
		$result = preg_replace_callback(
			'/(?<!\\\\)\\\\u([0-9a-fA-F]{4})/',
			function ( $matches ) {
				return '\\\\u' . $matches[1];
			},
			$content
		);
		return is_string( $result ) ? $result : $content;
	}

	/**
	 * Replace demo-site URLs with the current site URL.
	 *
	 * Rewrites `https?://websitedemos.net/<slug>/...` occurrences inside
	 * string leaves of the supplied value to `<site_url>/...`, dropping the
	 * demo host and the template slug so the tail path lines up with the
	 * newly imported site. Image file URLs are preserved so the batch image
	 * downloader can still fetch and localize them.
	 *
	 * Intended for classic-template imports only — AI imports don't ship
	 * with `websitedemos.net` URLs, so callers gate accordingly.
	 *
	 * @since 1.1.33
	 *
	 * @param mixed $value Array or string value to scrub. Other types are
	 *                     returned unchanged.
	 * @return mixed Cleaned value with the same shape as the input.
	 */
	public static function replace_source_site_url( $value ) {
		if ( is_array( $value ) ) {
			foreach ( $value as $key => $inner ) {
				$value[ $key ] = self::replace_source_site_url( $inner );
			}
			return $value;
		}

		if ( ! is_string( $value ) || false === stripos( $value, 'websitedemos.net' ) ) {
			return $value;
		}

		$site_url = trailingslashit( get_site_url() );

		$result = preg_replace_callback(
			// Tail class excludes common prose terminators so a URL embedded in
			// a sentence (e.g. `Visit …/page/, thanks`) doesn't swallow the `,`.
			'#https?://websitedemos\.net/[^/"\'\s]+/[^"\'\s<>,;!?)\]]*#i',
			function ( $matches ) use ( $site_url ) {
				$url = $matches[0];

				// Preserve image file URLs — batch image downloader will
				// fetch and localize them on a later pass.
				if ( (bool) preg_match( '~\.(?:jpe?g|png|gif|svg|webp|avif)(?:[?#][^\s]*)?$~i', $url ) ) {
					return $url;
				}

				// Skip past `https?://` to the host.
				$scheme_end = stripos( $url, '://' );
				if ( false === $scheme_end ) {
					return $site_url;
				}
				$host_start = $scheme_end + 3;

				// First `/` after host closes the host segment.
				$host_end = strpos( $url, '/', $host_start );
				if ( false === $host_end ) {
					return $site_url;
				}

				// Next `/` after that closes the slug segment.
				$slug_end = strpos( $url, '/', $host_end + 1 );
				if ( false === $slug_end ) {
					return $site_url;
				}

				return $site_url . substr( $url, $slug_end + 1 );
			},
			$value
		);

		return is_string( $result ) ? $result : $value;
	}
}
