<?php

namespace NewfoldLabs\WP\Module\Onboarding\Data\Services;

use NewfoldLabs\WP\Module\AI\SiteGen\SiteGen;
use NewfoldLabs\WP\Module\Onboarding\Data\Options;
use NewfoldLabs\WP\Module\Onboarding\Data\Data;
use NewfoldLabs\WP\Module\Onboarding\Data\Mustache\Mustache;
use NewfoldLabs\WP\Module\Onboarding\Data\Themes;
use NewfoldLabs\WP\Module\Onboarding\Data\Themes\Colors;
use NewfoldLabs\WP\Module\Onboarding\Data\Themes\Fonts;
use NewfoldLabs\WP\Module\Patterns\SiteClassification as PatternsSiteClassification;
use NewfoldLabs\WP\Module\Data\SiteClassification\PrimaryType;
use NewfoldLabs\WP\Module\Data\SiteClassification\SecondaryType;
use NewfoldLabs\WP\Module\Onboarding\Data\Services\GlobalStylesService;
use NewfoldLabs\WP\Module\Onboarding\Data\Services\TemplatePartsService;
use NewfoldLabs\WP\Module\Onboarding\Data\Events;
use NewfoldLabs\WP\Module\Onboarding\Services\ReduxStateService;

use function NewfoldLabs\WP\ModuleLoader\container;

/**
 * Class SiteGenService
 *
 * Class for handling SiteGen Interactions.
 */
class SiteGenService {

	/**
	 * Onboarding to SiteGen identifier map.
	 *
	 * @var array
	 */
	private static $identifiers = array(
		'site_config'           => 'siteconfig',
		'site_classification'   => 'siteclassification',
		'target_audience'       => 'targetaudience',
		'content_tones'         => 'contenttones',
		'content_structure'     => 'contentstructure',
		'color_palette'         => 'colorpalette',
		'sitemap'               => 'sitemap',
		'keywords'              => 'keywords',
		'plugin_recommendation' => 'pluginrecommendation',
		'font_pair'             => 'fontpair',
	);

	/**
	 * Get SiteGen identifier from an Onboarding identifier key.
	 *
	 * @param string $identifier_key Onboarding identifier key.
	 * @return string|false
	 */
	public static function get_identifier_name( $identifier_key ) {
		return isset( self::$identifiers[ $identifier_key ] ) ? self::$identifiers[ $identifier_key ] : false;
	}

	/**
	 * Gets Valid Identifiers.
	 *
	 * @return array
	 */
	public static function enabled_identifiers() {
		return array(
			'site_config'           => true,
			'site_classification'   => true,
			'target_audience'       => true,
			'content_tones'         => true,
			'content_structure'     => true,
			'color_palette'         => true,
			'keywords'              => true,
			'sitemap'               => true,
			'plugin_recommendation' => true,
			'font_pair'             => true,
		);
	}

	/**
	 * Determines whether the given identifier is valid.
	 *
	 * @param string $key The identifier to be evaluated.
	 * @return boolean
	 */
	public static function is_identifier( $key ) {
		return isset( self::enabled_identifiers()[ $key ] );
	}

	/**
	 * Checks if the site is eligible for SiteGen Capabilities.
	 *
	 * @return boolean
	 */
	public static function is_enabled() {
		if ( ! ( class_exists( 'NewfoldLabs\WP\Module\AI\SiteGen\SiteGen' ) ) ) {
			return false;
		}
		return true;
	}


	/**
	 * Sends the data required for SiteGen Generation
	 *
	 * @param string|array $site_info The prompt that configures the Site gen object.
	 * @param string       $identifier The identifier for Generating Site Meta.
	 * @param string       $site_type The type of site.
	 * @param string       $locale The locale for the site's content.
	 * @param boolean      $skip_cache To override the cache and fetch the data.
	 * @return array|\WP_Error
	 */
	public static function instantiate_site_meta( $site_info, $identifier, $site_type, $locale, $skip_cache = false ) {
		if ( ! self::is_identifier( $identifier ) ) {
			return new \WP_Error(
				'nfd_onboarding_error',
				__( 'Not a valid identifier', 'wp-module-onboarding-data' ),
				array(
					'status' => '400',
				)
			);
		}

		// If the site info is a string, convert it to an array.
		if ( gettype( $site_info ) === 'string' ) {
			$site_info = array( 'site_description' => $site_info );
		}

		$identifier = self::get_identifier_name( $identifier );
		$response   = SiteGen::generate_site_meta( $site_info, $identifier, $site_type, $locale, $skip_cache );
		if ( isset( $response['error'] ) ) {
			// Handle the error case by returning a WP_Error.
			return new \WP_Error(
				'nfd_onboarding_error',
				__( 'Error generating site meta: ', 'wp-module-onboarding-data' ) . $identifier,
				array( 'status' => 400 )
			);
		}

		return $response;
	}

