<?php

/**
 * Admin UI + AJAX to import bundled Elementor templates from JSON (manifest-driven).
 *
 * @package storzen
 */

if (! defined('ABSPATH')) {
	exit;
}

/**
 * Class Storzen_Elementor_Template_Import
 */
class Storzen_Elementor_Template_Import
{

	const MENU_SLUG = 'storzen-import-templates';

	const AJAX_ACTION = 'storzen_import_elementor_template';

	/** @var string */
	protected static $base_dir = '';

	/**
	 * Bootstrap hooks.
	 */
	public static function init()
	{
		self::$base_dir = trailingslashit(STORZEN_ROOT_PATH . 'data/elementor-templates');

		add_action('admin_menu', array(__CLASS__, 'register_menu'), 100);
		add_action('admin_enqueue_scripts', array(__CLASS__, 'enqueue_assets'));
		add_action('wp_ajax_' . self::AJAX_ACTION, array(__CLASS__, 'ajax_import'));
	}

	/**
	 * Submenu under Shop Addon (storzen).
	 */
	public static function register_menu()
	{
		add_submenu_page(
			'storzen',
			__('Import Templates', 'storzen'),
			__('Import Templates', 'storzen'),
			'manage_options',
			self::MENU_SLUG,
			array(__CLASS__, 'render_page')
		);
	}

	/**
	 * Assets for import screen only.
	 *
	 * @param string $hook_suffix Current admin page hook.
	 */
	public static function enqueue_assets($hook_suffix)
	{
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only screen id.
		$on_page = isset($_GET['page']) && sanitize_key(wp_unslash($_GET['page'])) === self::MENU_SLUG;
		if (! $on_page && false === strpos((string) $hook_suffix, self::MENU_SLUG)) {
			return;
		}

		wp_enqueue_style(
			'storzen-import-templates',
			STORZEN_ROOT_URL . 'assets/css/admin-import-templates.css',
			array(),
			STORZEN_VERSION
		);

		wp_enqueue_script(
			'storzen-import-templates',
			STORZEN_ROOT_URL . 'assets/js/admin-import-templates.js',
			array('jquery'),
			STORZEN_VERSION,
			true
		);

		wp_localize_script(
			'storzen-import-templates',
			'WcommeroProImport',
			array(
				'ajaxUrl'        => admin_url('admin-ajax.php'),
				'nonce'          => wp_create_nonce('storzen_import_tpl'),
				'action'         => self::AJAX_ACTION,
				'placeholderUrl' => self::get_default_preview_url(),
				'i18n'           => array(
					'importing' => __('Importing…', 'storzen'),
					'done'      => __('Imported successfully.', 'storzen'),
					'error'     => __('Import failed.', 'storzen'),
					'edit'      => __('Edit in Elementor', 'storzen'),
					'enabledHeading' => __('Auto-enabled widgets:', 'storzen'),
				),
			)
		);
	}

	/**
	 * Load and decode manifest.json.
	 *
	 * @return array{version?:string,templates:array<int,array<string,mixed>>}
	 */
	public static function get_manifest()
	{
		$path = self::$base_dir . 'manifest.json';
		if (! is_readable($path)) {
			return array('version' => '0', 'templates' => array());
		}

		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Local manifest only.
		$raw = file_get_contents($path);
		$data = json_decode($raw, true);
		if (! is_array($data) || ! isset($data['templates']) || ! is_array($data['templates'])) {
			return array('version' => '0', 'templates' => array());
		}

		return $data;
	}

	/**
	 * Resolve JSON file path and ensure it stays inside base directory.
	 *
	 * @param string $relative Relative path from manifest "file" key.
	 * @return string|false Absolute path or false.
	 */
	protected static function resolve_template_path($relative)
	{
		$relative = str_replace(array("\0", '../', '..\\'), '', $relative);
		$relative = ltrim($relative, '/');
		$full     = self::$base_dir . $relative;
		$real_base = realpath(self::$base_dir);
		$real_file = realpath($full);

		if (! $real_base || ! $real_file || strpos($real_file, $real_base) !== 0) {
			return false;
		}

		if (pathinfo($real_file, PATHINFO_EXTENSION) !== 'json') {
			return false;
		}

		return $real_file;
	}

	/**
	 * Find one template entry by id from manifest.
	 *
	 * @param string $id Template id.
	 * @return array<string,mixed>|null
	 */
	protected static function find_template($id)
	{
		$manifest = self::get_manifest();
		foreach ($manifest['templates'] as $tpl) {
			if (isset($tpl['id']) && (string) $tpl['id'] === $id) {
				return $tpl;
			}
		}
		return null;
	}

