/home/sylamedg/www/wp-content/plugins/templately/includes/Core/Importer/Runners/Attachments.php
<?php

namespace Templately\Core\Importer\Runners;

use Templately\Core\Importer\WPImport;

class Attachments extends WPContent {

	private $data = [];

	public function __construct($request_params) {
		parent::__construct($request_params);
		$this->attachments_init();
	}

	public function get_name(): string {
		return 'attachments';
	}

	public function get_label(): string {
		return __('Attachments', 'templately');
	}

	public function should_log(): bool {
		return true;
	}

	public function get_action(): string {
		return 'updateLog';
	}

	public function log_message(): string {
		if ($this->total > 0) {
			return __('Importing Attachments: (' . $this->get_processed() . '/' . $this->total . ')', 'templately');
		}
		return __('Importing Attachment.', 'templately');
	}

	public function should_run($data, $imported_data = []): bool {
		return !empty($this->manifest['has_attachments']);
	}

	public function import($data, $imported_data): array {
		$path       = $this->dir_path;
		$taxonomies = [];
		$terms      = [];
		$results    = [];
		$this->data = $data;

		$this->clear_old_el_cache();

		$this->import_actions();

		$import = $this->_import_type_data('attachments', $path, $imported_data, $taxonomies, $terms);
		$results['attachments'] = $import['summary']['posts'];
		$results['attachments_errors'] = $import['errors'];

		$this->import_actions(true);

		return $results;
	}

	/**
	 * Clear old elementor cache
	 * so that our second image hash for original_attachment_url don't
	 * pick up attachment from previous import
	 */
	public function clear_old_el_cache() {
		global $wpdb;

		$has_processed = $this->get_progress(false, 'attachments-cleared-old-el-cache', false);
		if($has_processed){
			return;
		}

		// Step 1: Retrieve all meta values where the meta_key is '_templately_image_hash_meta_id'
		$meta_ids = $wpdb->get_col(
			$wpdb->prepare(
				"SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s",
				'_templately_image_hash_meta_id'
			)
		);

		// Step 2: Delete the corresponding meta entries using the retrieved meta_ids
		if (!empty($meta_ids)) {
			$placeholders = implode(',', array_fill(0, count($meta_ids), '%d'));
			$wpdb->query(
				$wpdb->prepare(
					"DELETE FROM {$wpdb->postmeta} WHERE meta_id IN ($placeholders)",
					...$meta_ids
				)
			);

			if (defined('TEMPLATELY_DEBUG_LOG') && TEMPLATELY_DEBUG_LOG) {
				error_log('Deleted _elementor_source_image_hash entries with meta_ids: ' . implode(', ', $meta_ids));
			}
		}

		// Step 3: Delete all '_templately_image_hash_meta_id' entries
		$wpdb->delete(
			$wpdb->postmeta,
			array('meta_key' => '_templately_image_hash_meta_id'),
			array('%s')
		);

		// Check for errors
		if (defined('TEMPLATELY_DEBUG_LOG') && TEMPLATELY_DEBUG_LOG) {
			if($wpdb->last_error){
				error_log('MySQL Error during image hash cleanup: ' . $wpdb->last_error);
			}
		}
	}

	protected function import_actions($remove = false) {
		parent::import_actions($remove);

		if ($remove) {
			remove_filter('templately_import_copy_attachment', [$this, 'copy_attachment_file'], 10);
			remove_filter('wp_import_post_data_raw', [$this, 'ai_image_replacement_url'], 10);
			remove_filter('wp_import_post_meta', [$this, 'ai_image_replacement_metadata'], 10);
		} else {
			add_filter('templately_import_copy_attachment', [$this, 'copy_attachment_file'], 10, 4);
			add_filter('wp_import_post_data_raw', [$this, 'ai_image_replacement_url'], 10, 2);
			add_filter('wp_import_post_meta', [$this, 'ai_image_replacement_metadata'], 10, 3);
		}
	}

	public function copy_attachment_file($return, $att_id, $dest_file, $upload_dir) {
		// @todo check mapping url to new id

		if (!empty($att_id)) {
			// skip ai image replacement from local file
			if ($this->is_ai_image($att_id)) {
				return $return;
			}

			$file_name   = basename($dest_file);
			$path        = $this->dir_path . 'attachments' . DIRECTORY_SEPARATOR;
			$wp_filetype = wp_check_filetype($file_name);
			$ext         = $wp_filetype['ext'];

			$source_path = "{$path}{$att_id}.{$ext}";

			if (!file_exists($source_path)) {
				return $return;
			}

			$move_new_file = copy($source_path, $dest_file);

			if (!$move_new_file) {
				return $return;
			}

			$wp_filetype = wp_check_filetype_and_ext($source_path, $file_name);

			// Set correct file permissions.
			$stat  = stat(dirname($dest_file));
			$perms = $stat['mode'] & 0000666;
			chmod($dest_file, $perms);

			return [
				'file'  => $dest_file,
				'url'   => $upload_dir['url'] . "/$file_name",
				'type'  => $wp_filetype['type'],
				'error' => false,
			];
		}


		return $return;
	}