	/**
	 * Generate child them slug and name based on the generated title.
	 *
	 * @param array  $site_config The site config generated by AI.
	 * @param array  $data The homepage related data.
	 * @param string $homepage_index The index of the theme version.
	 * @return array
	 */
	public static function update_info_for_child_theme( $site_config, $data, $homepage_index = '' ) {
		// Fetch title and slug for the child theme
		$theme_name = \remove_accents( $site_config['site_title'] );
		$theme_slug = \sanitize_title_with_dashes( $theme_name );

		$homepage_slug              = $data['slug'];
		$title                      = str_replace( ' ', '-', str_replace( array( '(', ')' ), '', $data['title'] ) );
		$homepage_title_with_dashes = strtolower( str_replace( ' ', '-', $title ) );
		// if the user has not changed the name use the generated title for slug and title
		if ( 0 === strcasecmp( $homepage_slug, strtolower( $title ) ) ) {
			// if no index is passed use the slug
			if ( ! empty( $homepage_index ) ) {
				$version = explode( '-', $homepage_index );
			} else {
				$version = explode( '-', $data['slug'] );
			}
			array_shift( $version );
			$title_postfix = implode( ' ', $version );
			$slug_postfix  = implode( '-', $version );

			$data['title'] = implode( ' ', array( $theme_name, $title_postfix ) );
			$data['slug']  = implode( '-', array( $theme_slug, $slug_postfix ) );
		}
		return $data;
	}

	/**
	 * Populates the the fonts in the Theme's styles.
	 *
	 * @param object $theme_styles Theme styles json data.
	 * @param object $homepage_styles Customized Homepage styles.
	 * @return object $theme_styles Updated theme styles.
	 */
	public static function populate_fonts_in_theme_styles( $theme_styles, $homepage_styles ) {

		if ( ! empty( $homepage_styles['blocks'] ) && isset( $homepage_styles['blocks'][0] ) ) {
			$first_block = $homepage_styles['blocks'][0];

			if ( isset( $first_block['core/heading'] ) && isset( $first_block['core/heading']['typography']['fontFamily'] ) ) {
				$theme_styles['blocks']['core/heading']['typography']['fontFamily'] = $first_block['core/heading']['typography']['fontFamily'];
			}

			if ( isset( $first_block['core/body'] ) && isset( $first_block['core/body']['typography']['fontFamily'] ) ) {
				$theme_styles['typography']['fontFamily'] = $first_block['core/body']['typography']['fontFamily'];
			}
		}

		return $theme_styles;
	}

	/**
	 * Updates the global theme for the sitegen flow.
	 *
	 * @param array $data Data on homepage and it's corresponding styles.
	 * @return true|\WP_Error
	 */
	public static function update_styles_for_sitegen( $data ) {
		global $wp_filesystem;

		// Get the currently activated theme and the corresponding theme json
		$active_theme_dir       = \get_template_directory();
		$active_theme_json_file = $active_theme_dir . '/theme.json';

		// If the theme json doesn't exist, give up
		if ( ! $wp_filesystem->exists( $active_theme_json_file ) ) {
			return false;
		}

		$active_theme_json      = $wp_filesystem->get_contents( $active_theme_json_file );
		$active_theme_json_data = json_decode( $active_theme_json, true );

		// Apply the required changes to theme json
		$active_theme_json_data['settings']['color']['palette'] = $data['color']['palette'];
		$active_theme_json_data['styles']                       = self::populate_fonts_in_theme_styles( $active_theme_json_data['styles'], $data['styles'] );

		// Add the styles to global variation
		$active_global_styles_post_id = GlobalStylesService::get_active_custom_global_styles_post_id();
		GlobalStylesService::update_global_style_variation( $active_global_styles_post_id, $active_theme_json_data['styles'], $active_theme_json_data['settings'] );
		if ( ! empty( $data['header'] ) ) {
			$active_theme      = Themes::get_active_theme();
			$default_header_id = "$active_theme/header";
			// Update the default header template part with the selected content.
			$update_status = TemplatePartsService::update_template_part( $default_header_id, $data['header'] );
		}

		if ( ! empty( $data['footer'] ) ) {
			$active_theme      = Themes::get_active_theme();
			$default_footer_id = "$active_theme/footer";
			// Update the default header template part with the selected content.
			$update_status = TemplatePartsService::update_template_part( $default_footer_id, $data['footer'] );
		}
	}