	/**
	 * AJAX: import one template via Elementor local source.
	 */
	public static function ajax_import()
	{
		if (! current_user_can('manage_options')) {
			wp_send_json_error(array('message' => __('Permission denied.', 'storzen')), 403);
		}

		check_ajax_referer('storzen_import_tpl', 'nonce');

		if (! did_action('elementor/loaded') || ! class_exists('\Elementor\Plugin')) {
			wp_send_json_error(array('message' => __('Elementor is not active.', 'storzen')), 400);
		}

		if (class_exists('\Elementor\User') && ! \Elementor\User::is_current_user_can_upload_json()) {
			wp_send_json_error(array('message' => __('You are not allowed to import JSON templates.', 'storzen')), 403);
		}

		$template_id = isset($_POST['template_id']) ? sanitize_key(wp_unslash($_POST['template_id'])) : '';
		if ($template_id === '') {
			wp_send_json_error(array('message' => __('Invalid template.', 'storzen')), 400);
		}

		$entry = self::find_template($template_id);
		if (! $entry || empty($entry['file'])) {
			wp_send_json_error(array('message' => __('Template not found in manifest.', 'storzen')), 404);
		}

		// Per-template gating: PRO-flagged templates require an active PRO license.
		// Free templates import for everyone; only manifest entries with "pro": true
		// are locked. Enforced server-side so the lock can't be bypassed via AJAX.
		$is_pro     = defined('STORZEN_IS_PRO') && STORZEN_IS_PRO === 'yes';
		if (! empty($entry['pro']) && ! $is_pro) {
			wp_send_json_error(array('message' => __('A PRO license is required to import this template.', 'storzen')), 403);
		}

		$path = self::resolve_template_path((string) $entry['file']);
		if (! $path || ! is_readable($path)) {
			wp_send_json_error(array('message' => __('Template file is missing or invalid.', 'storzen')), 400);
		}

		$source = \Elementor\Plugin::instance()->templates_manager->get_source('local');
		if (! $source) {
			wp_send_json_error(array('message' => __('Elementor template library is unavailable.', 'storzen')), 500);
		}

		$name = basename($path);
		$result = $source->import_template($name, $path);

		if (is_wp_error($result)) {
			wp_send_json_error(
				array(
					'message' => $result->get_error_message(),
				),
				500
			);
		}

		if (empty($result) || ! is_array($result)) {
			wp_send_json_error(array('message' => __('Import returned no data.', 'storzen')), 500);
		}

		$first = $result[0];
		$lib_id = 0;
		if (is_array($first) && ! empty($first['template_id'])) {
			$lib_id = (int) $first['template_id'];
		} elseif (is_numeric($first)) {
			$lib_id = (int) $first;
		}

		$edit_url = '';
		if ($lib_id && class_exists('\Elementor\Plugin')) {
			$document = \Elementor\Plugin::instance()->documents->get($lib_id);
			if ($document) {
				$edit_url = $document->get_edit_url();
			}
		}

		// ── Auto-enable any widget toggles needed by this template ─────────
		// Without this, an imported template that uses (say) the Product Share
		// widget would render as "Widget not found" because the toggle defaults
		// to OFF. We scan the JSON for widgetTypes, look each one up in the
		// widget → toggle map, and flip those toggles ON. Idempotent — already-
		// enabled toggles aren't touched.
		$enabled_toggles = self::enable_toggles_for_template_file($path);

		wp_send_json_success(
			array(
				'template_id'     => $lib_id,
				'edit_url'        => $edit_url,
				'title'           => isset($entry['title']) ? $entry['title'] : '',
				'enabled_toggles' => $enabled_toggles, // [{'key': 'product_share', 'label': 'Product Share'}, ...]
			)
		);
	}

