<?php
/**
 * FoodOrd Theme demo importer.
 *
 * @package FoodOrd
 */

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

/**
 * Class Foodord_Theme_Demo_Importer
 */
class Foodord_Theme_Demo_Importer {
	/**
	 * Pending import option.
	 */
	private const OPTION_PENDING = 'foodord_theme_demo_import_pending';

	/**
	 * Completed import option.
	 */
	private const OPTION_COMPLETE = 'foodord_theme_demo_import_complete';

	/**
	 * One-time admin notice transient.
	 */
	private const TRANSIENT_NOTICE = 'foodord_theme_demo_import_notice';

	/**
	 * Backup meta key for order page content before theme migration.
	 */
	private const META_ORDER_PAGE_BACKUP = '_foodord_theme_demo_order_page_backup';

	/**
	 * Theme demo package relative path.
	 */
	private const PACKAGE_RELATIVE_PATH = 'config/theme-demo-import.json';

	/**
	 * Local asset directory relative to the active parent theme.
	 */
	private const PACKAGE_ASSETS_RELATIVE_DIR = 'config/theme-demo-assets';

	/**
	 * Init hooks.
	 *
	 * @return void
	 */
	public function init() {
		if ( ! is_admin() ) {
			return;
		}

		add_action( 'after_switch_theme', array( $this, 'queue_import_after_theme_switch' ) );
		add_action( 'admin_init', array( $this, 'maybe_run_import' ), 20 );
		add_action( 'admin_notices', array( $this, 'render_admin_notice' ) );
	}

	/**
	 * Queue theme import after the FoodOrd theme becomes active.
	 *
	 * @return void
	 */
	public function queue_import_after_theme_switch() {
		if ( ! function_exists( 'foodord_is_theme_active' ) || ! foodord_is_theme_active() ) {
			return;
		}

		if ( ! $this->needs_theme_demo_import() ) {
			delete_option( self::OPTION_PENDING );
			return;
		}

		$package_hash = $this->get_package_hash();
		if ( '' === $package_hash ) {
			return;
		}

		update_option( self::OPTION_PENDING, $package_hash );
	}

	/**
	 * Maybe run the theme demo import.
	 *
	 * @return void
	 */
	public function maybe_run_import() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		if ( function_exists( 'wp_doing_ajax' ) && wp_doing_ajax() ) {
			return;
		}

		if ( is_network_admin() ) {
			return;
		}

		if ( ! function_exists( 'foodord_is_theme_active' ) || ! foodord_is_theme_active() ) {
			return;
		}

		$package = $this->read_package();
		if ( ! is_array( $package ) ) {
			return;
		}

		$package_hash = $this->get_package_hash();
		if ( '' === $package_hash ) {
			return;
		}

		if ( $package_hash === get_option( self::OPTION_COMPLETE, '' ) ) {
			delete_option( self::OPTION_PENDING );
			return;
		}

		$pending_hash = (string) get_option( self::OPTION_PENDING, '' );
		if ( $package_hash !== $pending_hash ) {
			if ( ! $this->needs_theme_demo_import() ) {
				return;
			}

			update_option( self::OPTION_PENDING, $package_hash );
		}

		$order_page_id = $this->resolve_order_page_id();
		if ( $order_page_id <= 0 ) {
			return;
		}

		$this->disable_plugin_onboarding_redirect();
		$this->migrate_order_page_content( $order_page_id, $package );
		$this->import_theme_sidebar_widgets( $package );
		$this->import_theme_styling( $package );
		$this->import_cookie_law( $package );
		$this->import_home_banner( $package );

		update_option( self::OPTION_COMPLETE, $package_hash );
		delete_option( self::OPTION_PENDING );