	/**
	 * Generates a child theme for the sitegen flow.
	 *
	 * @param array $data Data on each homepage and it's corresponding styles.
	 * @return true|\WP_Error
	 */
	public static function generate_child_theme( $data ) {
		global $wp_filesystem;
		ThemeGeneratorService::connect_to_filesystem();
		$parent_theme_slug   = 'bluehost-blueprint';
		$parent_theme_exists = ( \wp_get_theme( $parent_theme_slug ) )->exists();
		if ( ! $parent_theme_exists ) {
			return new \WP_Error(
				'nfd_onboarding_error',
				__( 'Parent theme is missing to generate the child theme.', 'wp-module-onboarding-data' ),
				array( 'status' => 500 )
			);
		}

		/*
		Activate the parent theme if it is not active.
		This is necessary to register the parent theme's block patterns.
		 */
		$active_theme = Themes::get_active_theme();
		if ( $active_theme !== $parent_theme_slug ) {
			ThemeGeneratorService::activate_theme( $parent_theme_slug );
		}

		// Generate the necessary slugs and paths.
		$themes_dir       = dirname( \get_stylesheet_directory() );
		$parent_theme_dir = $themes_dir . '/' . $parent_theme_slug;
		$child_theme_slug = $data['slug'];
		$child_theme_dir  = $themes_dir . '/' . $child_theme_slug;

		$theme_json_file = $parent_theme_dir . '/theme.json';
		if ( ! $wp_filesystem->exists( $theme_json_file ) ) {
			return false;
		}
		$theme_json      = $wp_filesystem->get_contents( $theme_json_file );
		$theme_json_data = json_decode( $theme_json, true );

		$theme_json_data['settings']['color']['palette'] = $data['color']['palette'];
		$theme_json_data['styles']                       = self::populate_fonts_in_theme_styles( $theme_json_data['styles'], $data['styles'] );

		if ( ! $theme_json_data ) {
			return new \WP_Error(
				'nfd_onboarding_error',
				__( 'Could not generate theme.json', 'wp-module-onboarding-data' ),
				array( 'status' => 500 )
			);
		}

		$current_brand = Data::current_brand();
		$customer      = \wp_get_current_user();

		$default_site_titles_dashed = array( 'welcome', 'wordpress-site' );
		$site_title                 = \get_bloginfo( 'name' );
		$site_title_dashed          = \sanitize_title_with_dashes( $site_title );
		if ( empty( $site_title ) || in_array( $site_title_dashed, $default_site_titles_dashed, true ) ) {
			$site_title = $current_brand['brand'] . '-' . ThemeGeneratorService::get_site_url_hash();
		}

		$part_patterns = array();
		if ( ! empty( $data['header'] ) ) {
			$part_patterns['header'] = $data['header'];
		}

		if ( ! empty( $data['footer'] ) ) {
			$part_patterns['footer'] = $data['footer'];
		}

		$theme_style_data = array(
			'current_brand'     => Data::current_brand(),
			'brand'             => $current_brand['brand'],
			'brand_name'        => $current_brand['name'] ? $current_brand['name'] : 'Newfold Digital',
			'theme_name'        => $data['title'],
			'site_title'        => $site_title,
			'site_url'          => \site_url(),
			'author'            => $customer->user_firstname,
			'parent_theme_slug' => $parent_theme_slug,
			'child_theme_slug'  => $child_theme_slug,
		);

		$mustache                       = new Mustache();
		$child_theme_stylesheet_comment = $mustache->render_template( 'themeStylesheet', $theme_style_data );

		// Write the child theme to the filesystem under themes.
		$child_theme_data = array(
			'parent_theme_slug'              => $parent_theme_slug,
			'child_theme_slug'               => $child_theme_slug,
			'parent_theme_dir'               => $parent_theme_dir,
			'child_theme_dir'                => $child_theme_dir,
			'child_theme_json'               => \wp_json_encode( $theme_json_data ),
			'child_theme_stylesheet_comment' => $child_theme_stylesheet_comment,
			'part_patterns'                  => $part_patterns,
			'theme_screenshot_dir'           => realpath( __DIR__ . '/../assets/images' ),
			'theme_screenshot'               => isset( $data['screenshot'] ) ? $data['screenshot'] : false,
		);

		$child_theme_written = ThemeGeneratorService::write_child_theme( $child_theme_data );
		if ( true !== $child_theme_written ) {
			return new \WP_Error(
				'nfd_onboarding_error',
				$child_theme_written,
				array( 'status' => 500 )
			);
		}

		return true;
	}

	/**
	 * Gets the preview homepages
	 *
	 * @param string $site_description Description of the site.
	 * @param array  $content_style Description of the content style.
	 * @param array  $target_audience Description of the target audience.
	 * @param string $locale The locale for site's content.
	 * @return array|\WP_Error
	 */
	public static function generate_homepages( $site_description, $site_type, $content_style, $target_audience, $locale ) {

		$homepages = SiteGen::get_home_pages(
			$site_description,
			$site_type,
			$content_style,
			$target_audience,
			$locale,
			false
		);

		if ( isset( $homepages['error'] ) ) {
			return new \WP_Error(
				'nfd_onboarding_error',
				__( 'Error generating homepages: ', 'wp-module-onboarding-data' ),
				array( 'status' => 400 )
			);
		}

		$processed_homepages = self::process_homepages_response( $homepages );

		if ( is_wp_error( $processed_homepages ) ) {
			return $processed_homepages;
		}

		self::update_homepages( $processed_homepages );

		return $processed_homepages;
	}

	/**
	 * Regenerate previews for favourited homepages
	 *
	 * @param string $slug slug of the home page to be regenerated.
	 * @param array  $color_palette  color palatte.
	 * @return array|\WP_Error
	 */
	public static function regenerate_favorite_homepage( $slug, $color_palette ) {
		$existing_homepages = self::get_homepages();
		if ( ! isset( $existing_homepages[ $slug ] ) ) {
			return new \WP_Error(
				'nfd_onboarding_error',
				__( 'The homepage could not be found for regeneration.', 'wp-module-onboarding-data' ),
				array(
					'status' => 404,
				)
			);
		}
		$homepage = $existing_homepages[ $slug ];

		// Fetch the color palette data from the options table.
		$existing_color_palettes = self::get_color_palettes();

		if ( is_wp_error( $existing_color_palettes ) ) {
			return $existing_color_palettes;
		}

		// Decode the color palettes if it's not an array (assuming it's a JSON string).
		if ( ( is_string( $existing_color_palettes ) ) ) {
			$existing_color_palettes = json_decode( $existing_color_palettes, true );
		}

		// Select a random palette and check against the parent's palette.
		$palette_index    = array_rand( $existing_color_palettes );
		$selected_palette = self::transform_palette( $existing_color_palettes[ $palette_index ], $palette_index );

		// If regeneration is true and the selected palette matches the parent's palette, reselect.
		$palette_count = count( $existing_color_palettes );
		while ( $selected_palette === $color_palette && $palette_count > 1 ) {
			$palette_index    = array_rand( $existing_color_palettes );
			$selected_palette = self::transform_palette( $existing_color_palettes[ $palette_index ], $palette_index );
		}

		$homepage['slug']  .= '-copy';
		$homepage['title'] .= __( ' (Copy)', 'wp-module-onboarding-data' );
		$homepage['color']  = $selected_palette;

		while ( isset( $existing_homepages[ $homepage['slug'] ] ) ) {
			$homepage['slug']  .= '-copy';
			$homepage['title'] .= __( ' (Copy)', 'wp-module-onboarding-data' );
		}

		$existing_homepages[ $homepage['slug'] ] = $homepage;
		self::update_homepages( $existing_homepages );

		return $homepage;
	}