	public function is_ai_image($post_id) {
		if (!empty($post_id) && !empty($this->data["image_mappings"][$post_id])) {
			return true;
		}
		return false;
	}

	/**
	 * @param $post
	 * @param WPImport $wp_importer
	 * @return array
	 */
	public function ai_image_replacement_url($post, $wp_importer) {
		$post_id = $post['post_id'] ?? null;
		if ($this->is_ai_image($post_id) && !empty($post['post_type']) && $post['post_type'] === 'attachment') {
			$image_data = $this->data["image_mappings"][$post_id];

			if (!empty($image_data["newData"]["original"])) {
				$source = $image_data["source"];
				if($source === 'upload'){
					$new_id       = $image_data["newData"]["id"];
					$original_url = $image_data["originalUrl"];
					$new_url      = $image_data["newUrl"];

					$wp_importer->update_post_meta( $new_id );

					// Map pre-import ID to local ID.
					$wp_importer->processed_posts[ (int) $post_id ] = (int) $new_id;

					$wp_importer->set_url_map($original_url, $new_url);
					$wp_importer->set_url_map($original_url, $new_url, true);

					return $new_id;
				}
				else if($source ==='stock' && $image_data['newData']['provider'] == 'pexels'){
					$post['original_attachment_url'] = $post['attachment_url'];
					$post['guid']                    = $image_data["newData"]["original"];
					$post['attachment_url']          = $image_data["newData"]["original"];
				}
				else if($source === 'ai'){
					// @todo: coming soon
				}
			}
		}
		return $post;
	}

	public function ai_image_replacement_metadata($postmeta, $post_id, $post) {

		if ($this->is_ai_image($post_id)) {
			$image_data = $this->data["image_mappings"][$post_id]["newData"] ?? [];
			// alt. provider, photographer
			if (!empty($image_data["alt"])) {
				$postmeta[] = [
					'key'   => '_wp_attachment_image_alt',
					'value' => $image_data["alt"],
				];
			}
			if (!empty($image_data["provider"])) {
				$postmeta[] = [
					'key'   => '_templately_ai_image_provider',
					'value' => $image_data["provider"],
				];
			}
			if (!empty($image_data["photographer"])) {
				$postmeta[] = [
					'key'   => '_templately_ai_image_photographer',
					'value' => $image_data["photographer"],
				];
			}
		}

		return $postmeta;
	}

	public function get_processed() {
		$processed = $this->processed ?? [];
		$succeed = $processed['succeed'] ?? [];
		$failed = $processed['failed'] ?? [];

		return count($succeed) + count($failed);
	}

	public function post_log($post, $result) {
		if (isset($post['post_type'])) {
			if ($post['post_type'] !== 'attachment') {
				return;
			}

			// need to assign to processed so log_message() can use get_processed() to calculate progress
			// also bellow code used it to calculate progress
			$this->processed = $result;

			$type  = $post['post_type'];
			$title = $post['post_title'];
		}

		if (empty($type) || empty($title)) {
			return;
		}

		$progress = $this->total > 0 ? ceil((100 * ($this->get_processed())) / $this->total) : 100;

		$this->log($progress);
	}

	public function attachments_init() {
		add_filter('pre_http_request', [$this, 'pre_http_request'], 10, 3);
		add_filter('http_response', [$this, 'http_response'], 10, 3);
		// attachment insert hooks
		add_filter('wp_insert_attachment_data', [$this, 'before_insert_attachment'], 10, 2);
		add_action('add_attachment', [$this, 'after_insert_attachment'], 10, 1);
		add_filter('wp_update_attachment_metadata', [$this, 'wp_update_attachment_metadata'], 99999, 2);
	}

	public function pre_http_request($preempt, $parsed_args, $url) {
		// error_log(print_r([$preempt, $parsed_args, $url], true));

		$this->sse_log('attachments', 'Before downloading attachment: ' . esc_url($url), 1, 'eventLog');

		return $preempt;
	}

	public function http_response($response, $parsed_args, $url) {
		// error_log(print_r([$response, $parsed_args, $url], true));
		$this->sse_log('attachments', 'After downloading attachment: ' . $url, 1, 'eventLog');
		return $response;
	}

	/**
	 * Log before inserting attachment.
	 */
	public function before_insert_attachment($data, $postarr) {
		$this->sse_log('attachments', 'Before inserting attachment: ' . ($data['post_title'] ?? ''), 1, 'eventLog');
		return $data;
	}

	/**
	 * Log after attachment is inserted.
	 */
	public function after_insert_attachment($post_ID) {
		$post = get_post($post_ID);
		$this->sse_log('attachments', 'After inserting attachment: ' . ($post->post_title ?? ''), 1, 'eventLog');
	}

	public function wp_update_attachment_metadata($metadata, $attachment_id) {
		$this->sse_log('attachments', 'Updated attachment metadata: ' . $attachment_id, 1, 'eventLog');
		// $this->sse_message([
		// 	"action" => "eventLog",
		// 	"type" => "attachments",
		// 	"progress" => 1,
		// 	"message" => "Updated attachment metadata => " . $attachment_id,
		// 	"backtrace" => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 30),
		// ]);
		return $metadata;
	}
}