<?php
/**
 * Copies page-builder layout meta without corrupting JSON/serialized structures.
 *
 * @package BulkPageCreator
 */

namespace BulkPageCreator;

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

final class PageBuilderCopy {

	/** Meta keys that must never be copied (per-post cache, locks, revisions). */
	private const SKIP_KEYS = [
		'_edit_lock',
		'_edit_last',
		'_wp_old_slug',
		'_wp_old_date',
		'_wp_trash_meta_status',
		'_wp_trash_meta_time',
		'_pingme',
		'_encloseme',
		'_thumbnail_id',
	];

	/**
	 * Builder cache/asset meta tied to a specific post ID — skip copy, regenerate after.
	 *
	 * @var list<string>
	 */
	private const CACHE_KEYS = [
		'_elementor_css',
		'_elementor_inline_svg',
		'_elementor_page_assets',
		'_fl_builder_hash',
		'_fl_builder_css',
		'_fl_builder_js',
		'_fl_builder_google_fonts',
		'_bricks_page_css',
		'_bricks_page_js',
		'_bricks_assets',
		'_breakdance_css_file',
		'_breakdance_dependency_cache',
		'ct_css_cache',
		'ct_scripts_cache',
		'_et_dynamic_cached_shortcodes',
	];

	/** @var callable */
	private $substitute;

	/** @var callable */
	private $substitute_array;

	/**
	 * @param callable(string, array): string $substitute
	 * @param callable(array, array): array   $substitute_array
	 */
	public function __construct( callable $substitute, callable $substitute_array ) {
		$this->substitute       = $substitute;
		$this->substitute_array = $substitute_array;
	}

	public function copyFromTemplate( int $template_id, int $post_id, array $row_data ): void {
		$meta = get_post_meta( $template_id );
		if ( ! is_array( $meta ) ) {
			return;
		}

		foreach ( $meta as $key => $values ) {
			if ( ! is_string( $key ) || $this->shouldSkipKey( $key ) ) {
				continue;
			}

			$raw = $values[0] ?? '';
			if ( $raw === '' && $raw !== '0' ) {
				continue;
			}

			$this->copyMetaValue( $key, $raw, $post_id, $row_data );
		}

		$this->finalizeAssets( $post_id );

		/**
		 * Fires after page-builder meta is copied for a bulk-created post.
		 *
		 * @param int   $post_id     New post ID.
		 * @param int   $template_id Source template post ID.
		 * @param array $row_data    CSV row used for substitution.
		 */
		do_action( 'wpps_bpc_after_page_builder_copy', $post_id, $template_id, $row_data );
	}

	private function shouldSkipKey( string $key ): bool {
		if ( in_array( $key, self::SKIP_KEYS, true ) || in_array( $key, self::CACHE_KEYS, true ) ) {
			return true;
		}

		if ( str_starts_with( $key, '_oembed_' ) || str_starts_with( $key, '_menu_item_' ) ) {
			return true;
		}

		// Per-post compiled assets from any builder (e.g. _foo_css, _foo_cache).
		if ( preg_match( '/_(css|cache|hash|assets|compiled)$/i', $key ) ) {
			return true;
		}

		return false;
	}

	private function copyMetaValue( string $key, mixed $raw, int $post_id, array $row_data ): void {
		$value = maybe_unserialize( $raw );

		if ( is_array( $value ) ) {
			$value = ( $this->substitute_array )( $value, $row_data );
			update_post_meta( $post_id, $key, $value );

			return;
		}

		if ( is_object( $value ) ) {
			$value = (object) ( $this->substitute_array )( (array) $value, $row_data );
			update_post_meta( $post_id, $key, $value );

			return;
		}

		if ( ! is_string( $value ) ) {
			update_post_meta( $post_id, $key, $value );

			return;
		}

		if ( $this->isJsonDocument( $value ) ) {
			$decoded = json_decode( $value, true );
			if ( is_array( $decoded ) ) {
				$decoded = ( $this->substitute_array )( $decoded, $row_data );
				update_post_meta( $post_id, $key, wp_slash( wp_json_encode( $decoded ) ) );

				return;
			}
		}

		update_post_meta( $post_id, $key, ( $this->substitute )( $value, $row_data ) );
	}

	private function isJsonDocument( string $value ): bool {
		$trim = ltrim( $value );
		if ( $trim === '' || ( $trim[0] !== '{' && $trim[0] !== '[' ) ) {
			return false;
		}

		json_decode( $value, true );

		return json_last_error() === JSON_ERROR_NONE;
	}

	public function finalizeAssets( int $post_id ): void {
		if ( $post_id <= 0 ) {
			return;
		}

		$this->finalizeElementor( $post_id );
		$this->finalizeBeaverBuilder( $post_id );
		$this->finalizeBricks( $post_id );
		$this->finalizeDivi( $post_id );
		$this->finalizeBreakdance( $post_id );
		$this->finalizeOxygen( $post_id );
		$this->finalizeBrizy( $post_id );

		do_action( 'wpps_bpc_finalize_page_builder_assets', $post_id );
	}