	/**
	 * Regenerate previews homepages
	 *
	 * @param string $site_description Description of the site.
	 * @param array  $content_style Description of the content style.
	 * @param array  $target_audience Description of the target audience.
	 * @param string $locale The site content's locale.
	 * @return array|\WP_Error
	 */
	public static function regenerate_homepage( $site_description, $content_style, $target_audience, $locale ) {
		$existing_homepages    = self::get_homepages();
		$regenerated_homepages = self::get_regenerated_homepages();

		if ( ! empty( $regenerated_homepages ) ) {
			$regenerated_homepage                                = array_shift( $regenerated_homepages );
			$existing_homepages[ $regenerated_homepage['slug'] ] = $regenerated_homepage;
			self::update_homepages( $existing_homepages );
			self::update_regenerated_homepages( $regenerated_homepages );
			return $regenerated_homepage;
		}

		$regenerated_homepages = SiteGen::get_home_pages( $site_description, $content_style, $target_audience, $locale, true );
		if ( isset( $homepages['error'] ) ) {
			return new \WP_Error(
				'nfd_onboarding_error',
				__( 'Error re-generating homepages: ', 'wp-module-onboarding-data' ),
				array( 'status' => 400 )
			);
		}
		$processed_regenerated_homepages                     = self::process_homepages_response( $regenerated_homepages );
		$regenerated_homepage                                = array_shift( $processed_regenerated_homepages );
		$existing_homepages[ $regenerated_homepage['slug'] ] = $regenerated_homepage;
		self::update_homepages( $existing_homepages );
		self::update_regenerated_homepages( $processed_regenerated_homepages );
		return $regenerated_homepage;
	}

	/**
	 * Processes the Homepages response structure for homepages
	 *
	 * @param array $homepages array.
	 * @return array|\WP_Error
	 */
	public static function process_homepages_response(
		$homepages
	) {
		$processed_homepages = array();
		// Fetch the color palette data from the options table.
		$color_palettes = self::get_color_palettes();

		if ( is_wp_error( $color_palettes ) ) {
			return $color_palettes;
		}
		// Retrieve the existing homepages to find the last version number.
		$existing_homepages  = self::get_homepages();
		$last_version_number = self::get_last_version_number( $existing_homepages );
		$version_number      = $last_version_number + 1;

		foreach ( $homepages as $slug => $data ) {

			// Select a random palette and check against the parent's palette.
			$palette_index    = array_rand( $color_palettes );
			$selected_palette = self::transform_palette( $color_palettes[ $palette_index ], $palette_index );

			$homepage_slug                         = 'version-' . $version_number;
			$processed_homepages[ $homepage_slug ] = array(
				'slug'            => $homepage_slug,
				'title'           => __( 'Version ', 'wp-module-onboarding-data' ) . $version_number,
				'isFavorite'      => false,
				'content'         => $data['content'],
				'header'          => $data['header'],
				'footer'          => $data['footer'],
				'color'           => $selected_palette,
				'generatedImages' => $data['generatedImages'],
			);
			++$version_number;
		}

		return $processed_homepages;
	}


	/**
	 * Get color palattes from the SiteGen meta.
	 *
	 * @return array|\WP_Error
	 */
	public static function get_color_palettes() {
		$prompt = self::get_prompt();
		$site_type = self::get_site_type();
		$locale = self::get_locale();
		if ( ! $prompt ) {
			return new \WP_Error(
				'nfd_onboarding_error',
				__( 'Prompt not found.', 'wp-module-onboarding-data' ),
				array( 'status' => 404 )
			);
		}

		$color_palette = self::instantiate_site_meta(
			array(
				'site_description' => $prompt,
			),
			'color_palette',
			$site_type,
			$locale
		);

		if ( is_wp_error( $color_palette ) ) {
			return new \WP_Error(
				'nfd_onboarding_error',
				__( 'Cannot retrieve color palatte', 'wp-module-onboarding-data' ),
				array( 'status' => 400 )
			);
		}

		$color_palettes = array();
		if ( is_int( array_rand( $color_palette ) ) ) {
			$color_palettes = $color_palette;
		} else {
			$color_palettes[] = $color_palette;
		}
		return $color_palettes;
	}

	/**
	 * Get the last version number to increment excluiding the (copy) versions
	 *
	 * @param array $homepages unstructured home pages from sitegen ai responses.
	 * @return array|int
	 */
	public static function get_last_version_number( $homepages ) {
		// Initialize to zero, assuming there are no versions yet.
		$last_version_number = 0;

		// Loop through the homepages to find the highest version number.
		foreach ( $homepages as $slug => $data ) {
			// Extract the number from the slug (assuming slug is like "version3").
			if ( preg_match( '/version-(\d+)$/', $slug ) ) {
				++$last_version_number;
			}
		}

		return $last_version_number;
	}