		set_transient(
			self::TRANSIENT_NOTICE,
			__( 'FoodOrd Theme demo settings were applied to the existing FoodOrd order page layout.', 'foodord' ),
			60
		);
	}

	/**
	 * Render a one-time admin notice after import.
	 *
	 * @return void
	 */
	public function render_admin_notice() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		$message = get_transient( self::TRANSIENT_NOTICE );
		if ( ! is_string( $message ) || '' === $message ) {
			return;
		}

		delete_transient( self::TRANSIENT_NOTICE );

		wp_admin_notice(
			$message,
			array(
				'type'               => 'success',
				'dismissible'        => true,
				'additional_classes' => array( 'foodord-theme-demo-notice' ),
			)
		);
	}

	/**
	 * Determine whether the site still looks like a plugin-only setup.
	 *
	 * @return bool
	 */
	private function needs_theme_demo_import(): bool {
		$page_id = $this->resolve_order_page_id();
		if ( $page_id <= 0 ) {
			return false;
		}

		$post = get_post( $page_id );
		if ( ! $post instanceof WP_Post ) {
			return false;
		}

		$content = (string) $post->post_content;
		return $this->content_has_inline_card( $content );
	}

	/**
	 * Resolve the order page created by the plugin-only onboarding.
	 *
	 * @return int
	 */
	private function resolve_order_page_id(): int {
		$candidates = array();

		$stored_page_id = (int) get_option( 'foodord_onboarding_order_page_id', 0 );
		if ( $stored_page_id > 0 ) {
			$candidates[] = $stored_page_id;
		}

		$front_page_id = (int) get_option( 'page_on_front', 0 );
		if ( $front_page_id > 0 ) {
			$candidates[] = $front_page_id;
		}

		foreach ( array_unique( array_filter( $candidates ) ) as $page_id ) {
			$post = get_post( $page_id );
			if ( $post instanceof WP_Post && 'page' === $post->post_type ) {
				return (int) $post->ID;
			}
		}

		$pages = get_posts(
			array(
				'post_type'      => 'page',
				'post_status'    => array( 'publish', 'draft', 'private' ),
				'posts_per_page' => -1,
				'fields'         => 'ids',
			)
		);

		foreach ( $pages as $page_id ) {
			$post = get_post( (int) $page_id );
			if ( ! $post instanceof WP_Post ) {
				continue;
			}

			$content = (string) $post->post_content;
			if ( $this->content_has_inline_card( $content ) ) {
				return (int) $post->ID;
			}
		}

		return 0;
	}

	/**
	 * Determine whether the given content contains an inline FoodOrd card.
	 *
	 * @param string $content Post content.
	 * @return bool
	 */
	private function content_has_inline_card( string $content ): bool {
		if ( function_exists( 'has_shortcode' ) && has_shortcode( $content, 'foodord_card' ) ) {
			return true;
		}

		if ( function_exists( 'has_block' ) && has_block( 'foodord/card', $content ) ) {
			return true;
		}

		return false;
	}

	/**
	 * Disable plugin onboarding redirect once theme import takes over.
	 *
	 * @return void
	 */
	private function disable_plugin_onboarding_redirect() {
		update_option( 'foodord_onboarding_complete', 'yes' );
		delete_option( 'foodord_onboarding_redirect' );
	}

	/**
	 * Migrate the existing order page from inline cart to theme sidebar mode.
	 *
	 * @param int                $page_id Order page ID.
	 * @param array<string,mixed> $package Theme package.
	 * @return void
	 */
	private function migrate_order_page_content( int $page_id, array $package ) {
		$post = get_post( $page_id );
		if ( ! $post instanceof WP_Post ) {
			return;
		}

		$original_content = (string) $post->post_content;
		$updated_content  = $this->remove_inline_card_from_content( $original_content );

		if ( '' === trim( $updated_content ) ) {
			$fallback_content = $this->get_package_order_page_content( $package );
			if ( '' !== trim( $fallback_content ) ) {
				$updated_content = $fallback_content;
			}
		}

		if ( $original_content === $updated_content ) {
			return;
		}

		if ( '' === (string) get_post_meta( $page_id, self::META_ORDER_PAGE_BACKUP, true ) ) {
			update_post_meta( $page_id, self::META_ORDER_PAGE_BACKUP, $original_content );
		}

		wp_update_post(
			array(
				'ID'           => $page_id,
				'post_content' => $updated_content,
			)
		);
	}

	/**
	 * Remove inline FoodOrd card references from content.
	 *
	 * @param string $content Raw content.
	 * @return string
	 */
	private function remove_inline_card_from_content( string $content ): string {
		$updated = preg_replace( '/\s*\[foodord_card[^\]]*\]\s*/i', "\n", $content );
		$updated = is_string( $updated ) ? $updated : $content;

		$updated = preg_replace( '/\s*<!--\s*wp:foodord\/card\b[^>]*\/-->\s*/i', "\n", $updated );
		$updated = is_string( $updated ) ? $updated : $content;

		$updated = preg_replace( '/\s*<!--\s*wp:foodord\/card\b[^>]*-->.*?<!--\s*\/wp:foodord\/card\s*-->\s*/is', "\n", $updated );
		$updated = is_string( $updated ) ? $updated : $content;

		$updated = preg_replace( "/\n{3,}/", "\n\n", $updated );
		$updated = is_string( $updated ) ? trim( $updated ) . "\n" : $content;

		return $updated;
	}

	/**
	 * Get fallback order page content from the theme package.
	 *
	 * @param array<string,mixed> $package Theme package.
	 * @return string
	 */
	private function get_package_order_page_content( array $package ): string {
		$order_pages = isset( $package['order_pages'] ) && is_array( $package['order_pages'] ) ? $package['order_pages'] : array();
		foreach ( $order_pages as $page ) {
			if ( ! is_array( $page ) ) {
				continue;
			}

			$content = isset( $page['content'] ) ? (string) $page['content'] : '';
			if ( '' !== trim( $content ) ) {
				return $content;
			}
		}

		return '';
	}

	/**
	 * Import the theme sidebar and footer block widgets from the package.
	 *
	 * @param array<string,mixed> $package Theme package.
	 * @return void
	 */
	private function import_theme_sidebar_widgets( array $package ) {
		$widgets        = isset( $package['widgets'] ) && is_array( $package['widgets'] ) ? $package['widgets'] : array();
		$sidebars       = isset( $widgets['sidebars_widgets'] ) && is_array( $widgets['sidebars_widgets'] ) ? $widgets['sidebars_widgets'] : array();
		$widget_options = isset( $widgets['widget_options']['widget_block'] ) && is_array( $widgets['widget_options']['widget_block'] )
			? $widgets['widget_options']['widget_block']
			: array();

		if ( empty( $sidebars ) || empty( $widget_options ) ) {
			return;
		}

		$current_sidebars = get_option( 'sidebars_widgets', array() );
		$current_sidebars = is_array( $current_sidebars ) ? $current_sidebars : array();
		$current_blocks   = get_option( 'widget_block', array() );
		$current_blocks   = is_array( $current_blocks ) ? $current_blocks : array();

		$target_sidebars   = array(
			'foodord-sidebar',
			'footer-widget-1',
			'footer-widget-2',
			'footer-widget-3',
			'footer-widget-4',
		);
		$next_instance_id = $this->get_next_widget_block_instance_id( $current_blocks );
		$did_update       = false;

		foreach ( $target_sidebars as $sidebar_id ) {
			$sidebar_items = isset( $sidebars[ $sidebar_id ] ) && is_array( $sidebars[ $sidebar_id ] ) ? $sidebars[ $sidebar_id ] : array();
			if ( empty( $sidebar_items ) ) {
				continue;
			}

			$new_sidebar_items = array();

			foreach ( $sidebar_items as $widget_id ) {
				if ( ! is_string( $widget_id ) || ! preg_match( '/^block-(\d+)$/', $widget_id, $matches ) ) {
					continue;
				}

				$source_id       = (int) $matches[1];
				$source_instance = isset( $widget_options[ $source_id ] ) && is_array( $widget_options[ $source_id ] ) ? $widget_options[ $source_id ] : array();
				if ( empty( $source_instance ) ) {
					continue;
				}

				$existing_id = $this->find_matching_widget_block_instance( $current_blocks, $source_instance );
				if ( $existing_id > 0 ) {
					$new_sidebar_items[] = 'block-' . $existing_id;
					continue;
				}

				$current_blocks[ $next_instance_id ] = $source_instance;
				$new_sidebar_items[]                 = 'block-' . $next_instance_id;
				$next_instance_id++;
			}

			if ( empty( $new_sidebar_items ) ) {
				continue;
			}

			$current_sidebars[ $sidebar_id ] = $new_sidebar_items;
			$did_update = true;
		}

		if ( ! $did_update ) {
			return;
		}

		$current_blocks['_multiwidget'] = 1;
		if ( ! isset( $current_sidebars['array_version'] ) ) {
			$current_sidebars['array_version'] = 3;
		}

		update_option( 'widget_block', $current_blocks );
		update_option( 'sidebars_widgets', $current_sidebars );
	}

	/**
	 * Find a matching block widget instance by content.
	 *
	 * @param array<string|int,mixed> $current_blocks Current widget_block option.
	 * @param array<string,mixed>     $source_instance Source widget instance.
	 * @return int
	 */
	private function find_matching_widget_block_instance( array $current_blocks, array $source_instance ): int {
		$source_content = isset( $source_instance['content'] ) ? trim( (string) $source_instance['content'] ) : '';
		if ( '' === $source_content ) {
			return 0;
		}

		foreach ( $current_blocks as $instance_id => $instance ) {
			if ( ! is_int( $instance_id ) || ! is_array( $instance ) ) {
				continue;
			}

			$current_content = isset( $instance['content'] ) ? trim( (string) $instance['content'] ) : '';
			if ( $current_content === $source_content ) {
				return $instance_id;
			}
		}

		return 0;
	}

	/**
	 * Get the next available numeric block widget instance ID.
	 *
	 * @param array<string|int,mixed> $current_blocks Current widget_block option.
	 * @return int
	 */
	private function get_next_widget_block_instance_id( array $current_blocks ): int {
		$max_id = 1;

		foreach ( array_keys( $current_blocks ) as $instance_id ) {
			if ( is_int( $instance_id ) && $instance_id > $max_id ) {
				$max_id = $instance_id;
			}
		}

		return $max_id + 1;
	}

	/**
	 * Import theme styling settings.
	 *
	 * @param array<string,mixed> $package Theme package.
	 * @return void
	 */
	private function import_theme_styling( array $package ) {
		$styling = isset( $package['theme_admin']['styling'] ) && is_array( $package['theme_admin']['styling'] )
			? $package['theme_admin']['styling']
			: array();

		foreach ( $styling as $key => $value ) {
			$key = is_string( $key ) ? $key : '';
			if ( '' === $key || ! is_string( $value ) ) {
				continue;
			}

			$color = sanitize_hex_color( $value );
			if ( ! $color ) {
				continue;
			}

			set_theme_mod( $key, $color );
		}
	}

	/**
	 * Import cookie law settings.
	 *
	 * @param array<string,mixed> $package Theme package.
	 * @return void
	 */
	private function import_cookie_law( array $package ) {
		$cookie_law = isset( $package['theme_admin']['cookie_law'] ) && is_array( $package['theme_admin']['cookie_law'] )
			? $package['theme_admin']['cookie_law']
			: array();

		if ( empty( $cookie_law ) ) {
			return;
		}

		update_option( 'wr_cookie_law_enabled', ! empty( $cookie_law['enabled'] ) ? 1 : 0 );

		if ( isset( $cookie_law['message'] ) && is_string( $cookie_law['message'] ) ) {
			update_option( 'wr_cookie_law_message', $cookie_law['message'] );
		}

		$page_id = $this->resolve_post_reference_id( isset( $cookie_law['page'] ) ? $cookie_law['page'] : null );
		update_option( 'wr_cookie_law_page', $page_id );
	}

	/**
	 * Import home banner settings.
	 *
	 * @param array<string,mixed> $package Theme package.
	 * @return void
	 */
	private function import_home_banner( array $package ) {
		$home_banner = isset( $package['theme_admin']['home_banner'] ) && is_array( $package['theme_admin']['home_banner'] )
			? $package['theme_admin']['home_banner']
			: array();

		if ( empty( $home_banner ) ) {
			return;
		}

		update_option( 'wr_home_banner_enabled', ! empty( $home_banner['enabled'] ) );

		$image_ids = array();
		if ( isset( $home_banner['images'] ) && is_array( $home_banner['images'] ) ) {
			foreach ( $home_banner['images'] as $image ) {
				if ( ! is_array( $image ) ) {
					continue;
				}

				$image_id = $this->ensure_packaged_attachment( $image );
				if ( $image_id > 0 && ! in_array( $image_id, $image_ids, true ) ) {
					$image_ids[] = $image_id;
				}
			}
		} elseif ( isset( $home_banner['image'] ) && is_array( $home_banner['image'] ) ) {
			$image_id = $this->ensure_packaged_attachment( $home_banner['image'] );
			if ( $image_id > 0 && ! in_array( $image_id, $image_ids, true ) ) {
				$image_ids[] = $image_id;
			}
		}

		if ( ! empty( $image_ids ) ) {
			update_option( 'wr_home_banner_images', $image_ids, false );
			delete_option( 'wr_home_banner_image' );
		}

		$position_options = array(
			'top-left',
			'top-center',
			'top-right',
			'center-left',
			'center-center',
			'center-right',
			'bottom-left',
			'bottom-center',
			'bottom-right',
		);
		foreach ( array( 'desktop', 'tablet', 'mobile' ) as $device ) {
			$position_key = 'position_' . $device;
			$position     = isset( $home_banner[ $position_key ] ) && is_string( $home_banner[ $position_key ] )
				? sanitize_key( $home_banner[ $position_key ] )
				: 'center-center';
			if ( ! in_array( $position, $position_options, true ) ) {
				$position = 'center-center';
			}

			update_option( 'wr_home_banner_position_' . $device, $position );
		}

		if ( isset( $home_banner['logo'] ) && is_array( $home_banner['logo'] ) ) {
			$logo_id = $this->ensure_packaged_attachment( $home_banner['logo'] );
			if ( $logo_id > 0 ) {
				update_option( 'wr_home_banner_logo', $logo_id );
			}
		}

		if ( isset( $home_banner['company_name'] ) && is_string( $home_banner['company_name'] ) ) {
			update_option( 'wr_home_banner_company_name', $home_banner['company_name'] );
		}

		if ( isset( $home_banner['company_phone'] ) && is_string( $home_banner['company_phone'] ) ) {
			update_option( 'wr_home_banner_phone', $home_banner['company_phone'] );
		}

		if ( isset( $home_banner['company_address'] ) && is_string( $home_banner['company_address'] ) ) {
			update_option( 'wr_home_banner_company_address', $home_banner['company_address'] );
		}

		if ( isset( $home_banner['iframe_code'] ) && is_string( $home_banner['iframe_code'] ) ) {
			update_option( 'wr_home_banner_iframe_code', $home_banner['iframe_code'] );
		}
	}

	/**
	 * Ensure an attachment from the theme package exists in the Media Library.
	 *
	 * @param array<string,mixed> $attachment_ref Attachment reference from package.
	 * @return int
	 */
	private function ensure_packaged_attachment( array $attachment_ref ): int {
		$filename = isset( $attachment_ref['filename'] ) ? sanitize_file_name( (string) $attachment_ref['filename'] ) : '';
		if ( '' === $filename ) {
			return 0;
		}

		$existing_id = $this->find_attachment_by_filename( $filename );
		if ( $existing_id > 0 ) {
			return $existing_id;
		}

		$source_path = $this->get_packaged_asset_path( $filename );
		if ( '' === $source_path || ! file_exists( $source_path ) ) {
			return 0;
		}

		$file_contents = file_get_contents( $source_path );
		if ( false === $file_contents ) {
			return 0;
		}

		$upload = wp_upload_bits( $filename, null, $file_contents );
		if ( ! empty( $upload['error'] ) || empty( $upload['file'] ) ) {
			return 0;
		}

		$attachment = array(
			'post_mime_type' => isset( $attachment_ref['mime_type'] ) ? (string) $attachment_ref['mime_type'] : wp_check_filetype( $upload['file'] )['type'],
			'post_title'     => isset( $attachment_ref['title'] ) ? sanitize_text_field( (string) $attachment_ref['title'] ) : pathinfo( $filename, PATHINFO_FILENAME ),
			'post_content'   => '',
			'post_status'    => 'inherit',
		);

		$attachment_id = wp_insert_attachment( $attachment, $upload['file'] );
		if ( ! $attachment_id || is_wp_error( $attachment_id ) ) {
			return 0;
		}

		require_once ABSPATH . 'wp-admin/includes/image.php';

		$metadata = wp_generate_attachment_metadata( $attachment_id, $upload['file'] );
		if ( is_array( $metadata ) ) {
			wp_update_attachment_metadata( $attachment_id, $metadata );
		}

		if ( isset( $attachment_ref['alt'] ) && is_string( $attachment_ref['alt'] ) && '' !== trim( $attachment_ref['alt'] ) ) {
			update_post_meta( $attachment_id, '_wp_attachment_image_alt', sanitize_text_field( $attachment_ref['alt'] ) );
		}

		return (int) $attachment_id;
	}

	/**
	 * Find an attachment by the original filename.
	 *
	 * @param string $filename File name.
	 * @return int
	 */
	private function find_attachment_by_filename( string $filename ): int {
		$filename = sanitize_file_name( $filename );
		if ( '' === $filename ) {
			return 0;
		}

		$cache_key = 'foodord_demo_attachment_' . md5( $filename );
		$cached_id = wp_cache_get( $cache_key, 'foodord-demo-importer' );

		if ( false !== $cached_id ) {
			return absint( $cached_id );
		}

		$attachment_title = pathinfo( $filename, PATHINFO_FILENAME );
		$attachment_ids   = get_posts(
			array(
				'post_type'              => 'attachment',
				'post_status'            => 'inherit',
				'posts_per_page'         => 10,
				'orderby'                => 'ID',
				'order'                  => 'DESC',
				'fields'                 => 'ids',
				'no_found_rows'          => true,
				'cache_results'          => true,
				'update_post_meta_cache' => false,
				'update_post_term_cache' => false,
				'title'                  => $attachment_title,
			)
		);

		if ( empty( $attachment_ids ) || ! is_array( $attachment_ids ) ) {
			wp_cache_set( $cache_key, 0, 'foodord-demo-importer' );
			return 0;
		}

		foreach ( $attachment_ids as $attachment_id ) {
			$attached_file = get_attached_file( $attachment_id );
			if ( ! is_string( $attached_file ) || '' === $attached_file ) {
				continue;
			}

			if ( $filename === wp_basename( $attached_file ) ) {
				$attachment_id = absint( $attachment_id );
				wp_cache_set( $cache_key, $attachment_id, 'foodord-demo-importer' );
				return $attachment_id;
			}
		}

		wp_cache_set( $cache_key, 0, 'foodord-demo-importer' );
		return 0;
	}

	/**
	 * Get a packaged asset path from the active parent theme.
	 *
	 * @param string $filename Asset filename.
	 * @return string
	 */
	private function get_packaged_asset_path( string $filename ): string {
		$filename = sanitize_file_name( $filename );
		if ( '' === $filename ) {
			return '';
		}

		$base_dir = trailingslashit( get_template_directory() ) . self::PACKAGE_ASSETS_RELATIVE_DIR;
		return trailingslashit( $base_dir ) . $filename;
	}

	/**
	 * Resolve a page/post reference from the export payload.
	 *
	 * @param mixed $reference Exported post reference.
	 * @return int
	 */
	private function resolve_post_reference_id( $reference ): int {
		if ( ! is_array( $reference ) ) {
			return 0;
		}

		$post_type = isset( $reference['post_type'] ) ? sanitize_key( (string) $reference['post_type'] ) : 'page';
		$slug      = isset( $reference['slug'] ) ? sanitize_title( (string) $reference['slug'] ) : '';
		if ( '' === $slug ) {
			return 0;
		}

		$post = get_page_by_path( $slug, OBJECT, $post_type );
		return $post instanceof WP_Post ? (int) $post->ID : 0;
	}

	/**
	 * Read the bundled theme package.
	 *
	 * @return array<string,mixed>|null
	 */
	private function read_package() {
		$package_path = trailingslashit( get_template_directory() ) . self::PACKAGE_RELATIVE_PATH;
		if ( ! file_exists( $package_path ) ) {
			return null;
		}

		$raw = file_get_contents( $package_path );
		if ( false === $raw || '' === trim( $raw ) ) {
			return null;
		}

		$decoded = json_decode( $raw, true );
		return is_array( $decoded ) ? $decoded : null;
	}

	/**
	 * Get the current package hash.
	 *
	 * @return string
	 */
	private function get_package_hash(): string {
		$package_path = trailingslashit( get_template_directory() ) . self::PACKAGE_RELATIVE_PATH;
		if ( ! file_exists( $package_path ) ) {
			return '';
		}

		$hash = md5_file( $package_path );
		return is_string( $hash ) ? $hash : '';
	}
}