	private function finalizeElementor( int $post_id ): void {
		if ( ! class_exists( '\Elementor\Plugin' ) || get_post_meta( $post_id, '_elementor_data', true ) === '' ) {
			return;
		}

		delete_post_meta( $post_id, '_elementor_css' );

		if ( ! did_action( 'elementor/loaded' ) ) {
			return;
		}

		try {
			$document = \Elementor\Plugin::$instance->documents->get( $post_id, false );
			if ( $document && method_exists( $document, 'is_built_with_elementor' ) && $document->is_built_with_elementor() ) {
				if ( method_exists( $document, 'get_css_file' ) ) {
					$css_file = $document->get_css_file();
					if ( $css_file && method_exists( $css_file, 'update' ) ) {
						$css_file->update();

						return;
					}
				}
			}
			if ( class_exists( '\Elementor\Core\Files\CSS\Post' ) ) {
				$css = new \Elementor\Core\Files\CSS\Post( $post_id );
				if ( method_exists( $css, 'update' ) ) {
					$css->update();
				}
			}
		} catch ( \Throwable $e ) {
			return;
		}
	}

	private function finalizeBeaverBuilder( int $post_id ): void {
		if ( get_post_meta( $post_id, '_fl_builder_data', true ) === '' && get_post_meta( $post_id, '_fl_builder_draft', true ) === '' ) {
			return;
		}

		delete_post_meta( $post_id, '_fl_builder_hash' );
		delete_post_meta( $post_id, '_fl_builder_css' );
		delete_post_meta( $post_id, '_fl_builder_js' );

		if ( ! class_exists( 'FLBuilderModel' ) ) {
			return;
		}

		try {
			if ( method_exists( 'FLBuilderModel', 'delete_asset_cache_for_post' ) ) {
				\FLBuilderModel::delete_asset_cache_for_post( $post_id );
			} elseif ( method_exists( 'FLBuilderModel', 'delete_all_asset_cache' ) ) {
				\FLBuilderModel::delete_all_asset_cache( $post_id );
			}
			if ( class_exists( 'FLBuilder' ) && method_exists( 'FLBuilder', 'generate_post_css' ) ) {
				\FLBuilder::generate_post_css( $post_id );
			}
		} catch ( \Throwable $e ) {
			return;
		}
	}

	private function finalizeBricks( int $post_id ): void {
		$has_bricks = get_post_meta( $post_id, '_bricks_page_content_2', true ) !== ''
			|| get_post_meta( $post_id, '_bricks_page_header_2', true ) !== ''
			|| get_post_meta( $post_id, '_bricks_page_footer_2', true ) !== '';

		if ( ! $has_bricks ) {
			return;
		}

		foreach ( [ '_bricks_page_css', '_bricks_page_js', '_bricks_assets' ] as $cache_key ) {
			delete_post_meta( $post_id, $cache_key );
		}

		if ( ! defined( 'BRICKS_VERSION' ) ) {
			return;
		}

		try {
			if ( class_exists( '\Bricks\Assets' ) && method_exists( '\Bricks\Assets', 'generate_css_file' ) ) {
				\Bricks\Assets::generate_css_file( $post_id );
			} elseif ( class_exists( '\Bricks\Assets' ) && method_exists( '\Bricks\Assets', 'generate_inline_css' ) ) {
				\Bricks\Assets::generate_inline_css( $post_id );
			}
		} catch ( \Throwable $e ) {
			return;
		}
	}

	private function finalizeDivi( int $post_id ): void {
		$uses_divi = get_post_meta( $post_id, '_et_pb_use_builder', true ) === 'on'
			|| str_contains( (string) get_post_field( 'post_content', $post_id ), '[et_pb_' );

		if ( ! $uses_divi ) {
			return;
		}

		delete_post_meta( $post_id, '_et_dynamic_cached_shortcodes' );

		try {
			if ( class_exists( '\ET_Core_PageResource' ) && method_exists( '\ET_Core_PageResource', 'remove_static_resources' ) ) {
				\ET_Core_PageResource::remove_static_resources( $post_id, 'all' );
			}
			if ( function_exists( 'et_pb_clear_cached_templates' ) ) {
				et_pb_clear_cached_templates();
			}
		} catch ( \Throwable $e ) {
			return;
		}
	}

	private function finalizeBreakdance( int $post_id ): void {
		if ( get_post_meta( $post_id, '_breakdance_data', true ) === '' ) {
			return;
		}

		delete_post_meta( $post_id, '_breakdance_css_file' );
		delete_post_meta( $post_id, '_breakdance_dependency_cache' );

		try {
			if ( class_exists( '\Breakdance\Render\AssetManager' ) && method_exists( '\Breakdance\Render\AssetManager', 'clearCache' ) ) {
				\Breakdance\Render\AssetManager::clearCache( $post_id );
			}
		} catch ( \Throwable $e ) {
			return;
		}
	}

	private function finalizeOxygen( int $post_id ): void {
		$has_oxygen = get_post_meta( $post_id, 'ct_builder_json', true ) !== ''
			|| get_post_meta( $post_id, 'ct_builder_shortcodes', true ) !== '';

		if ( ! $has_oxygen ) {
			return;
		}

		delete_post_meta( $post_id, 'ct_css_cache' );
		delete_post_meta( $post_id, 'ct_scripts_cache' );
	}

	private function finalizeBrizy( int $post_id ): void {
		if ( get_post_meta( $post_id, 'brizy-post', true ) === '' ) {
			return;
		}

		delete_post_meta( $post_id, 'brizy-post-editor-version' );
		delete_post_meta( $post_id, 'brizy-asset-version' );
	}
}