	/**
	 * Transform the color palatte structure for response
	 *
	 * @param array  $palette color platte chosen to transform.
	 * @param string $palette_index color palatte index.
	 * @return array
	 */
	public static function transform_palette( $palette, $palette_index ) {
		$palette_name        = 'palette-' . ( $palette_index + 1 );
		$transformed_palette = array(
			'slug'    => $palette_name,
			'palette' => array_map(
				function ( $key, $value ) {
					return array(
						'slug'  => $key,
						'name'  => ucfirst( str_replace( '_', ' ', $key ) ),
						'color' => $value,
					);
				},
				array_keys( $palette ),
				$palette
			),
		);

		return $transformed_palette;
	}

	/**
	 * Get Plugin recommendations from the SiteGen meta.
	 *
	 * @return array|\WP_Error
	 */
	public static function get_plugin_recommendations() {
		$flow_data = \get_option( Options::get_option_name( 'flow' ), false );
		if ( ! $flow_data || empty( $flow_data['sitegen']['siteDetails']['prompt'] ) ) {
			return new \WP_Error(
				'nfd_onboarding_error',
				__( 'Prompt not found.', 'wp-module-onboarding-data' ),
				array( 'status' => 404 )
			);
		}

		$prompt                 = self::get_prompt();
		$site_type              = self::get_site_type();
		$locale                 = self::get_locale();
		$plugin_recommendations = self::instantiate_site_meta(
			array(
				'site_description' => $prompt,
			),
			'plugin_recommendation',
			$site_type,
			$locale
		);

		if ( is_wp_error( $plugin_recommendations ) || isset( $plugin_recommendations['error'] ) ) {
			return new \WP_Error(
				'nfd_onboarding_error',
				__( 'Cannot retrieve plugin recommendations.', 'wp-module-onboarding-data' ),
				array( 'status' => 400 )
			);
		}

		$priority                  = 0;
		$recommended_plugins       = isset( $plugin_recommendations['recommendedPlugins'] ) ? $plugin_recommendations['recommendedPlugins'] : array();
		$final_recommended_plugins = array();
		foreach ( $recommended_plugins as $recommended_plugin ) {
			$recommended_plugin['priority'] = $priority;
			$priority                      += 20;
			$recommended_plugin['activate'] = false;
			array_push( $final_recommended_plugins, $recommended_plugin );
		}

		$required_plugins       = isset( $plugin_recommendations['requiredPlugins'] ) ? $plugin_recommendations['requiredPlugins'] : array();
		$final_required_plugins = array();
		foreach ( $required_plugins as $required_plugin ) {
			$required_plugin['priority'] = $priority;
			$priority                   += 20;
			$required_plugin['activate'] = true;
			array_push( $final_required_plugins, $required_plugin );
		}

		return array_merge( $final_required_plugins, $final_recommended_plugins );
	}

	/**
	 * Filters Wonder Blocks transients before they are set.
	 *
	 * @return void
	 */
	public static function pre_set_filter_wonder_blocks_transients() {
		$args = wp_parse_args(
			array(
				'primary_type'   => PatternsSiteClassification::get_primary_type(),
				'secondary_type' => PatternsSiteClassification::get_secondary_type(),
			)
		);
		$id   = md5( serialize( $args ) );

		\add_action( "pre_set_transient_wba_templates_{$id}", array( __CLASS__, 'filter_wonder_blocks_templates_transient' ), 10, 1 );
		\add_action( 'pre_set_transient_wba_templates_categories', array( __CLASS__, 'filter_wonder_blocks_categories_transient' ), 10, 1 );
	}

	/**
	 * Filters the Wonder Blocks templates transient.
	 *
	 * @param array $value The original value of the transient.
	 * @return array
	 */
	public static function filter_wonder_blocks_templates_transient( $value ) {
		if ( empty( $value ) || ! is_array( $value ) ) {
			return $value;
		}

		$homepages = self::get_homepages();
		if ( ! $homepages ) {
			return $value;
		}

		foreach ( $homepages as $index => $data ) {
			array_unshift(
				$value,
				array(
					'id'          => $data['slug'],
					'slug'        => $data['slug'],
					'title'       => $data['slug'],
					'description' => $data['slug'],
					'content'     => $data['content'],
					'categories'  => array( 'home', 'featured' ),
				)
			);
		}

		return $value;
	}

	/**
	 * Filters the Wonder Blocks categories transient.
	 *
	 * @param array $value The original value of the transient.
	 * @return array
	 */
	public static function filter_wonder_blocks_categories_transient( $value ) {
		if ( empty( $value ) || ! is_array( $value ) ) {
			return $value;
		}

		$homepages = self::get_homepages();
		if ( ! $homepages ) {
			return $value;
		}

		foreach ( $value as $index => $category ) {
			if ( 'home' === $category['title'] ) {
				$category['count'] = $category['count'] + count( $homepages );
				$value[ $index ]   = $category;
			}
		}

		return $value;
	}

	/**
	 * Fetches the homepages generated in the Sitegen flow.
	 *
	 * @return false|array
	 */
	public static function get_homepages() {
		$data = FlowService::read_data_from_wp_option( false );
		return isset( $data['sitegen']['homepages']['data'] ) ? $data['sitegen']['homepages']['data'] : false;
	}

	/**
	 * Get the prompt entered during the sitegen flow.
	 *
	 * @return string|false
	 */
	public static function get_prompt() {
		$data = ReduxStateService::get( 'input' );
		return ! empty( $data['prompt'] ) ? $data['prompt'] : false;
	}

