<?php
/**
 * Image Generator Module Class
 *
 * Main module class for image generation features.
 * Registers REST API endpoints and coordinates image generation.
 *
 * @package SmartyPress_AI_Engine
 * @since 1.0.0
 */

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

/**
 * Image Generator Module class
 */
class SmartyPress_AI_Image_Generator_Module extends SmartyPress_AI_Module_Base {

	/**
	 * Maximum time for slow image providers.
	 */
	const IMAGE_GENERATION_TIME_LIMIT = 600;

	/**
	 * Image generator instance
	 *
	 * @var SmartyPress_AI_Image_Generator|null
	 */
	private $image_generator = null;

	/**
	 * Constructor
	 *
	 * @param array $providers AI providers instances.
	 * @param array $settings Plugin settings.
	 */
	public function __construct( $providers = array(), $settings = array() ) {
		$this->module_id      = 'image_generator';
		$this->module_name    = 'Image Generator';
		$this->module_version = '1.0.0';

		parent::__construct( $providers, $settings );
	}

	/**
	 * Initialize module components
	 */
	public function init() {
		if ( ! $this->is_enabled() ) {
			return;
		}

		$this->register_settings();
		$this->register_hooks();

		add_action( 'init', array( $this, 'register_image_marker_block' ) );
		add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ) );

		// Register REST API routes.
		add_action( 'init', function () {
			add_action( 'rest_api_init', array( $this, 'register_module_rest_routes' ), 20 );
		}, 20 );

		if ( is_admin() ) {
			$this->register_admin_pages();
		}
	}

	/**
	 * Register module settings
	 */
	public function register_settings() {
		do_action( 'smartypress_ai_module_image_generator_settings', $this );
	}

	/**
	 * Get module settings
	 *
	 * @return array Module settings.
	 */
	public function get_module_settings() {
		return array(
			'enabled' => $this->is_enabled(),
		);
	}

	/**
	 * Register the public image marker block.
	 */
	public function register_image_marker_block() {
		register_block_type(
			'smartypress-ai/image-marker',
			array(
				'api_version'     => 2,
				'attributes'      => array(
					'context'      => array(
						'type'    => 'string',
						'default' => '',
					),
					'prompt'       => array(
						'type'    => 'string',
						'default' => '',
					),
					'style'        => array(
						'type'    => 'string',
						'default' => 'realistic_photo',
					),
					'status'       => array(
						'type'    => 'string',
						'default' => 'placeholder',
					),
					'attachmentId' => array(
						'type'    => 'number',
						'default' => 0,
					),
				),
				'render_callback' => array( $this, 'render_image_marker_block' ),
			)
		);
	}

	/**
	 * Enqueue image marker block editor assets.
	 */
	public function enqueue_block_editor_assets() {
		$dist_dir = SMARTYPRESS_AI_PLUGIN_DIR . 'includes/modules/image-generator/assets/dist/';
		$dist_url = SMARTYPRESS_AI_PLUGIN_URL . 'includes/modules/image-generator/assets/dist/';
		$js_file  = $dist_dir . 'image-generator.js';

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

		$asset_file = $dist_dir . 'image-generator.asset.php';
		$asset      = file_exists( $asset_file ) ? include $asset_file : array(
			'dependencies' => array( 'react', 'react-dom', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n' ),
			'version'      => SMARTYPRESS_AI_VERSION,
		);
		$version    = filemtime( $js_file ) ?: ( $asset['version'] ?? SMARTYPRESS_AI_VERSION );

		wp_enqueue_script(
			'smartypress-ai-image-generator',
			$dist_url . 'image-generator.js',
			array_merge( $asset['dependencies'] ?? array(), array( 'react', 'react-dom' ) ),
			$version,
			true
		);

		wp_set_script_translations(
			'smartypress-ai-image-generator',
			'smartypress-ai-engine',
			SMARTYPRESS_AI_PLUGIN_DIR . 'languages'
		);

		wp_localize_script(
			'smartypress-ai-image-generator',
			'smartypressAIImageGenerator',
			array(
				'restUrl'               => rest_url( 'smartypress/v1/' ),
				'nonce'                 => wp_create_nonce( 'wp_rest' ),
				'pluginUrl'             => SMARTYPRESS_AI_PLUGIN_URL . 'includes/modules/image-generator/',
				'settings'              => $this->settings,
				'imageModels'           => $this->get_image_provider_models(),
				'providerModels'        => $this->get_text_provider_models(),
				'providers'             => array_keys( SmartyPress_AI_Providers::get_available_providers() ),
				'isRuLocale'            => ( get_locale() === 'ru_RU' ),
				'locale'                => get_locale(),
				'localeDefaultLanguage' => function_exists( 'smartypress_ai_get_language_by_locale' ) ? smartypress_ai_get_language_by_locale() : get_locale(),
			)
		);

		$css_file = $dist_dir . 'image-generator.css';
		if ( file_exists( $css_file ) ) {
			wp_enqueue_style(
				'smartypress-ai-image-generator',
				$dist_url . 'image-generator.css',
				array( 'wp-components' ),
				filemtime( $css_file ) ?: $version
			);
		}
	}

	/**
	 * Render image marker block on the frontend.
	 *
	 * @param array $attributes Block attributes.
	 * @return string
	 */
	public function render_image_marker_block( $attributes ) {
		$attachment_id = absint( $attributes['attachmentId'] ?? 0 );

		if ( ! $attachment_id ) {
			return '';
		}

		$image = wp_get_attachment_image( $attachment_id, 'large' );

		if ( '' === $image ) {
			return '';
		}

		return '<figure class="wp-block-image smartypress-ai-image-marker-image">' . $image . '</figure>';
	}

	/**
	 * Register REST API routes
	 */
	protected function register_rest_routes() {
		add_action( 'rest_api_init', array( $this, 'register_module_rest_routes' ) );
	}

	/**
	 * Register module REST API routes
	 */
	public function register_module_rest_routes() {
		// Generate image.
		register_rest_route(
			'smartypress/v1',
			'/generate-image',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'generate_image_endpoint' ),
				'permission_callback' => array( $this, 'check_permissions' ),
				'args'                => array(
					'prompt'     => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_textarea_field',
					),
					'provider'   => array(
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
						'default'           => '',
					),
					'model'      => array(
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
						'default'           => 'gpt-image-1',
					),
					'resolution' => array(
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
						'default'           => '1024x1024',
					),
					'text_model'   => array(
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
						'default'           => 'gpt-4o-mini',
					),
					'text_provider' => array(
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
						'default'           => '',
					),
					'focus_keyword' => array(
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
						'default'           => '',
					),
					'post_id'       => array(
						'type'              => 'integer',
						'sanitize_callback' => 'absint',
						'default'           => 0,
					),
					'language'      => array(
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
						'default'           => '',
					),
				),
			)
		);

		// Get generated images history.
		register_rest_route(
			'smartypress/v1',
			'/generated-images',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'get_generated_images_endpoint' ),
				'permission_callback' => array( $this, 'check_permissions' ),
				'args'                => array(
					'per_page' => array(
						'type'    => 'integer',
						'default' => 100,
					),
					'page'     => array(
						'type'    => 'integer',
						'default' => 1,
					),
				),
			)
		);

		// Get available image models.
		register_rest_route(
			'smartypress/v1',
			'/image-models',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'get_image_models_endpoint' ),
				'permission_callback' => array( $this, 'check_permissions' ),
			)
		);

		// Get available image edit models.
		register_rest_route(
			'smartypress/v1',
			'/image-edit-models',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'get_image_edit_models_endpoint' ),
				'permission_callback' => array( $this, 'check_permissions' ),
			)
		);

		// Regenerate (edit) image.
		register_rest_route(
			'smartypress/v1',
			'/regenerate-image',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'regenerate_image_endpoint' ),
				'permission_callback' => array( $this, 'check_permissions' ),
				'args'                => array(
					'attachment_id' => array(
						'required'          => true,
						'type'              => 'integer',
						'sanitize_callback' => 'absint',
					),
					'prompt'        => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_textarea_field',
					),
					'provider'      => array(
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
						'default'           => '',
					),
					'model'         => array(
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
						'default'           => 'gpt-image-1',
					),
				),
			)
		);
	}

	/**
	 * Generate image endpoint
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function generate_image_endpoint( $request ) {
		$prompt         = $request->get_param( 'prompt' );
		$provider       = $request->get_param( 'provider' );
		$model          = $request->get_param( 'model' );
		$resolution     = $request->get_param( 'resolution' );
		$text_model     = $request->get_param( 'text_model' );
		$text_provider  = $request->get_param( 'text_provider' );
		$focus_keyword  = $this->sanitize_focus_keyword( $request->get_param( 'focus_keyword' ) );
		$post_id        = absint( $request->get_param( 'post_id' ) );
		$language       = $request->get_param( 'language' );

		if ( empty( $prompt ) ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Prompt is required.', 'smartypress-ai-engine' ),
				),
				400
			);
		}

		// Get provider instance.
		$provider_instance = $this->get_provider( $provider );

		if ( ! $provider_instance ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'No AI provider available. Please configure an API key in Settings.', 'smartypress-ai-engine' ),
				),
				400
			);
		}

		// Check if provider supports image generation.
		if ( ! method_exists( $provider_instance, 'generate_image' ) ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Selected provider does not support image generation.', 'smartypress-ai-engine' ),
				),
				400
			);
		}

		if ( class_exists( 'SmartyPress_AI_Logger' ) ) {
			SmartyPress_AI_Logger::log_module_event( 'image_generator', 'image_generation_request', array(
				'provider'   => $provider ?: 'default',
				'model'      => $model ?: 'gpt-image-1',
				'resolution' => $resolution ?: '1024x1024',
				'prompt'     => $prompt,
			), true );
		}

		$text_provider_instance = null;
		if ( ! empty( $text_provider ) ) {
			$text_provider_instance = $this->get_provider( $text_provider );
		}
		if ( ! $text_provider_instance ) {
			$text_provider_instance = $provider_instance;
		}

		if ( '' === $focus_keyword && $post_id && current_user_can( 'edit_post', $post_id ) ) {
			$focus_keyword = $this->get_post_focus_keyword( $post_id );
		}

		try {
			$generator = new SmartyPress_AI_Image_Generator( $provider_instance, $this->settings, $text_provider_instance );
			$result    = $generator->generate(
				$prompt,
				$model ?: 'gpt-image-1',
				$resolution ?: '1024x1024',
				$text_model ?: 'gpt-4o-mini',
				array(
					'focus_keyword' => $focus_keyword,
					'language'      => $language,
				)
			);
		} catch ( \Throwable $e ) {
			if ( class_exists( 'SmartyPress_AI_Logger' ) ) {
				SmartyPress_AI_Logger::log_module_event( 'image_generator', 'generation_exception', array(
					'error'  => $e->getMessage(),
					'prompt' => $prompt,
					'model'  => $model ?: 'gpt-image-1',
				), false );
			}

			return new \WP_REST_Response(
				array(
					'success' => false,
					'error'   => $e->getMessage(),
				),
				500
			);
		}

		$status = $result['success'] ? 200 : 500;

		return new \WP_REST_Response( $result, $status );
	}

	/**
	 * Get generated images endpoint
	 *
	 * Returns list of AI-generated images from the media library.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function get_generated_images_endpoint( $request ) {
		$per_page = absint( $request->get_param( 'per_page' ) ) ?: 100;
		$page     = absint( $request->get_param( 'page' ) ) ?: 1;

		$query = new \WP_Query(
			array(
				'post_type'      => 'attachment',
				'post_status'    => 'inherit',
				'posts_per_page' => $per_page,
				'paged'          => $page,
				'orderby'        => 'date',
				'order'          => 'DESC',
				'meta_query'     => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
					array(
						'key'     => 'smartypress_ai_generated',
						'compare' => 'EXISTS',
					),
				),
			)
		);

		$images = array();

		foreach ( $query->posts as $attachment ) {
			$attached_file    = get_attached_file( $attachment->ID );
			$filesize         = $attached_file && file_exists( $attached_file ) ? filesize( $attached_file ) : 0;
			$metadata_warning = get_post_meta( $attachment->ID, 'smartypress_ai_metadata_warning', true );
			$metadata_warning = is_array( $metadata_warning ) ? $metadata_warning : array();

			$images[] = array(
				'id'               => $attachment->ID,
				'title'            => $attachment->post_title,
				'description'      => $attachment->post_content,
				'url'              => wp_get_attachment_url( $attachment->ID ),
				'thumbnail_url'    => wp_get_attachment_image_url( $attachment->ID, 'thumbnail' ) ?: wp_get_attachment_url( $attachment->ID ),
				'filename'         => basename( $attached_file ?: '' ),
				'alt'              => get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ),
				'prompt'           => get_post_meta( $attachment->ID, 'smartypress_ai_prompt', true ),
				'model'            => get_post_meta( $attachment->ID, 'smartypress_ai_model', true ),
				'resolution'       => get_post_meta( $attachment->ID, 'smartypress_ai_resolution', true ),
				'filesize'         => $filesize,
				'date'             => $attachment->post_date,
				'metadata_warning' => $metadata_warning,
			);
		}

		return new \WP_REST_Response(
			array(
				'success' => true,
				'data'    => $images,
				'total'   => $query->found_posts,
				'pages'   => $query->max_num_pages,
			),
			200
		);
	}

	/**
	 * Regenerate image endpoint
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function regenerate_image_endpoint( $request ) {
		$attachment_id = $request->get_param( 'attachment_id' );
		$prompt        = $request->get_param( 'prompt' );
		$provider_name = $request->get_param( 'provider' );
		$model         = $request->get_param( 'model' );

		if ( empty( $prompt ) ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Correction prompt is required.', 'smartypress-ai-engine' ),
				),
				400
			);
		}

		$attachment = get_post( $attachment_id );
		if ( ! $attachment || 'attachment' !== $attachment->post_type ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Attachment not found.', 'smartypress-ai-engine' ),
				),
				404
			);
		}

		if ( ! get_post_meta( $attachment_id, 'smartypress_ai_generated', true ) ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'This is not an AI-generated image.', 'smartypress-ai-engine' ),
				),
				400
			);
		}

		if ( empty( $provider_name ) || empty( $model ) ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Please choose an image provider and model in Image Generation settings.', 'smartypress-ai-engine' ),
				),
				400
			);
		}

		$provider = $this->get_provider( $provider_name );
		if ( ! $provider ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'No image provider available. Please configure an API key in Settings.', 'smartypress-ai-engine' ),
				),
				400
			);
		}

		if ( ! method_exists( $provider, 'edit_image' ) ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Selected provider does not support image editing.', 'smartypress-ai-engine' ),
				),
				400
			);
		}

		if ( method_exists( $provider, 'get_available_image_edit_models' ) ) {
			$edit_models = $provider->get_available_image_edit_models();
			if ( empty( $edit_models[ $model ] ) ) {
				return new \WP_REST_Response(
					array(
						'success' => false,
						'error'   => __( 'Selected image model does not support image editing. Please choose a model that supports image-to-image regeneration.', 'smartypress-ai-engine' ),
					),
					400
				);
			}
		}

		if ( class_exists( 'SmartyPress_AI_Logger' ) ) {
			SmartyPress_AI_Logger::log_module_event( 'image_generator', 'regeneration_request', array(
				'provider'      => $provider_name,
				'model'         => $model,
				'attachment_id' => $attachment_id,
			), true );
		}

		$resolution = get_post_meta( $attachment_id, 'smartypress_ai_resolution', true ) ?: '1024x1024';

		try {
			$generator = new SmartyPress_AI_Image_Generator( $provider, $this->settings );
			$result    = $generator->regenerate( $attachment_id, $prompt, $model, $resolution );
		} catch ( \Throwable $e ) {
			if ( class_exists( 'SmartyPress_AI_Logger' ) ) {
				SmartyPress_AI_Logger::log_module_event( 'image_generator', 'regeneration_exception', array(
					'error'             => $e->getMessage(),
					'attachment_id'     => $attachment_id,
					'correction_prompt' => $prompt,
				), false );
			}
			return new \WP_REST_Response(
				array(
					'success' => false,
					'error'   => $e->getMessage(),
				),
				500
			);
		}

		$status = $result['success'] ? 200 : 500;
		return new \WP_REST_Response( $result, $status );
	}

	/**
	 * Get available image models endpoint
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function get_image_models_endpoint( $request ) {
		return new \WP_REST_Response(
			array(
				'success' => true,
				'data'    => $this->get_image_provider_models(),
			),
			200
		);
	}

	/**
	 * Get available image edit models endpoint
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function get_image_edit_models_endpoint( $request ) {
		return new \WP_REST_Response(
			array(
				'success' => true,
				'data'    => $this->get_image_edit_provider_models(),
			),
			200
		);
	}

	/**
	 * Get available image models for configured providers.
	 *
	 * @return array Image models grouped by provider.
	 */
	private function get_image_provider_models() {
		$providers_data = array();

		// Get all available providers.
		$available_providers = SmartyPress_AI_Providers::get_available_providers();

		foreach ( $available_providers as $provider_name => $provider ) {
			if ( method_exists( $provider, 'get_available_image_models' ) ) {
				$models = $provider->get_available_image_models();
				if ( ! empty( $models ) ) {
					$providers_data[ $provider_name ] = $models;
				}
			}
		}

		return $providers_data;
	}

	/**
	 * Get available text models for configured providers.
	 *
	 * @return array Text models grouped by provider.
	 */
	private function get_text_provider_models() {
		$providers_data     = array();
		$available_providers = SmartyPress_AI_Providers::get_available_providers();

		foreach ( $available_providers as $provider_name => $provider ) {
			if ( method_exists( $provider, 'get_available_models' ) ) {
				$models = $provider->get_available_models();
				if ( ! empty( $models ) ) {
					$providers_data[ $provider_name ] = $models;
				}
			}
		}

		return $providers_data;
	}

	/**
	 * Get available image edit models for configured providers.
	 *
	 * @return array Image edit models grouped by provider.
	 */
	private function get_image_edit_provider_models() {
		$providers_data = array();

		$available_providers = SmartyPress_AI_Providers::get_available_providers();

		foreach ( $available_providers as $provider_name => $provider ) {
			if ( method_exists( $provider, 'get_available_image_edit_models' ) ) {
				$models = $provider->get_available_image_edit_models();
				if ( ! empty( $models ) ) {
					$providers_data[ $provider_name ] = $models;
				}
			}
		}

		return $providers_data;
	}

	/**
	 * Resolve the primary focus keyword from supported SEO post meta.
	 *
	 * @param int $post_id Post ID.
	 * @return string
	 */
	private function get_post_focus_keyword( $post_id ) {
		$meta_keys = array(
			'rank_math_focus_keyword',
			'_yoast_wpseo_focuskw',
			'_aioseo_keywords',
			'_smartypress_ai_focus_keywords',
			'smartypress_ai_seo_keywords',
		);

		foreach ( $meta_keys as $meta_key ) {
			$keyword = $this->sanitize_focus_keyword( $this->get_first_keyword_from_meta( get_post_meta( $post_id, $meta_key, true ) ) );
			if ( '' !== $keyword ) {
				return $keyword;
			}
		}

		return '';
	}

	/**
	 * Extract the first keyword from scalar or array meta value.
	 *
	 * @param mixed $value Meta value.
	 * @return string
	 */
	private function get_first_keyword_from_meta( $value ) {
		if ( is_array( $value ) ) {
			foreach ( $value as $item ) {
				$keyword = $this->get_first_keyword_from_meta( $item );
				if ( '' !== $keyword ) {
					return $keyword;
				}
			}

			return '';
		}

		if ( ! is_scalar( $value ) ) {
			return '';
		}

		$keywords = preg_split( '/\r\n|\r|\n|,/', (string) $value );
		$keyword  = sanitize_text_field( trim( (string) ( $keywords[0] ?? '' ) ) );

		return preg_replace( '/\s+/u', ' ', $keyword );
	}

	/**
	 * Sanitize and validate focus keyword values from editor meta or DOM.
	 *
	 * @param mixed $keyword Raw keyword.
	 * @return string
	 */
	private function sanitize_focus_keyword( $keyword ) {
		if ( ! is_scalar( $keyword ) ) {
			return '';
		}

		$keyword = preg_replace( '/\s+/u', ' ', sanitize_text_field( trim( (string) $keyword ) ) );
		$invalid = array(
			'0',
			'1',
			'on',
			'off',
			'yes',
			'no',
			'true',
			'false',
			'enabled',
			'disabled',
			'checked',
			'unchecked',
			'null',
			'none',
		);

		if ( '' === $keyword || mb_strlen( $keyword, 'UTF-8' ) < 3 || in_array( strtolower( $keyword ), $invalid, true ) ) {
			return '';
		}

		return $keyword;
	}

	/**
	 * Register admin pages
	 */
	protected function register_admin_pages() {
		// Admin pages are handled by the main admin app with React Router.
	}

	/**
	 * Check REST API permissions
	 *
	 * @return bool
	 */
	public function check_permissions() {
		return current_user_can( 'edit_posts' );
	}
}