	/**
	 * Widget name → (toggle key, parent tab) lookup.
	 *
	 * Mirrors the registration logic in
	 * elementor/storzen-elementor-widgets-init.php. When a widget appears
	 * in an imported template, the corresponding toggle on the corresponding
	 * settings tab is flipped ON so the widget actually registers.
	 *
	 * Tab slugs match the admin-panel.php tab declarations; option keys are
	 * built as `pk_storzen_widgets_<tab>` by the Panel framework.
	 *
	 * @return array<string, array{toggle:string, tab:string, label:string}>
	 */
	protected static function widget_toggle_map()
	{
		return array(
			// Shop tab
			'storzen-grid'                      => array('toggle' => 'product_card',           'tab' => 'shop',           'label' => 'Product Card'),
			'storzen-archive-grid'              => array('toggle' => 'archive_grid',           'tab' => 'shop',           'label' => 'Archive Products Grid'),
			'storzen-shop-sidebar'              => array('toggle' => 'elementor_shop_sidebar', 'tab' => 'shop',           'label' => 'Shop With Sidebar'),
			'storzen-sidebar-filter-search'     => array('toggle' => 'sidebar_search',         'tab' => 'shop',           'label' => 'Sidebar Products Search'),
			'storzen-sidebar-filter-categories' => array('toggle' => 'sidebar_ajax_cats',      'tab' => 'shop',           'label' => 'Sidebar Ajax Categories'),
			'storzen-sidebar-filter-attributes' => array('toggle' => 'sidebar_ajax_attrs',     'tab' => 'shop',           'label' => 'Sidebar Ajax Attributes'),
			'storzen-sidebar-filter-stock'      => array('toggle' => 'sidebar_ajax_stock',     'tab' => 'shop',           'label' => 'Sidebar Ajax Stock'),
			'storzen-sidebar-filter-ratings'    => array('toggle' => 'sidebar_ajax_ratings',   'tab' => 'shop',           'label' => 'Sidebar Ajax Ratings'),
			'storzen-slider'                    => array('toggle' => 'product_carousel',       'tab' => 'shop',           'label' => 'Product Carousel'),
			'storzen-general'                   => array('toggle' => 'product_grid_w',         'tab' => 'shop',           'label' => 'Product Grid'),
			'storzen-tab'                       => array('toggle' => 'elementor_shop_tab',     'tab' => 'shop',           'label' => 'Tab Style'),
			'storzen-list-style'                => array('toggle' => 'elementor_shop_list',    'tab' => 'shop',           'label' => 'List Style'),

			// 'sidebar-filter' is gated by ANY sidebar_ajax_*; turning on the
			// most common one (categories) is enough for it to render.
			'storzen-sidebar-filter'            => array('toggle' => 'sidebar_ajax_cats',      'tab' => 'shop',           'label' => 'Sidebar Ajax Categories'),

			// Shop Details tab
			'storzen-product-title'             => array('toggle' => 'product_title',          'tab' => 'shop_details',   'label' => 'Product Title'),
			'storzen-product-price'             => array('toggle' => 'product_price',          'tab' => 'shop_details',   'label' => 'Product Price'),
			'storzen-product-rating'            => array('toggle' => 'product_rating',         'tab' => 'shop_details',   'label' => 'Product Rating'),
			'storzen-product-add-to-cart'       => array('toggle' => 'product_atc',            'tab' => 'shop_details',   'label' => 'Add to Cart'),
			'storzen-product-gallery'           => array('toggle' => 'product_gallery',        'tab' => 'shop_details',   'label' => 'Product Gallery'),
			'storzen-product-description'       => array('toggle' => 'product_desc',           'tab' => 'shop_details',   'label' => 'Product Description'),
			'storzen-product-related'           => array('toggle' => 'related_products',       'tab' => 'shop_details',   'label' => 'Related Products'),
			'storzen-product-tabs'              => array('toggle' => 'product_tabs',           'tab' => 'shop_details',   'label' => 'Product Tabs'),
			'storzen-product-sticky-atc'        => array('toggle' => 'sticky_atc',             'tab' => 'shop_details',   'label' => 'Sticky Add to Cart'),
			'storzen-product-share'             => array('toggle' => 'product_share',          'tab' => 'shop_details',   'label' => 'Product Share'),
			'storzen-product-meta'              => array('toggle' => 'product_meta',           'tab' => 'shop_details',   'label' => 'SKU, Category & Tags'),
			'storzen-product-service-info'      => array('toggle' => 'product_service_info',   'tab' => 'shop_details',   'label' => 'Product Service Info'),
			'storzen-product-buy-now'           => array('toggle' => 'buy_now',                'tab' => 'shop_details',   'label' => 'Buy It Now'),
			'storzen-product-utility-links'     => array('toggle' => 'product_utility_links',  'tab' => 'shop_details',   'label' => 'Compare / Shipping / Ask'),
			'storzen-product-realtime-visitor'  => array('toggle' => 'realtime_visitor',       'tab' => 'shop_details',   'label' => 'Realtime Visitor'),

			// Cart tab
			'storzen-cart-table'                => array('toggle' => 'cart_table',             'tab' => 'cart',           'label' => 'Cart Table'),
			'storzen-cart-totals'               => array('toggle' => 'cart_totals',            'tab' => 'cart',           'label' => 'Cart Totals'),
			'storzen-cart-coupon'               => array('toggle' => 'cart_coupon',            'tab' => 'cart',           'label' => 'Cart Coupon'),
			'storzen-mini-cart-drawer'          => array('toggle' => 'mini_cart_drw',          'tab' => 'cart',           'label' => 'Mini Cart Drawer'),

			// Checkout tab
			'storzen-checkout-form'             => array('toggle' => 'checkout_form',          'tab' => 'checkout',       'label' => 'Checkout Form'),
			'storzen-checkout-order-review'     => array('toggle' => 'order_review',           'tab' => 'checkout',       'label' => 'Order Review'),
			'storzen-checkout-payment'          => array('toggle' => 'payment_methods',        'tab' => 'checkout',       'label' => 'Payment Methods'),

			// Thank You tab
			'storzen-thankyou-order-details'    => array('toggle' => 'order_details',          'tab' => 'thankyou',       'label' => 'Order Details'),
			'storzen-thankyou-order-summary'    => array('toggle' => 'order_summary',          'tab' => 'thankyou',       'label' => 'Order Summary'),
			'storzen-thankyou-upsell-after'     => array('toggle' => 'upsell_after',           'tab' => 'thankyou',       'label' => 'Upsell After Purchase'),

			// My Account tab
			'storzen-my-account-dashboard'      => array('toggle' => 'acc_dashboard',          'tab' => 'my_account',     'label' => 'Account Dashboard'),
			'storzen-my-account-orders'         => array('toggle' => 'acc_orders',             'tab' => 'my_account',     'label' => 'Account Orders'),
			'storzen-my-account-addresses'      => array('toggle' => 'acc_addresses',          'tab' => 'my_account',     'label' => 'Account Addresses'),
			'storzen-my-account-details'        => array('toggle' => 'acc_details',            'tab' => 'my_account',     'label' => 'Account Details'),
			'storzen-my-account-login'          => array('toggle' => 'acc_login',              'tab' => 'my_account',     'label' => 'Account Login'),
			'storzen-my-account-wishlist'       => array('toggle' => 'acc_wishlist',           'tab' => 'my_account',     'label' => 'Account Wishlist'),
			'storzen-my-account-full'           => array('toggle' => 'acc_full',               'tab' => 'my_account',     'label' => 'My Account (Full)'),
		);
	}