	/**
	 * Get the site type entered during the sitegen flow.
	 *
	 * @return ?string - The site type or null if not set.
	 */
	public static function get_site_type(): ?string {
		$data = ReduxStateService::get( 'input' );
		if ( ! empty( $data['siteType'] ) ) {
			return $data['siteType'];
		}

		return null;
	}

	/**
	 * Get the locale entered during the sitegen flow.
	 *
	 * @return string|false
	 */
	public static function get_locale() {
		$data = ReduxStateService::get( 'input' );
		return ! empty( $data['selectedLocale'] ) ? $data['selectedLocale'] : false;
	}

	/**
	 * Update the list of sitegen generated homepages.
	 *
	 * @param array $homepages The new list of homepages.
	 * @return boolean
	 */
	public static function update_homepages( $homepages ) {
		$data = FlowService::read_data_from_wp_option( false );
		if ( ! isset( $data['sitegen']['homepages']['data'] ) ) {
			return false;
		}

		$data['sitegen']['homepages']['data'] = $homepages;
		FlowService::update_data_in_wp_option( $data );
		return true;
	}

	/**
	 * Get the list of regenerated homepages.
	 *
	 * @return array
	 */
	public static function get_regenerated_homepages() {
		return \get_option( Options::get_option_name( 'sitegen_regenerated_homepages' ), array() );
	}

	/**
	 * Update the list of sitegen regenerated homepages.
	 *
	 * @param array $regenerated_homepages The new list of regenerated homepages.
	 * @return boolean
	 */
	public static function update_regenerated_homepages( $regenerated_homepages ) {
		\update_option( Options::get_option_name( 'sitegen_regenerated_homepages' ), $regenerated_homepages );
		return true;
	}

	/**
	 * Generate and publish the sitemap pages.
	 *
	 * @param string  $site_description The description of the site (prompt).
	 * @param array   $content_style The type of content style.
	 * @param array   $target_audience The target audience meta.
	 * @param array   $sitemap The list of site pages and their keywords.
	 * @param string  $locale The site content's locale.
	 * @param boolean $update_nav_menu Whether or not the nav menu should be updated with the new pages.
	 * @return array|boolean
	 */
	public static function publish_sitemap_pages( $site_description, $site_type, $content_style, $target_audience, $sitemap, $locale, $update_nav_menu = false ) {
		$other_pages = SiteGen::get_pages(
			$site_description,
			$site_type,
			$content_style,
			$target_audience,
			$sitemap,
			$locale,
			false
		);

		$navigation_links_grammar = '';

		// TODO: Improve error handling to reliably determine if a page has been published or not instead of trying and returning true.
		foreach ( $sitemap as $index => $page ) {
			if ( ! isset( $other_pages[ $page['slug'] ] ) || isset( $other_pages[ $page['slug'] ]['error'] ) ) {
				continue;
			}

			$slug = '';
			if ( isset( $page['path'] ) ) {
				$slug_paths = explode( '/', $page['path'] );
				if ( count( $slug_paths ) > 1 ) {
					$slug = $slug_paths[1];
				}
			}
			$page_content = $other_pages[ $page['slug'] ];
			$post_id      = SitePagesService::publish_page(
				$page['title'],
				$page_content,
				true,
				array(
					'nf_dc_page' => $page['slug'],
				),
				$slug
			);
			if ( $update_nav_menu && ! is_wp_error( $post_id ) ) {
				$navigation_links_grammar .= self::get_nav_link_grammar_from_post_data( $post_id, $page['title'], get_permalink( $post_id ) );
			}
			if ( ! is_wp_error( $post_id ) && self::is_products_or_shop_page( $page['slug'] ) ) {
				self::set_woo_shop_page( $post_id );
			}
		}

		if ( $update_nav_menu ) {
			// Get the site navigation.
			$site_navigation = new \WP_Query(
				array(
					'name'      => 'navigation',
					'post_type' => 'wp_navigation',
				)
			);
			// Add sitemap pages to the navigation menu.
			if ( ! empty( $site_navigation->posts ) ) {
				wp_update_post(
					array(
						'ID'           => $site_navigation->posts[0]->ID,
						'post_content' => $navigation_links_grammar,
						'post_status'  => 'publish',
					)
				);
			} else {
				wp_insert_post(
					array(
						'post_title'   => 'Navigation',
						'post_content' => $navigation_links_grammar,
						'post_type'    => 'wp_navigation',
						'post_status'  => 'publish',
					)
				);
			}
		}

		return true;
	}

	/**
	 * Checks if it is a products or shop slug
	 *
	 * @param string $slug Slug of the page being generated.
	 * @return boolean
	 */
	public static function is_products_or_shop_page( $slug ) {
		$product_page_slug = array(
			'products' => true,
			'shop'     => true,
		);
		return array_key_exists( $slug, $product_page_slug );
	}

	/**
	 * Sets the products page generated by AI to woocommerce shop page
	 *
	 * @param integer $page_id Id of the page
	 */
	public static function set_woo_shop_page( $page_id ) {
		$option_shop_page_id                 = Options::get_option_name( 'wc_shop_page_id', false );
		$option_wc_queue_flush_rewrite_rules = Options::get_option_name( 'wc_queue_flush_rewrite_rules', false );
		update_option( $option_shop_page_id, $page_id );
		update_option( $option_wc_queue_flush_rewrite_rules, 'yes' );
	}

