<?php
/**
 * Settings > Priizmo AI Summary & FAQ Schema admin page.
 *
 * @package Priizmo_Engine
 */

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

/**
 * Class Priizmo_Engine_Settings
 *
 * Registers the "Settings > Priizmo AI Summary & FAQ Schema" admin page and
 * handles registration, sanitization, and rendering of all plugin options.
 */
class Priizmo_Engine_Settings {

	/**
	 * Option group used by the Settings API.
	 *
	 * @var string
	 */
	const OPTION_GROUP = 'priizmo_engine_settings_group';

	/**
	 * Settings page slug.
	 *
	 * Must exactly match the Freemius "menu" slug configured in
	 * priizmo-ai-summary-faq-schema.php ('priizmo-ai-summary-faq-schema').
	 * Freemius attaches its connect/account/pricing UI to whichever
	 * submenu page already exists at that slug; a mismatched slug here is
	 * what caused the "Sorry, you are not allowed to access this page"
	 * error on options-general.php?page=... (and ?page=..._pricing) in an
	 * earlier version of this plugin.
	 *
	 * @var string
	 */
	const PAGE_SLUG = 'priizmo-ai-summary-faq-schema';

	/**
	 * Models allowed in the "Default Model" dropdown, grouped by provider.
	 *
	 * @var array
	 */
	private static $allowed_models = array(
		'openai'    => array(
			'gpt-5.6-luna'  => 'GPT-5.6 Luna (OpenAI)',
			'gpt-5.6-terra' => 'GPT-5.6 Terra (OpenAI)',
			'gpt-5.6-sol'   => 'GPT-5.6 Sol (OpenAI)',
		),
		'anthropic' => array(
			'claude-haiku-4-5' => 'Claude Haiku 4.5 (Anthropic)',
			'claude-sonnet-5'  => 'Claude Sonnet 5 (Anthropic)',
			'claude-opus-4-8'  => 'Claude Opus 4.8 (Anthropic)',
		),
	);

	/**
	 * Placeholder used in place of a stored secret so it is never printed
	 * back into page markup. Left untouched on save, it means "keep the
	 * existing key."
	 *
	 * @var string
	 */
	const SECRET_PLACEHOLDER = '__PRIIZMO_ENGINE_UNCHANGED__';

	/**
	 * Valid values for the "Summary Display Location" dropdown.
	 *
	 * @var array
	 */
	private static $display_locations = array(
		'above_content' => 'Automatically insert above content',
		'before_h2'      => 'Automatically insert before the first H2 tag',
		'shortcode_only' => 'Manual only via shortcode',
	);