	/**
	 * Scan an Elementor template JSON file and recursively collect every
	 * `widgetType`. Returns a flat array of unique widget names.
	 *
	 * @param string $json_path  Absolute path to the template JSON.
	 * @return string[]
	 */
	protected static function extract_widget_types_from_template($json_path)
	{
		if (! is_readable($json_path)) {
			return array();
		}

		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Local bundled JSON.
		$raw = file_get_contents($json_path);
		$data = json_decode($raw, true);
		if (! is_array($data)) {
			return array();
		}

		$found = array();
		self::walk_elementor_tree($data, $found);
		return array_values(array_unique($found));
	}

	/**
	 * Recursive walker — collects widgetType strings from an Elementor tree.
	 *
	 * @param mixed $node
	 * @param array $found  Collected widget types (passed by reference).
	 */
	protected static function walk_elementor_tree($node, array &$found)
	{
		if (is_array($node)) {
			$is_widget = isset($node['elType']) && $node['elType'] === 'widget';
			if ($is_widget && ! empty($node['widgetType']) && is_string($node['widgetType'])) {
				$found[] = $node['widgetType'];
			}
			foreach ($node as $child) {
				if (is_array($child)) {
					self::walk_elementor_tree($child, $found);
				}
			}
		}
	}

	/**
	 * Read a template's widgetTypes, map them to toggles, and ensure each toggle
	 * is set to true in the appropriate option key.
	 *
	 * Idempotent — toggles already ON are not touched, and the response only
	 * lists toggles that were *changed* by this call so the UI can confirm
	 * exactly what happened.
	 *
	 * @param string $template_path Absolute path to the template JSON.
	 * @return array<int, array{key:string, label:string}>  Toggles that were just enabled.
	 */
	protected static function enable_toggles_for_template_file($template_path)
	{
		$widget_types = self::extract_widget_types_from_template($template_path);
		if (empty($widget_types)) {
			return array();
		}

		$map = self::widget_toggle_map();

		// Group required toggles by their tab so we update each option once.
		// $required: tab => [toggle_key => label]
		$required = array();
		foreach ($widget_types as $type) {
			if (! isset($map[$type])) {
				continue; // Non-Storzen widget (core Elementor) — nothing to enable.
			}
			$entry = $map[$type];
			$tab   = $entry['tab'];
			if (! isset($required[$tab])) {
				$required[$tab] = array();
			}
			$required[$tab][$entry['toggle']] = $entry['label'];
		}

		if (empty($required)) {
			return array();
		}

		$changed = array();

		foreach ($required as $tab => $toggles) {
			$option_key = 'pk_storzen_widgets_' . $tab;
			$opt        = get_option($option_key, array());
			if (! is_array($opt)) {
				$opt = array();
			}

			// Force-write every required toggle to TRUE regardless of current
			// state. This is bulletproof against runtime/UI default mismatches
			// (a class of bug where a widget appears "on" in the admin UI but
			// the runtime check returns false because get_widget_toggle_default
			// disagrees with admin-panel's set_default).
			//
			// We still track which toggles actually CHANGED value so the import
			// success card can surface exactly what was modified to the user.
			$dirty = false;
			foreach ($toggles as $toggle_key => $label) {
				$current = isset($opt[$toggle_key]) ? $opt[$toggle_key] : null;
				$was_on  = ($current === true) || ($current === 1) || ($current === '1');

				// Always set to true.
				$opt[$toggle_key] = true;
				$dirty            = true;

				// Only report the toggle if it actually changed value, so the
				// UI doesn't list every toggle on every re-import.
				if (! $was_on) {
					$changed[] = array('key' => $toggle_key, 'label' => $label);
				}
			}

			if ($dirty) {
				update_option($option_key, $opt);
			}
		}

		return $changed;
	}