	/**
	 * Trash the "Sample Page" generated for all new sites.
	 *
	 * @return boolean
	 */
	public static function trash_sample_page() {
		return SitePagesService::delete_page_by_name( 'sample-page' );
	}

	/**
	 * Get the dummy navigation menu items for the Sitegen previews.
	 * Adding action hooks that trigger the AI Module generates site meta.
	 * This needs to be added before the do_action is triggered from AI Module
	 *
	 * @return void
	 */
	public static function instantiate_sitegen_hooks() {
		\add_action( 'newfold/ai/sitemeta-siteconfig:generated', array( __CLASS__, 'set_site_title_and_tagline' ), 10, 1 );
		\add_action( 'newfold/ai/sitemeta-siteclassification:generated', array( __CLASS__, 'set_site_classification' ), 10, 1 );
	}

	/**
	 * Sets the Title and Tagline for the site.
	 *
	 * @param array $site_details The Site title and site tagline.
	 * @return boolean
	 */
	public static function set_site_title_and_tagline( $site_details ) {

		// Updates the Site Title.
		if ( ( ! empty( $site_details['site_title'] ) ) ) {
			\update_option( Options::get_option_name( 'blog_name', false ), $site_details['site_title'] );
		}

		// Updates the Site Desc (Tagline).
		if ( ( ! empty( $site_details['tagline'] ) ) ) {
			\update_option( Options::get_option_name( 'blog_description', false ), $site_details['tagline'] );
		}
		return true;
	}

	/**
	 * Sets the site classification options that classify the site.
	 *
	 * @param array $site_classification The site classification site meta.
	 * @return void
	 */
	public static function set_site_classification( $site_classification ) {
		if ( isset( $site_classification['primaryType'] ) ) {
			$primary_type = new PrimaryType( 'slug', $site_classification['primaryType'] );
			$primary_type->save();
		}

		if ( isset( $site_classification['slug'] ) ) {
			$secondary_type = new SecondaryType( 'slug', $site_classification['slug'] );
			$secondary_type->save();
		}
	}

	/**
	 * Get the dummy navigation menu items for the Sitegen previews.
	 *
	 * @return array
	 */
	public static function get_dummy_navigation_menu_items() {
		$prompt    = self::get_prompt();
		$site_type = self::get_site_type();
		$locale    = self::get_locale();
		$site_info = array( 'site_description' => $prompt );
		$sitemap   = self::instantiate_site_meta( $site_info, 'sitemap', $site_type, $locale );
		if ( is_wp_error( $sitemap ) ) {
			return array();
		}

		$dummy_items = array();
		foreach ( $sitemap as $page ) {
			if ( ! isset( $page['title'] ) ) {
				continue;
			}

			array_push( $dummy_items, $page['title'] );

		}

		return $dummy_items;
	}

	/**
	 * Returns the wp:navigation-link grammar for a given post.
	 *
	 * @param integer $id The Post ID.
	 * @param string  $name The name of the post to display on the menu.
	 * @param string  $url The permalink of the post.
	 * @return string|false
	 */
	public static function get_nav_link_grammar_from_post_data( $id, $name, $url ) {
		return "<!-- wp:navigation-link {\"label\":\"$name\",\"type\":\"page\",\"id\":$id,\"url\":\"$url\",\"kind\":\"post-type\"} /-->";
	}

	/**
	 * Compresses an image based on its MIME type.
	 *
	 * This function takes raw image data and its MIME type as input, and
	 * returns the compressed image data.
	 *
	 * @param string $image_data The raw data of the image to be compressed.
	 * @param string $mime_type The MIME type of the image (e.g., 'image/jpeg', 'image/png').
	 *
	 * @return string|false Returns the compressed image data as a string if successful or false.
	 */
	public static function compress_image( $image_data, $mime_type ) {
		/*
		Steps : Create an image resource from string, check type, apply gd functions to reduce size based on quality,
		save output buffer content and return it, clean output buffer and destry created iamge.
		*/

		$image = imagecreatefromstring( $image_data );
		if ( false === $image ) {
			return $image_data;
		}

		ob_start();

		switch ( $mime_type ) {
			case 'image/jpeg':
				// 75 is the quality it is not lossless.
				imagejpeg( $image, null, 75 );
				break;
			case 'image/png':
				// it can go from 0 to 9, it is lossless.
				imagepng( $image, null, 9 );
				break;
			case 'image/gif':
				// Compress GIF.
				imagegif( $image, null );
				break;
			case 'image/webp':
				// same as jpeg.
				imagewebp( $image, null, 75 );
				break;
			default:
				ob_end_clean();
				imagedestroy( $image );
				return $image_data;
		}

		$compressed_image_data = ob_get_contents();
		ob_end_clean();
		imagedestroy( $image );

		return $compressed_image_data;
	}