	/**
	 * Constructor. Hooks the admin page and settings registration.
	 */
	public function __construct() {
		// Priority 10 (WordPress default) is required here: Freemius hooks
		// its own `admin_menu` callback at the default priority too, and
		// needs our submenu page (same slug, see PAGE_SLUG) registered
		// in the normal registration pass to correctly attach its
		// connect/account/pricing UI to it.
		add_action( 'admin_menu', array( $this, 'register_settings_page' ), 10 );
		add_action( 'admin_init', array( $this, 'register_settings' ) );
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) );
	}

	/**
	 * Enqueues admin assets, but only on the plugin's own settings page.
	 *
	 * @param string $hook_suffix Current admin page hook suffix.
	 */
	public function enqueue_admin_assets( $hook_suffix ) {
		if ( 'settings_page_' . self::PAGE_SLUG !== $hook_suffix ) {
			return;
		}

		wp_enqueue_style(
			'priizmo-engine-admin',
			PRIIZMO_ENGINE_PLUGIN_URL . 'assets/css/admin.css',
			array(),
			PRIIZMO_ENGINE_VERSION
		);

		// WordPress core's own color picker (wp-color-picker), used for the
		// two summary-box color fields below -- reusing this built-in tool
		// instead of a free-text CSS textarea, per WP.org's guidance to
		// prefer WordPress's own tested UI components over a plugin
		// reinventing (and having to secure) its own.
		wp_enqueue_style( 'wp-color-picker' );
		wp_enqueue_script( 'wp-color-picker' );
		wp_add_inline_script(
			'wp-color-picker',
			'jQuery(function($){$(".priizmo-engine-color-picker").wpColorPicker();});'
		);
	}

	/**
	 * Default option values.
	 *
	 * @return array
	 */
	public static function get_defaults() {
		return array(
			'openai_api_key'    => '',
			'anthropic_api_key' => '',
			'default_model'     => 'gpt-5.6-terra',
			'tldr_prompt'       => "Summarize the following blog post in 2-3 concise sentences suitable for an AI search engine (e.g. ChatGPT, Perplexity) to quote directly. Focus on the key takeaway and avoid marketing language.\n\nPost content:\n{post_content}",
			'faq_prompt'        => "Based only on the following blog post, generate 4-6 frequently asked questions and concise, factual answers. Prioritize natural, high-intent questions a person might ask an AI search engine when deciding, planning, comparing options, or seeking practical guidance on this topic. Do not introduce facts, dates, products, or claims not supported by the post.\n\nRespond with ONLY a raw JSON array of objects, each with a \"question\" key and an \"answer\" key (plain text, no markdown). Do not include any explanation, commentary, or markdown code fences -- the response must start with \"[\" and end with \"]\".\n\nPost content:\n{post_content}",
			'summary_display_location' => 'shortcode_only',
			'summary_box_bg_color'      => '#f8f9fa',
			'summary_box_accent_color'  => '#2271b1',
			// Off by default in the free distribution, on by default in the
			// premium one -- see priizmo_engine_licensing_opt_in_enabled()
			// in the main plugin file for why.
			'licensing_opt_in'          => PRIIZMO_ENGINE_IS_PREMIUM_CODE,
		);
	}

	/**
	 * Looks up which provider (openai|anthropic) a given model belongs to.
	 *
	 * @param string $model Model slug, e.g. "gpt-5.6-terra".
	 *
	 * @return string|null Provider key, or null if the model is not recognized.
	 */
	public static function get_provider_for_model( $model ) {
		foreach ( self::$allowed_models as $provider => $models ) {
			if ( array_key_exists( $model, $models ) ) {
				return $provider;
			}
		}

		return null;
	}

	/**
	 * Seed default options on activation without clobbering existing values.
	 */
	public static function maybe_set_defaults() {
		$existing = get_option( PRIIZMO_ENGINE_OPTION_NAME );

		if ( false === $existing ) {
			add_option( PRIIZMO_ENGINE_OPTION_NAME, self::get_defaults() );
			return;
		}

		// Backfill any keys introduced in later versions.
		$merged = wp_parse_args( $existing, self::get_defaults() );
		update_option( PRIIZMO_ENGINE_OPTION_NAME, $merged );
	}

	/**
	 * Registers the "Priizmo AI Summary & FAQ Schema" page under the Settings menu.
	 */
	public function register_settings_page() {
		add_options_page(
			__( 'Priizmo AI Summary & FAQ Schema', 'priizmo-ai-summary-faq-schema' ),
			__( 'Priizmo AI Summary & FAQ Schema', 'priizmo-ai-summary-faq-schema' ),
			'manage_options',
			self::PAGE_SLUG,
			array( $this, 'render_settings_page' )
		);
	}

	/**
	 * Registers the option, section, and fields with the Settings API.
	 */
	public function register_settings() {
		register_setting(
			self::OPTION_GROUP,
			PRIIZMO_ENGINE_OPTION_NAME,
			array(
				'type'              => 'array',
				'sanitize_callback' => array( $this, 'sanitize_settings' ),
				'default'           => self::get_defaults(),
			)
		);

		add_settings_section(
			'priizmo_engine_privacy_section',
			__( 'Privacy & Licensing', 'priizmo-ai-summary-faq-schema' ),
			array( $this, 'render_privacy_section' ),
			self::PAGE_SLUG
		);

		add_settings_field(
			'licensing_opt_in',
			__( 'Freemius Licensing & Update Checks', 'priizmo-ai-summary-faq-schema' ),
			array( $this, 'render_licensing_opt_in_field' ),
			self::PAGE_SLUG,
			'priizmo_engine_privacy_section'
		);

		add_settings_section(
			'priizmo_engine_api_keys_section',
			__( 'API Credentials', 'priizmo-ai-summary-faq-schema' ),
			array( $this, 'render_api_keys_section' ),
			self::PAGE_SLUG
		);

		add_settings_field(
			'openai_api_key',
			__( 'OpenAI API Key', 'priizmo-ai-summary-faq-schema' ),
			array( $this, 'render_api_key_field' ),
			self::PAGE_SLUG,
			'priizmo_engine_api_keys_section',
			array( 'key' => 'openai_api_key' )
		);

		add_settings_field(
			'anthropic_api_key',
			__( 'Anthropic API Key', 'priizmo-ai-summary-faq-schema' ),
			array( $this, 'render_api_key_field' ),
			self::PAGE_SLUG,
			'priizmo_engine_api_keys_section',
			array( 'key' => 'anthropic_api_key' )
		);

		add_settings_section(
			'priizmo_engine_model_section',
			__( 'Model Selection', 'priizmo-ai-summary-faq-schema' ),
			'__return_false',
			self::PAGE_SLUG
		);

		add_settings_field(
			'default_model',
			__( 'Default Model', 'priizmo-ai-summary-faq-schema' ),
			array( $this, 'render_default_model_field' ),
			self::PAGE_SLUG,
			'priizmo_engine_model_section'
		);

		add_settings_section(
			'priizmo_engine_prompts_section',
			__( 'Prompt Templates', 'priizmo-ai-summary-faq-schema' ),
			array( $this, 'render_prompts_section' ),
			self::PAGE_SLUG
		);

		add_settings_field(
			'tldr_prompt',
			__( 'TL;DR Prompt', 'priizmo-ai-summary-faq-schema' ),
			array( $this, 'render_textarea_field' ),
			self::PAGE_SLUG,
			'priizmo_engine_prompts_section',
			array(
				'key'   => 'tldr_prompt',
				'label' => __( 'TL;DR Prompt', 'priizmo-ai-summary-faq-schema' ),
			)
		);

		add_settings_field(
			'faq_prompt',
			__( 'FAQ Prompt', 'priizmo-ai-summary-faq-schema' ),
			array( $this, 'render_textarea_field' ),
			self::PAGE_SLUG,
			'priizmo_engine_prompts_section',
			array(
				'key'   => 'faq_prompt',
				'label' => __( 'FAQ Prompt', 'priizmo-ai-summary-faq-schema' ),
			)
		);

		add_settings_section(
			'priizmo_engine_display_section',
			__( 'Summary Display & Styling', 'priizmo-ai-summary-faq-schema' ),
			array( $this, 'render_display_section' ),
			self::PAGE_SLUG
		);

		add_settings_field(
			'summary_display_location',
			__( 'Summary Display Location', 'priizmo-ai-summary-faq-schema' ),
			array( $this, 'render_display_location_field' ),
			self::PAGE_SLUG,
			'priizmo_engine_display_section'
		);

		add_settings_field(
			'summary_box_bg_color',
			__( 'Summary Box Background Color', 'priizmo-ai-summary-faq-schema' ),
			array( $this, 'render_color_field' ),
			self::PAGE_SLUG,
			'priizmo_engine_display_section',
			array(
				'key'     => 'summary_box_bg_color',
				'default' => '#f8f9fa',
			)
		);

		add_settings_field(
			'summary_box_accent_color',
			__( 'Summary Box Accent Color', 'priizmo-ai-summary-faq-schema' ),
			array( $this, 'render_color_field' ),
			self::PAGE_SLUG,
			'priizmo_engine_display_section',
			array(
				'key'     => 'summary_box_accent_color',
				'default' => '#2271b1',
			)
		);
	}

	/**
	 * Sanitizes and validates all settings before they are persisted.
	 *
	 * @param array $input Raw input from the settings form.
	 *
	 * @return array Sanitized settings to store.
	 */
	public function sanitize_settings( $input ) {
		$existing = get_option( PRIIZMO_ENGINE_OPTION_NAME, self::get_defaults() );
		$defaults = self::get_defaults();
		$output   = array();

		if ( ! is_array( $input ) ) {
			$input = array();
		}

		// API keys: never overwrite the stored secret with the masked
		// placeholder or an empty value submitted from the form.
		foreach ( array( 'openai_api_key', 'anthropic_api_key' ) as $key ) {
			$submitted = isset( $input[ $key ] ) ? trim( (string) $input[ $key ] ) : '';

			if ( '' === $submitted || self::SECRET_PLACEHOLDER === $submitted ) {
				$output[ $key ] = isset( $existing[ $key ] ) ? $existing[ $key ] : $defaults[ $key ];
			} else {
				$output[ $key ] = sanitize_text_field( $submitted );
			}
		}

		// Default model: must be one of the explicitly whitelisted models.
		$valid_models = array_merge(
			array_keys( self::$allowed_models['openai'] ),
			array_keys( self::$allowed_models['anthropic'] )
		);

		$submitted_model = isset( $input['default_model'] ) ? sanitize_text_field( $input['default_model'] ) : '';

		if ( in_array( $submitted_model, $valid_models, true ) ) {
			$output['default_model'] = $submitted_model;
		} else {
			$output['default_model'] = $defaults['default_model'];
			add_settings_error(
				PRIIZMO_ENGINE_OPTION_NAME,
				'priizmo_engine_invalid_model',
				__( 'The selected default model was invalid and has been reset to the default.', 'priizmo-ai-summary-faq-schema' )
			);
		}

		// Prompt templates: allow only plain text, no HTML/script content.
		foreach ( array( 'tldr_prompt', 'faq_prompt' ) as $key ) {
			$submitted = isset( $input[ $key ] ) ? wp_unslash( $input[ $key ] ) : '';
			$submitted = sanitize_textarea_field( $submitted );

			$output[ $key ] = ( '' !== trim( $submitted ) ) ? $submitted : $defaults[ $key ];
		}

		// Summary display location: must be a whitelisted option.
		$submitted_location = isset( $input['summary_display_location'] ) ? sanitize_text_field( $input['summary_display_location'] ) : '';

		if ( array_key_exists( $submitted_location, self::$display_locations ) ) {
			$output['summary_display_location'] = $submitted_location;
		} else {
			$output['summary_display_location'] = $defaults['summary_display_location'];
		}

		// Summary box colors: must be well-formed hex colors (WordPress
		// core's own validator); anything else falls back to the built-in
		// default rather than being stored as-is.
		foreach ( array( 'summary_box_bg_color', 'summary_box_accent_color' ) as $key ) {
			$submitted = isset( $input[ $key ] ) ? sanitize_text_field( $input[ $key ] ) : '';
			$validated = sanitize_hex_color( $submitted );

			$output[ $key ] = ! empty( $validated ) ? $validated : $defaults[ $key ];
		}

		// Licensing opt-in: a genuine boolean checkbox -- its absence from
		// the submitted form data legitimately means "unchecked", not
		// "value not provided, fall back to the default" like the fields
		// above.
		$output['licensing_opt_in'] = ! empty( $input['licensing_opt_in'] );

		return $output;
	}

	/**
	 * Renders the Privacy & Licensing section description.
	 */
	public function render_privacy_section() {
		echo '<p>' . esc_html__( 'This plugin never sends your post content or generated summaries/FAQs anywhere except the AI provider you configure below, and only when you explicitly click a "Generate" button or run Bulk Processing. The one optional exception is described here.', 'priizmo-ai-summary-faq-schema' ) . '</p>';
	}

	/**
	 * Renders the "Freemius Licensing & Update Checks" opt-in checkbox.
	 *
	 * Off by default in the free distribution: no connection to Freemius
	 * (or anyone else) is made unless this is checked. See
	 * priizmo_engine_licensing_opt_in_enabled() in the main plugin file.
	 */
	public function render_licensing_opt_in_field() {
		$checked = Priizmo_Engine::get_setting( 'licensing_opt_in', PRIIZMO_ENGINE_IS_PREMIUM_CODE );
		$field_name = PRIIZMO_ENGINE_OPTION_NAME . '[licensing_opt_in]';
		?>
		<label>
			<input
				type="checkbox"
				name="<?php echo esc_attr( $field_name ); ?>"
				value="1"
				<?php checked( $checked ); ?>
			/>
			<?php esc_html_e( 'Enable Freemius licensing & update checks (optional)', 'priizmo-ai-summary-faq-schema' ); ?>
		</label>
		<p class="description">
			<?php esc_html_e( 'Off by default. When enabled, this plugin connects to Freemius to check for plugin updates and, for Pro users, validate your license. While this stays unchecked, no connection to Freemius (or any other third party) is made at all.', 'priizmo-ai-summary-faq-schema' ); ?>
		</p>
		<?php
	}

	/**
	 * Renders the API Credentials section description.
	 */
	public function render_api_keys_section() {
		echo '<p>' . esc_html__( 'API keys are required to generate AI summaries and FAQ schema. Keys are stored in the WordPress options table and are never displayed in full once saved.', 'priizmo-ai-summary-faq-schema' ) . '</p>';
	}

	/**
	 * Renders the Prompt Templates section description.
	 */
	public function render_prompts_section() {
		echo '<p>' . wp_kses(
			__( 'Customize the prompts sent to the AI model. Use the <code>{post_content}</code> placeholder to inject the post body.', 'priizmo-ai-summary-faq-schema' ),
			array( 'code' => array() )
		) . '</p>';
	}

	/**
	 * Renders a masked password field for an API key.
	 *
	 * @param array $args Field arguments, contains 'key'.
	 */
	public function render_api_key_field( $args ) {
		$key       = $args['key'];
		$value     = Priizmo_Engine::get_setting( $key, '' );
		$field_id  = PRIIZMO_ENGINE_OPTION_NAME . '_' . $key;
		$field_name = PRIIZMO_ENGINE_OPTION_NAME . '[' . $key . ']';

		// Never render the real secret back into the page markup. Show a
		// masked placeholder instead; leaving the field untouched keeps
		// the existing key.
		$display_value = ( '' !== $value ) ? self::SECRET_PLACEHOLDER : '';
		$masked_hint    = ( '' !== $value ) ? sprintf(
			/* translators: %s: last 4 characters of the stored API key. */
			esc_html__( 'A key ending in "%s" is currently saved.', 'priizmo-ai-summary-faq-schema' ),
			esc_html( substr( $value, -4 ) )
		) : esc_html__( 'No key saved yet.', 'priizmo-ai-summary-faq-schema' );
		?>
		<input
			type="password"
			id="<?php echo esc_attr( $field_id ); ?>"
			name="<?php echo esc_attr( $field_name ); ?>"
			value="<?php echo esc_attr( $display_value ); ?>"
			class="regular-text"
			autocomplete="new-password"
			placeholder="<?php esc_attr_e( 'sk-...', 'priizmo-ai-summary-faq-schema' ); ?>"
		/>
		<p class="description"><?php echo esc_html( $masked_hint ); ?> <?php esc_html_e( 'Leave unchanged to keep the current key, or enter a new value to replace it.', 'priizmo-ai-summary-faq-schema' ); ?></p>
		<?php
	}

	/**
	 * Renders the default model dropdown, grouped by provider.
	 */
	public function render_default_model_field() {
		$current    = Priizmo_Engine::get_setting( 'default_model', 'gpt-5.6-terra' );
		$field_id   = PRIIZMO_ENGINE_OPTION_NAME . '_default_model';
		$field_name = PRIIZMO_ENGINE_OPTION_NAME . '[default_model]';
		?>
		<select id="<?php echo esc_attr( $field_id ); ?>" name="<?php echo esc_attr( $field_name ); ?>">
			<?php foreach ( self::$allowed_models as $provider => $models ) : ?>
				<optgroup label="<?php echo esc_attr( ucfirst( $provider ) ); ?>">
					<?php foreach ( $models as $model_value => $model_label ) : ?>
						<option value="<?php echo esc_attr( $model_value ); ?>" <?php selected( $current, $model_value ); ?>>
							<?php echo esc_html( $model_label ); ?>
						</option>
					<?php endforeach; ?>
				</optgroup>
			<?php endforeach; ?>
		</select>
		<p class="description"><?php esc_html_e( 'The model used by default when generating TL;DR summaries and FAQ schema.', 'priizmo-ai-summary-faq-schema' ); ?></p>
		<?php
	}

	/**
	 * Renders a textarea field for a prompt template.
	 *
	 * @param array $args Field arguments, contains 'key' and 'label'.
	 */
	public function render_textarea_field( $args ) {
		$key        = $args['key'];
		$value      = Priizmo_Engine::get_setting( $key, '' );
		$field_id   = PRIIZMO_ENGINE_OPTION_NAME . '_' . $key;
		$field_name = PRIIZMO_ENGINE_OPTION_NAME . '[' . $key . ']';
		?>
		<textarea
			id="<?php echo esc_attr( $field_id ); ?>"
			name="<?php echo esc_attr( $field_name ); ?>"
			rows="6"
			class="large-text code"
		><?php echo esc_textarea( $value ); ?></textarea>
		<?php
	}

	/**
	 * Renders the Summary Display & Styling section description.
	 */
	public function render_display_section() {
		echo '<p>' . esc_html__( 'Control where the AI-generated summary appears on the front end, and optionally override its default appearance.', 'priizmo-ai-summary-faq-schema' ) . '</p>';
	}

	/**
	 * Renders the "Summary Display Location" dropdown.
	 */
	public function render_display_location_field() {
		$current    = Priizmo_Engine::get_setting( 'summary_display_location', 'shortcode_only' );
		$field_id   = PRIIZMO_ENGINE_OPTION_NAME . '_summary_display_location';
		$field_name = PRIIZMO_ENGINE_OPTION_NAME . '[summary_display_location]';
		?>
		<select id="<?php echo esc_attr( $field_id ); ?>" name="<?php echo esc_attr( $field_name ); ?>">
			<?php foreach ( self::$display_locations as $value => $label ) : ?>
				<option value="<?php echo esc_attr( $value ); ?>" <?php selected( $current, $value ); ?>>
					<?php echo esc_html( $label ); ?>
				</option>
			<?php endforeach; ?>
		</select>
		<p class="description"><?php esc_html_e( 'Choose how the cached AI summary is placed on single post pages. The [priizmo_summary] shortcode always works regardless of this setting.', 'priizmo-ai-summary-faq-schema' ); ?></p>
		<?php
	}

	/**
	 * Renders a WordPress core color picker field for one of the summary
	 * box's two customizable colors.
	 *
	 * @param array $args Field arguments, contains 'key' and 'default'.
	 */
	public function render_color_field( $args ) {
		$key        = $args['key'];
		$value      = Priizmo_Engine::get_setting( $key, $args['default'] );
		$field_id   = PRIIZMO_ENGINE_OPTION_NAME . '_' . $key;
		$field_name = PRIIZMO_ENGINE_OPTION_NAME . '[' . $key . ']';
		?>
		<input
			type="text"
			id="<?php echo esc_attr( $field_id ); ?>"
			name="<?php echo esc_attr( $field_name ); ?>"
			value="<?php echo esc_attr( $value ); ?>"
			class="priizmo-engine-color-picker"
			data-default-color="<?php echo esc_attr( $args['default'] ); ?>"
		/>
		<?php
	}

	/**
	 * Renders the full settings page markup, including the tab navigation
	 * between "Settings" and "Bulk Processing".
	 */
	public function render_settings_page() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		$active_tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'settings'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		?>
		<div class="wrap priizmo-engine-settings">
			<h1><?php esc_html_e( 'Priizmo AI Summary & FAQ Schema', 'priizmo-ai-summary-faq-schema' ); ?></h1>
			<?php $this->render_tab_nav( $active_tab ); ?>

			<?php if ( 'bulk' === $active_tab ) : ?>
				<?php $this->render_bulk_tab(); ?>
			<?php else : ?>
				<p><?php esc_html_e( 'Configure your AI provider credentials, default model, and the prompt templates used to generate AEO summaries and FAQ schema for your posts.', 'priizmo-ai-summary-faq-schema' ); ?></p>

				<div class="priizmo-engine-howto notice notice-info inline">
					<p><strong><?php esc_html_e( 'How to generate a summary or FAQ for a post:', 'priizmo-ai-summary-faq-schema' ); ?></strong></p>
					<ol>
						<li><?php esc_html_e( 'Add your API key and pick a default model below, then save.', 'priizmo-ai-summary-faq-schema' ); ?></li>
						<li>
							<?php esc_html_e( 'Open any Post and switch to Edit mode. Look for the', 'priizmo-ai-summary-faq-schema' ); ?>
							<strong><?php esc_html_e( '"AEO Controls"', 'priizmo-ai-summary-faq-schema' ); ?></strong>
							<?php esc_html_e( 'panel: in the block editor (Gutenberg) it appears as a panel in the right-hand sidebar; if your site uses the Classic Editor instead, look for it as a box in the right-hand column.', 'priizmo-ai-summary-faq-schema' ); ?>
						</li>
						<li><?php esc_html_e( 'Click "Generate AI Summary" and/or "Generate AI FAQs" there. Both are cached automatically as soon as they\'re generated, so you only need to do this once per post (unless you want to regenerate).', 'priizmo-ai-summary-faq-schema' ); ?></li>
						<li>
							<?php esc_html_e( 'The FAQ appears automatically at the end of the post. The summary does not appear automatically by default -- either change', 'priizmo-ai-summary-faq-schema' ); ?>
							<strong><?php esc_html_e( '"Summary Display Location"', 'priizmo-ai-summary-faq-schema' ); ?></strong>
							<?php esc_html_e( 'below to place it automatically, or add the', 'priizmo-ai-summary-faq-schema' ); ?>
							<code>[priizmo_summary]</code>
							<?php esc_html_e( 'shortcode to a post manually.', 'priizmo-ai-summary-faq-schema' ); ?>
						</li>
					</ol>
					<p>
						<?php esc_html_e( 'Need to process many existing posts at once instead of one at a time? That\'s available on the', 'priizmo-ai-summary-faq-schema' ); ?>
						<strong><?php esc_html_e( 'Bulk Processing', 'priizmo-ai-summary-faq-schema' ); ?></strong>
						<?php esc_html_e( 'tab above (Pro).', 'priizmo-ai-summary-faq-schema' ); ?>
					</p>
				</div>

				<form action="options.php" method="post">
					<?php
					settings_fields( self::OPTION_GROUP );
					do_settings_sections( self::PAGE_SLUG );
					submit_button( __( 'Save Settings', 'priizmo-ai-summary-faq-schema' ) );
					?>
				</form>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * Renders the "Bulk Processing" tab: the real, functional UI for Pro
	 * users, or a plain upgrade notice otherwise (see
	 * render_bulk_tab_locked() for why that notice deliberately doesn't
	 * mock up the real feature's controls). This method always exists in
	 * both the free and premium codebases -- only Priizmo_Engine_Bulk itself
	 * (the actual Action Scheduler processing engine) is Pro-only/stripped
	 * from the free distribution.
	 */
	private function render_bulk_tab() {
		if ( class_exists( 'Priizmo_Engine_Bulk' ) && priizmo_engine_is_pro() ) {
			Priizmo_Engine_Bulk::render_admin_tab();
			return;
		}

		$this->render_bulk_tab_locked();
	}

	/**
	 * Renders the locked "Bulk Processing" tab shown to free-plan users: a
	 * plain description of the feature plus an upgrade message and a
	 * Freemius checkout link -- deliberately with no disabled form
	 * controls or other mockup of the actual feature UI. WordPress.org's
	 * Plugin Directory Guidelines treat even a visually-disabled preview
	 * of a locked feature as the same kind of "feature present but
	 * gated" issue as actually shipping it disabled, so this intentionally
	 * doesn't render the real category dropdown/start button at all (that
	 * markup only exists in Priizmo_Engine_Bulk::render_admin_tab(), which
	 * doesn't ship in the free distribution in the first place).
	 */
	private function render_bulk_tab_locked() {
		$upgrade_url = ( function_exists( 'priizmo_engine_fs' ) && is_object( priizmo_engine_fs() ) )
			? priizmo_engine_fs()->get_upgrade_url()
			: 'https://tpcrm.io/aeo-engine/pricing';
		?>
		<div class="priizmo-engine-bulk-tab priizmo-engine-bulk-tab-locked">
			<div class="notice notice-info priizmo-engine-upsell-notice">
				<p>
					<strong><?php esc_html_e( 'Bulk Processing is a Pro feature.', 'priizmo-ai-summary-faq-schema' ); ?></strong>
					<?php esc_html_e( 'The Pro version can process your entire existing post archive in the background (with a category filter and progress tracking), without risking server timeouts.', 'priizmo-ai-summary-faq-schema' ); ?>
				</p>
				<p>
					<a href="<?php echo esc_url( $upgrade_url ); ?>" class="button button-primary priizmo-engine-upgrade-cta" target="_blank" rel="noopener noreferrer">
						<?php esc_html_e( 'Learn more about Priizmo AI Summary & FAQ Schema Pro', 'priizmo-ai-summary-faq-schema' ); ?>
					</a>
				</p>
			</div>
		</div>
		<?php
	}

	/**
	 * Renders the "Settings" / "Bulk Processing" tab navigation shared by
	 * both tabs.
	 *
	 * @param string $active_tab Currently active tab slug.
	 */
	private function render_tab_nav( $active_tab ) {
		$tabs = array(
			'settings' => __( 'Settings', 'priizmo-ai-summary-faq-schema' ),
			'bulk'     => __( 'Bulk Processing', 'priizmo-ai-summary-faq-schema' ),
		);
		?>
		<h2 class="nav-tab-wrapper priizmo-engine-tab-nav">
			<?php foreach ( $tabs as $slug => $label ) : ?>
				<a
					href="<?php echo esc_url( add_query_arg( array( 'page' => self::PAGE_SLUG, 'tab' => $slug ), admin_url( 'options-general.php' ) ) ); ?>"
					class="nav-tab <?php echo ( $slug === $active_tab ) ? 'nav-tab-active' : ''; ?>"
				>
					<?php echo esc_html( $label ); ?>
				</a>
			<?php endforeach; ?>
		</h2>
		<?php
	}
}