	/** @var string[] */
	protected static $allowed_thumb_ext = array('jpg', 'jpeg', 'png', 'gif', 'webp', 'svg');

	/**
	 * URL shown when manifest has no thumb or file missing.
	 *
	 * @return string
	 */
	public static function get_default_preview_url()
	{
		return STORZEN_ROOT_URL . 'data/elementor-templates/images/preview-placeholder.svg';
	}

	/**
	 * Resolve preview image URL for the import grid.
	 *
	 * - Empty: use bundled placeholder (caller may substitute).
	 * - `http://` or `https://`: external image (validated URL).
	 * - Relative path: file under `data/elementor-templates/` (same rules as JSON files).
	 *
	 * @param string               $thumb Relative path, full URL, or empty.
	 * @param array<string, mixed> $tpl   Full template entry from manifest (for filters).
	 * @return string Safe URL for <img src=""> or empty if invalid.
	 */
	public static function get_preview_image_url($thumb, array $tpl = array())
	{
		$thumb = trim((string) $thumb);

		if ($thumb === '') {
			$url = '';
		} elseif (preg_match('#^https?://#i', $thumb)) {
			$parsed = wp_parse_url($thumb);
			if (empty($parsed['scheme']) || ! in_array(strtolower((string) $parsed['scheme']), array('http', 'https'), true)) {
				$url = '';
			} else {
				$url = esc_url_raw($thumb);
			}
		} else {
			$relative = str_replace(array("\0", '../', '..\\'), '', $thumb);
			$relative = ltrim(str_replace('\\', '/', $relative), '/');
			$ext      = strtolower((string) pathinfo($relative, PATHINFO_EXTENSION));
			if ($relative === '' || ! in_array($ext, self::$allowed_thumb_ext, true)) {
				$url = '';
			} else {
				$full = self::$base_dir . $relative;
				$real_base = realpath(self::$base_dir);
				$real_file = realpath($full);
				if (! $real_base || ! $real_file || strpos($real_file, $real_base) !== 0 || ! is_readable($real_file)) {
					$url = '';
				} else {
					$url = STORZEN_ROOT_URL . 'data/elementor-templates/' . $relative;
				}
			}
		}

		/**
		 * Filter the preview image URL for one template card.
		 *
		 * @param string               $url  Resolved URL or empty.
		 * @param array<string, mixed> $tpl  Manifest entry.
		 * @param string               $thumb Raw thumb value from manifest.
		 */
		return (string) apply_filters('storzen_import_template_preview_url', $url, $tpl, $thumb);
	}