	/**
	 * Uploads images to the WordPress media library as attachments.
	 *
	 * This function takes an array of image URLs, downloads them, and
	 * uploads them to the WordPress media library, returning the URLs
	 * of the newly uploaded images.
	 *
	 * @param array $image_urls An array of image URLs to upload.
	 * @return array|false An array of WordPress attachment URLs on success, false on failure.
	 * @throws Exception If there is an error during the upload process.
	 */
	public static function upload_images_to_wp_media_library( $image_urls ) {
		require_once ABSPATH . 'wp-admin/includes/media.php';
		require_once ABSPATH . 'wp-admin/includes/image.php';

		global $wp_filesystem;
		ThemeGeneratorService::connect_to_filesystem();

		$uploaded_image_urls = array();
		try {
			foreach ( $image_urls as $image_url ) {
				// Check if the URL is valid.
				if ( ! filter_var( $image_url, FILTER_VALIDATE_URL ) ) {
					continue;
				}

				// Fetch the image via remote get with timeout and a retry attempt.
				$attempt      = 0;
				$max_attempts = 2;
				while ( $attempt < $max_attempts ) {
					$response = wp_remote_get( $image_url, array( 'timeout' => 15 ) );
					if ( ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response ) ) {
						break;
					}
					++$attempt;
				}
				if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
					continue;
				}
				// Reading the headers from the image url to determine.
				$headers      = wp_remote_retrieve_headers( $response );
				$content_type = $headers['content-type'] ?? '';
				$image_data   = wp_remote_retrieve_body( $response );
				if ( empty( $content_type ) || empty( $image_data ) ) {
					continue;
				}
				// Determine the file extension based on MIME type.
				$file_extension = '';
				switch ( $content_type ) {
					case 'image/jpeg':
						$file_extension = '.jpg';
						break;
					case 'image/png':
						$file_extension = '.png';
						break;
					case 'image/gif':
						$file_extension = '.gif';
						break;
					case 'image/webp':
						$file_extension = '.webp';
						break;
				}

				if ( '' === $file_extension ) {
					continue;
				}
				// create upload directory.
				$upload_dir = wp_upload_dir();
				// xtract a filename from the URL.
				$parsed_url = wp_parse_url( $image_url );
				$path_parts = pathinfo( $parsed_url['path'] );
				// filename to be added in directory.
				$original_filename = $path_parts['filename'] . $file_extension;

				// to ensure the filename is unique within the upload directory.
				$filename = wp_unique_filename( $upload_dir['path'], $original_filename );
				$filepath = $upload_dir['path'] . '/' . $filename;
				/* Compressing the image to reduce size */
				$compressed_image_data = self::compress_image( $image_data, $content_type );

				$wp_filesystem->put_contents( $filepath, $compressed_image_data );

				// Create an attachment post for the image, metadata needed for WordPress media library.
				// guid -for url, post_title for cleaned up name, post content is empty as this is an attachment.
				// post_status inherit is for visibility.
				$attachment = array(
					'guid'           => $upload_dir['url'] . '/' . $filename,
					'post_mime_type' => $content_type,
					'post_title'     => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
					'post_content'   => '',
					'post_status'    => 'inherit',
				);
				$attach_id  = wp_insert_attachment( $attachment, $filepath );

				// Generate and assign metadata for the attachment.
				$attach_data = wp_generate_attachment_metadata( $attach_id, $filepath );
				wp_update_attachment_metadata( $attach_id, $attach_data );

				// Add the WordPress attachment URL to the list.
				if ( $attach_id ) {
					$attachment_url = wp_get_attachment_url( $attach_id );
					if ( ! $attachment_url ) {
						$attachment_url = null;
					}
					$uploaded_image_urls[ $image_url ] = $attachment_url;
				}
			}
		} catch ( \Exception $e ) {
			// Log error.
		}

		return $uploaded_image_urls;
	}

	/**
	 * Replace the uploaded images in the block grammar.
	 *
	 * This function takes a block of content and an array of new image URLs, uploads the images
	 * to the WordPress media library, and then replaces the old image URLs in the content
	 * with the new ones.
	 *
	 * @param array $content The block grammar containing the old image URLs.
	 * @param array $generated_image_urls An array of new image URLs to replace the old ones in the content.
	 */
	public static function sideload_images_and_replace_grammar( $content, $generated_image_urls ) {

		if ( ! isset( $generated_image_urls ) || ! is_array( $generated_image_urls ) ) {
			return;
		}
		// Upload the images in the 'generatedImages' array to WordPress media library.
		$url_mapping = self::upload_images_to_wp_media_library( $generated_image_urls );

		foreach ( $url_mapping as $old_url => $new_url ) {
			if ( null === $new_url ) {
				continue;
			}
			// escaping any special characters in the old URL to avoid breaking the regex.
			$escaped_old_url = preg_quote( $old_url, '/' );

			$escaped_old_url_regex_double_quote = '/"' . $escaped_old_url . '.*?"/m';
			$content                            = preg_replace( $escaped_old_url_regex_double_quote, '"' . $new_url . '"', $content );

			$escaped_old_url_regex_parenthesis = '/\(' . $escaped_old_url . '.*?\)/m';
			$content                           = preg_replace( $escaped_old_url_regex_parenthesis, '(' . $new_url . ')', $content );
		}

		// Update the content with new image URLs.
		return $content;
	}

	/**
	 * Syncs flow data with new updates.
	 *
	 * This function is responsible for updating the flow data with new home page data changes.
	 *
	 * @param array $updated_data The new data to be integrated into the existing flow data.
	 */
	public static function sync_flow_data( $updated_data ) {
		$data                                 = FlowService::read_data_from_wp_option( false );
		$data['sitegen']['homepages']['data'] = $updated_data;
		FlowService::update_data_in_wp_option( $data );
	}

	/**
	 * Reset the error status in the flow data.
	 *
	 * @param array $data The flow data.
	 * @return array
	 */
	public static function reset_error_status( $data ) {
		if ( isset( $data['sitegen']['siteGenErrorMeta']['status'] ) && true === $data['sitegen']['siteGenErrorMeta']['status'] ) {
			$data['sitegen']['siteGenErrorMeta']['status'] = false;
		}

		return $data;
	}
}