	/**
	 * Render admin page HTML (grid + filters).
	 */
	public static function render_page()
	{
		if (! current_user_can('manage_options')) {
			return;
		}

		$is_pro   = defined('STORZEN_IS_PRO') && STORZEN_IS_PRO === 'yes';
		$manifest = self::get_manifest();
		$items    = $manifest['templates'];

		$cats = array(
			'all'             => __('All', 'storzen'),
			'shop'            => __('Shop', 'storzen'),
			'single-product'  => __('Single Product', 'storzen'),
			'cart'            => __('Cart', 'storzen'),
			'checkout'        => __('Checkout', 'storzen'),
			'account'         => __('My Account', 'storzen'),
			'thank-you'       => __('Thank You', 'storzen'),
		);

?>
		<div class="wrap szp-import-templates">
			<h1><?php echo esc_html__('Import Templates', 'storzen'); ?></h1>
			<p class="description">
				<?php echo esc_html__('Import Elementor templates bundled with this plugin into your site library. Requires Elementor.', 'storzen'); ?>
			</p>

			<?php if (! did_action('elementor/loaded')) : ?>
				<div class="notice notice-warning">
					<p><?php echo esc_html__('Please install and activate Elementor to import templates.', 'storzen'); ?></p>
				</div>
			<?php endif; ?>

			<div class="szp-import-filters" role="tablist" aria-label="<?php esc_attr_e('Filter templates', 'storzen'); ?>">
				<?php foreach ($cats as $slug => $label) : ?>
					<button type="button" class="button szp-filter-pill<?php echo 'all' === $slug ? ' is-active' : ''; ?>" data-filter="<?php echo esc_attr($slug); ?>">
						<?php echo esc_html($label); ?>
					</button>
				<?php endforeach; ?>
			</div>

			<?php if (empty($items)) : ?>
				<p class="szp-import-empty"><?php echo esc_html__('No templates in manifest. Add JSON files under data/elementor-templates/ — see README.txt in that folder.', 'storzen'); ?></p>
			<?php else : ?>
				<div class="szp-import-grid">
					<?php foreach ($items as $tpl) : ?>
						<?php
						$tid      = isset($tpl['id']) ? sanitize_key($tpl['id']) : '';
						$title    = isset($tpl['title']) ? $tpl['title'] : $tid;
						$cat      = isset($tpl['category']) ? sanitize_key($tpl['category']) : 'other';
						if (! isset($cats[$cat]) && 'all' !== $cat) {
							$cat = 'other';
						}
						$thumb    = isset($tpl['thumb']) ? $tpl['thumb'] : '';
						$turl     = self::get_preview_image_url($thumb, $tpl);
						if ($turl === '') {
							$turl = self::get_default_preview_url();
						}
						$desc     = isset($tpl['description']) ? $tpl['description'] : '';
						$is_tpl_pro  = ! empty($tpl['pro']);
						$tpl_locked  = $is_tpl_pro && ! $is_pro;
						?>
						<article class="szp-import-card<?php echo $tpl_locked ? ' szp-import-card--locked' : ''; ?>" data-category="<?php echo esc_attr($cat); ?>" data-template-id="<?php echo esc_attr($tid); ?>">
							<?php if ($is_tpl_pro) : ?>
								<span class="szp-import-card__pro-badge">PRO</span>
							<?php endif; ?>
							<div class="szp-import-card__thumb">
								<img class="szp-import-card__img" src="<?php echo esc_url($turl); ?>" alt="<?php echo esc_attr($title); ?>" loading="lazy" decoding="async" />
								<div class="szp-import-card__overlay">
									<?php if ($tpl_locked) : ?>
										<a href="<?php echo esc_url('https://storzen.webtend.net/pricing/'); ?>" target="_blank" rel="noopener" class="button button-primary">
											<?php esc_html_e('Upgrade to PRO', 'storzen'); ?>
										</a>
									<?php else : ?>
										<button type="button" class="button button-primary szp-import-btn" data-template-id="<?php echo esc_attr($tid); ?>" <?php disabled(! did_action('elementor/loaded')); ?>>
											<?php echo esc_html__('Import template', 'storzen'); ?>
										</button>
									<?php endif; ?>
								</div>
							</div>
							<h3 class="szp-import-card__title"><?php echo esc_html($title); ?></h3>
							<?php if ($desc) : ?>
								<p class="szp-import-card__desc"><?php echo esc_html($desc); ?></p>
							<?php endif; ?>
							<p class="szp-import-card__msg" aria-live="polite"></p>
						</article>
					<?php endforeach; ?>
				</div>
			<?php endif; ?>
		</div>
<?php
	}
}
