<?php
/**
 * Dashboard Tab - Command Center for Trial and Paid Users
 *
 * The dashboard serves as the primary proof of execution where users see
 * ClearPost running their content engine. It displays metrics, upcoming posts,
 * and status based on the user's scenario.
 *
 * @package Simple_AI_Auto_Post
 * @since 2.5.0
 */

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

/**
 * Get count of posts generated by ClearPost.
 *
 * @param string|null $since Optional. Only count posts generated after this date.
 *                           Should be in MySQL datetime format (Y-m-d H:i:s).
 * @return int Number of posts generated.
 */
function saiap_get_generated_posts_count( $since = null ) {
	$args = array(
		'post_type'      => 'post',
		'post_status'    => array( 'publish', 'draft', 'future' ),
		'meta_key'       => '_saiap_generated',
		'meta_value'     => '1',
		'posts_per_page' => -1,
		'fields'         => 'ids',
	);

	if ( $since ) {
		$args['meta_query'] = array(
			'relation' => 'AND',
			array(
				'key'   => '_saiap_generated',
				'value' => '1',
			),
			array(
				'key'     => '_saiap_generated_at',
				'value'   => $since,
				'compare' => '>=',
				'type'    => 'DATETIME',
			),
		);
		// Remove the simple meta_key/meta_value since we're using meta_query.
		unset( $args['meta_key'] );
		unset( $args['meta_value'] );
	}

	$posts = get_posts( $args );
	return count( $posts );
}

/**
 * Get count of posts generated during the current/recent trial period.
 *
 * @return int Number of posts generated during trial.
 */
function saiap_get_trial_generated_posts_count() {
	$trial_started = get_option( 'saiap_trial_started_at', '' );
	if ( empty( $trial_started ) ) {
		return 0;
	}

	return saiap_get_generated_posts_count( $trial_started );
}

/**
 * Get upcoming scheduled posts.
 *
 * @param int $limit Maximum number of posts to return.
 * @return array Array of post objects with ID, title, and scheduled date.
 */
function saiap_get_upcoming_scheduled_posts( $limit = 5 ) {
	$posts = get_posts(
		array(
			'post_type'      => 'post',
			'post_status'    => 'future',
			'posts_per_page' => $limit,
			'orderby'        => 'date',
			'order'          => 'ASC',
		)
	);

	$result = array();
	foreach ( $posts as $post ) {
		$result[] = array(
			'id'           => $post->ID,
			'title'        => $post->post_title,
			'scheduled_at' => $post->post_date,
			'edit_url'     => get_edit_post_link( $post->ID, 'raw' ),
		);
	}

	return $result;
}

/**
 * Get the dashboard content variant based on user scenario.
 *
 * @return string One of: 'trial_active', 'trial_expired', 'paid', 'locked'
 */
function saiap_get_dashboard_content_variant() {
	$scenario = saiap_get_user_scenario();

	switch ( $scenario ) {
		case 'active_trial':
			return 'trial_active';
		case 'expired_trial':
			return 'trial_expired';
		case 'paid':
			return 'paid';
		case 'no_trial_no_keys':
		case 'no_trial_has_keys':
		default:
			// Show locked state with trial CTA overlay.
			return 'locked';
	}
}

/**
 * Render the dashboard status indicator.
 *
 * @param string $variant The dashboard content variant.
 */
/**
 * Check if automated setup is currently in progress.
 *
 * Setup is considered "in progress" if it was triggered within the last 15 minutes.
 *
 * @return bool True if setup is in progress, false otherwise.
 */
function saiap_is_setup_in_progress() {
	$setup_triggered_at = get_option( 'saiap_setup_triggered_at', 0 );
	if ( ! $setup_triggered_at ) {
		return false;
	}
	// Once the first post has been delivered we consider setup done, regardless
	// of whether the JS-side clearSetupFlag AJAX ever landed. Without this guard
	// the dashboard re-entered the polling loop on every page load and
	// openFirstPostModal popped the calendar modal each visit.
	if ( get_option( 'saiap_first_post_created', 0 ) ) {
		return false;
	}
	$time_elapsed = time() - (int) $setup_triggered_at;
	return $time_elapsed < ( 15 * MINUTE_IN_SECONDS );
}

/**
 * Check if calendar items exist for the current site.
 *
 * Makes an inline API call to check if calendar items exist (today to +7 days).
 * Returns false on any error to gracefully handle API failures.
 *
 * @return bool True if calendar items exist, false otherwise.
 */
function saiap_calendar_items_exist() {
	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$start_date = gmdate( 'Y-m-d' );
	$end_date   = gmdate( 'Y-m-d', strtotime( '+7 days' ) );

	$response = wp_remote_get(
		SAIAP_PREMIUM_API_URL . '/api/seo/calendar?' . http_build_query(
			array(
				'domain'      => $domain,
				'license_key' => $license_key,
				'start_date'  => $start_date,
				'end_date'    => $end_date,
			)
		),
		array(
			'timeout' => 10, // Shorter timeout for status check
			'headers' => array(
				'Content-Type' => 'application/json',
			),
		)
	);

	if ( is_wp_error( $response ) ) {
		return false;
	}

	$body = json_decode( wp_remote_retrieve_body( $response ), true );
	$code = wp_remote_retrieve_response_code( $response );

	if ( 200 !== $code ) {
		return false;
	}

	// Check if items array exists and is non-empty
	if ( ! isset( $body['items'] ) || ! is_array( $body['items'] ) ) {
		return false;
	}

	return count( $body['items'] ) > 0;
}

/**
 * Get the cached calendar items count.
 *
 * Returns the count from transient cache, or 0 if not cached.
 * The cache is populated when calendar items are fetched via AJAX.
 *
 * @return int The number of calendar items, or 0 if not cached.
 */
function saiap_get_calendar_items_count() {
	$count = get_transient( 'saiap_calendar_items_count' );
	return false !== $count ? (int) $count : 0;
}

/**
 * Get the cached count of planned/scheduled calendar items.
 *
 * Returns the count of calendar items in 'planned' status (not yet generated).
 * The cache is populated when calendar items are fetched via AJAX.
 *
 * @return int The number of planned calendar items, or 0 if not cached.
 */
function saiap_get_planned_calendar_items_count() {
	$count = get_transient( 'saiap_planned_calendar_items_count' );
	return false !== $count ? (int) $count : 0;
}

/**
 * Render the dashboard status indicator.
 *
 * For trial_active and paid variants, shows a three-step onboarding status.
 * For other variants, shows simple status text.
 *
 * @param string $variant The dashboard content variant.
 */
function saiap_render_dashboard_status( $variant ) {
	// For trial_active and paid, show three-step onboarding status
	if ( in_array( $variant, array( 'trial_active', 'paid' ), true ) ) {
		saiap_render_dashboard_status_steps( $variant );
		return;
	}

	// For other variants, show simple status
	$status_class = 'paused';
	$status_text  = __( 'ClearPost is paused', 'clearpost-simple-ai-auto-post' );
	$status_icon  = 'dashicons-controls-pause';

	if ( 'locked' === $variant ) {
		// Fresh users who haven't started anything yet - don't say "paused"
		$status_class = 'ready';
		$status_text  = __( 'Ready to start', 'clearpost-simple-ai-auto-post' );
		$status_icon  = 'dashicons-flag';
	}
	// trial_expired keeps the default "paused" status

	?>
	<div class="saiap-dashboard-status saiap-dashboard-status--<?php echo esc_attr( $status_class ); ?>">
		<span class="dashicons <?php echo esc_attr( $status_icon ); ?>"></span>
		<span class="saiap-dashboard-status__text"><?php echo esc_html( $status_text ); ?></span>
	</div>
	<?php
}

/**
 * Render the three-step onboarding status display.
 *
 * Shows the status of three key onboarding steps:
 * 1. Analyzing your site
 * 2. Creating SEO strategy
 * 3. Managing content calendar
 *
 * @param string $variant The dashboard content variant (trial_active or paid).
 */
function saiap_render_dashboard_status_steps( $variant ) {
	$is_setup_in_progress = saiap_is_setup_in_progress();

	// Step 1: Analyzing your site
	$step1_complete = saiap_trial_onboarding_step_complete( 'site_analyzed' );
	$step1_state    = $step1_complete ? 'complete' : ( $is_setup_in_progress ? 'in-progress' : 'pending' );

	// Step 2: Creating SEO strategy
	$step2_complete = saiap_trial_onboarding_step_complete( 'strategy_created' );
	if ( $step2_complete ) {
		$step2_state = 'complete';
	} elseif ( $step1_complete ) {
		// Step 2 can only be in-progress or pending if step 1 is complete
		$step2_state = $is_setup_in_progress ? 'in-progress' : 'pending';
	} else {
		// Step 1 not complete yet, so step 2 is pending
		$step2_state = 'pending';
	}

	// Step 3: Managing content calendar
	$step3_complete = saiap_calendar_items_exist();
	if ( $step3_complete ) {
		$step3_state = 'complete';
	} elseif ( $step2_complete ) {
		// Step 3 can only be in-progress or pending if step 2 is complete
		$step3_state = $is_setup_in_progress ? 'in-progress' : 'pending';
	} else {
		// Step 2 not complete yet, so step 3 is pending
		$step3_state = 'pending';
	}

	?>
	<div class="saiap-dashboard-status saiap-dashboard-status--running">
		<div class="saiap-dashboard-status-steps">
			<?php
			// Step 1: Analyzing your site
			saiap_render_dashboard_status_step(
				'analyzing',
				__( 'Analyzing your site', 'clearpost-simple-ai-auto-post' ),
				$step1_state,
				$step1_complete
			);

			// Step 2: Creating SEO strategy
			saiap_render_dashboard_status_step(
				'strategy',
				__( 'Creating SEO strategy', 'clearpost-simple-ai-auto-post' ),
				$step2_state,
				$step2_complete
			);

			// Step 3: Managing content calendar
			saiap_render_dashboard_status_step(
				'calendar',
				__( 'Managing content calendar', 'clearpost-simple-ai-auto-post' ),
				$step3_state,
				$step3_complete
			);
			?>
		</div>
	</div>
	<?php
}

/**
 * Render a single status step.
 *
 * @param string $key Step identifier key.
 * @param string $label Step label text.
 * @param string $state Step state: 'complete', 'in-progress', or 'pending'.
 * @param bool   $is_complete Whether the step is complete (for label past tense).
 */
function saiap_render_dashboard_status_step( $key, $label, $state, $is_complete ) {
	$step_class = 'saiap-dashboard-status-step saiap-dashboard-status-step--' . esc_attr( $state );

	// Map step keys to numbers.
	$step_numbers = array(
		'analyzing' => 1,
		'strategy'  => 2,
		'calendar'  => 3,
	);
	$step_number  = isset( $step_numbers[ $key ] ) ? $step_numbers[ $key ] : 1;

	// Change label to past tense when complete.
	if ( 'complete' === $state ) {
		if ( 'analyzing' === $key ) {
			$label = __( 'Site analyzed', 'clearpost-simple-ai-auto-post' );
		} elseif ( 'strategy' === $key ) {
			$label = __( 'SEO strategy created', 'clearpost-simple-ai-auto-post' );
		}
	}

	?>
	<div class="<?php echo esc_attr( $step_class ); ?>">
		<div class="saiap-dashboard-status-step__icon">
			<?php if ( 'complete' === $state ) : ?>
				<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
					<path d="M13.3 4.3L6 11.6L2.7 8.3L3.4 7.6L6 10.2L12.6 3.6L13.3 4.3Z" fill="currentColor"/>
				</svg>
			<?php elseif ( 'in-progress' === $state ) : ?>
				<div class="saiap-dashboard-status-step__spinner"></div>
			<?php else : ?>
				<span class="saiap-dashboard-status-step__number"><?php echo esc_html( $step_number ); ?></span>
			<?php endif; ?>
		</div>
		<span class="saiap-dashboard-status-step__label"><?php echo esc_html( $label ); ?></span>
	</div>
	<?php
}


/**
 * Render the top row with metrics and autopilot settings.
 *
 * @param string $variant The dashboard content variant.
 */
function saiap_render_dashboard_top_row( $variant ) {
	$total_generated = saiap_get_generated_posts_count();
	$scheduled_count = saiap_get_planned_calendar_items_count();
	$is_active       = in_array( $variant, array( 'trial_active', 'paid' ), true );

	// For trial, also show trial-specific count.
	$trial_generated = 0;
	if ( 'trial_active' === $variant || 'trial_expired' === $variant ) {
		$trial_generated = saiap_get_trial_generated_posts_count();
	}

	?>
	<div class="saiap-dashboard-top-row">
		<!-- Metrics -->
		<div class="saiap-metric-card">
			<div class="saiap-metric-card__value"><?php echo esc_html( number_format_i18n( $total_generated ) ); ?></div>
			<div class="saiap-metric-card__label"><?php echo esc_html( _n( 'Post Generated', 'Posts Generated', $total_generated, 'clearpost-simple-ai-auto-post' ) ); ?></div>
		</div>

		<div class="saiap-metric-card">
			<div class="saiap-metric-card__value"><?php echo esc_html( number_format_i18n( $scheduled_count ) ); ?></div>
			<div class="saiap-metric-card__label"><?php echo esc_html( _n( 'Post Scheduled', 'Posts Scheduled', $scheduled_count, 'clearpost-simple-ai-auto-post' ) ); ?></div>
		</div>

		<!-- Toggleable Panel: GSC Chart / Autopilot Settings -->
		<?php
		$license_key     = get_option( 'saiap_license_key', '' );
		$has_license     = ! empty( $license_key );
		$domain          = saiap_get_server_host();
		$premium_api_url = str_replace( 'host.docker.internal', 'localhost', SAIAP_PREMIUM_API_URL );
		$gsc_nonce       = wp_create_nonce( 'saiap_gsc_nonce' );
		$gsc_status_url  = admin_url( 'admin-ajax.php?action=saiap_gsc_status&_wpnonce=' . $gsc_nonce );
		$gsc_chart_url   = admin_url( 'admin-ajax.php?action=saiap_gsc_chart&_wpnonce=' . $gsc_nonce );
		$gsc_connect_url = $premium_api_url . '/api/gsc/oauth/start?' . http_build_query(
			array(
				'domain'     => $domain,
				'return_url' => admin_url( 'admin.php?page=saiap&tab=dashboard' ),
			)
		);
		?>
		<div class="saiap-panel-toggle" data-gsc-status-url="<?php echo esc_attr( $gsc_status_url ); ?>" data-gsc-chart-url="<?php echo esc_attr( $gsc_chart_url ); ?>" data-gsc-connect-url="<?php echo esc_attr( $gsc_connect_url ); ?>" data-has-license="<?php echo $has_license ? '1' : '0'; ?>">
			<!-- Toggle icons (top-right corner) -->
			<div class="saiap-panel-toggle__icons">
				<button type="button" class="saiap-panel-toggle__icon saiap-panel-toggle__icon--active" data-panel="chart" title="<?php esc_attr_e( 'Search Performance', 'clearpost-simple-ai-auto-post' ); ?>">
					<span class="dashicons dashicons-chart-area"></span>
				</button>
				<button type="button" class="saiap-panel-toggle__icon" data-panel="settings" title="<?php esc_attr_e( 'Settings', 'clearpost-simple-ai-auto-post' ); ?>">
					<span class="dashicons dashicons-admin-generic"></span>
				</button>
			</div>

			<!-- Panel: GSC Chart -->
			<div class="saiap-panel-toggle__content saiap-panel-toggle__content--active" data-panel="chart">
				<div id="saiap-gsc-chart-area">
					<div id="saiap-gsc-chart-loading" style="display: flex; align-items: center; justify-content: center; height: 100%; color: var(--saiap-text-muted, #888);">
						<span class="spinner is-active" style="float: none; margin: 0 8px 0 0;"></span>
						<?php esc_html_e( 'Loading...', 'clearpost-simple-ai-auto-post' ); ?>
					</div>
					<div id="saiap-gsc-chart-root" style="display: none; width: 100%; height: 100%;"></div>
					<p id="saiap-gsc-chart-tagline" class="saiap-gsc-chart-tagline" style="display: none;"><?php esc_html_e( 'ClearPost AI uses real search performance data to improve its results over time.', 'clearpost-simple-ai-auto-post' ); ?></p>
					<div id="saiap-gsc-chart-cta" style="display: none;">
						<div class="saiap-gsc-cta">
							<span class="dashicons dashicons-chart-area saiap-gsc-cta__icon"></span>
							<div class="saiap-gsc-cta__text">
								<strong><?php esc_html_e( 'See your search performance', 'clearpost-simple-ai-auto-post' ); ?></strong>
								<span><?php esc_html_e( 'Connect Google Search Console to track clicks, impressions, and rankings.', 'clearpost-simple-ai-auto-post' ); ?></span>
							</div>
							<a href="<?php echo esc_url( $gsc_connect_url ); ?>" class="button button-primary button-small" style="text-decoration: none; white-space: nowrap;">
								<?php esc_html_e( 'Connect GSC', 'clearpost-simple-ai-auto-post' ); ?>
							</a>
						</div>
					</div>
					<div id="saiap-gsc-chart-empty" style="display: none;">
						<div class="saiap-gsc-cta">
							<span class="dashicons dashicons-chart-area saiap-gsc-cta__icon"></span>
							<span><?php esc_html_e( 'No search data yet. Data usually appears 2-3 days after connecting.', 'clearpost-simple-ai-auto-post' ); ?></span>
						</div>
					</div>
				</div>
			</div>

			<!-- Panel: Autopilot Settings -->
			<div class="saiap-panel-toggle__content" data-panel="settings" style="display: none;">
				<div class="saiap-autopilot-inline <?php echo ! $is_active ? 'saiap-autopilot-inline--disabled' : ''; ?>">
					<div class="saiap-autopilot-inline__control">
						<label for="saiap-autopilot-enabled" class="saiap-toggle-label">
							<input type="checkbox" id="saiap-autopilot-enabled"
									<?php disabled( ! $is_active ); ?>
									<?php checked( get_option( 'saiap_autopilot_enabled', true ) ); ?>>
							<span class="saiap-toggle-text"><?php esc_html_e( 'Autopilot', 'clearpost-simple-ai-auto-post' ); ?></span>
						</label>
					</div>

					<div class="saiap-autopilot-inline__control">
						<label for="saiap-posts-per-week" class="saiap-select-label">
							<?php esc_html_e( 'Posts/week', 'clearpost-simple-ai-auto-post' ); ?>
						</label>
						<?php
						$plan_cap     = absint( get_option( 'saiap_plan_cadence_cap', 0 ) );
						$dropdown_max = $plan_cap > 0 ? $plan_cap : 14;
						?>
						<select id="saiap-posts-per-week" <?php disabled( ! $is_active ); ?>>
							<?php for ( $i = 1; $i <= $dropdown_max; $i++ ) : ?>
								<option value="<?php echo esc_attr( $i ); ?>"
									<?php selected( get_option( 'saiap_posts_per_week', 7 ), $i ); ?>>
									<?php echo esc_html( $i ); ?>
								</option>
							<?php endfor; ?>
						</select>
						<?php if ( $plan_cap > 0 ) : ?>
							<a href="<?php echo esc_url( saiap_get_checkout_url() ); ?>" target="_blank" class="saiap-plan-upgrade-hint">
								<?php
								printf(
									/* translators: %d: maximum posts per week for the current plan */
									esc_html__( 'Your plan includes up to %d posts/week. Upgrade for more.', 'clearpost-simple-ai-auto-post' ),
									$plan_cap
								);
								?>
							</a>
						<?php endif; ?>
					</div>

					<div class="saiap-autopilot-inline__control">
						<label for="saiap-review-before-publish" class="saiap-toggle-label">
							<input type="checkbox" id="saiap-review-before-publish"
									<?php disabled( ! $is_active ); ?>
									<?php checked( get_option( 'saiap_review_before_publish', false ) ); ?>>
							<span class="saiap-toggle-text"><?php esc_html_e( 'Review first', 'clearpost-simple-ai-auto-post' ); ?></span>
						</label>
					</div>

					<?php
					$models           = saiap_get_ai_models();
					$current_provider = get_option( 'saiap_default_provider', 'anthropic' );
					$current_model    = get_option( "saiap_{$current_provider}_model", 'claude-opus-4-5' );
					?>
					<div class="saiap-autopilot-inline__control">
						<label for="saiap-model-select" class="saiap-select-label">
							<?php esc_html_e( 'Model', 'clearpost-simple-ai-auto-post' ); ?>
						</label>
						<select id="saiap-model-select" <?php disabled( ! $is_active ); ?>>
							<?php foreach ( $models as $provider => $provider_models ) : ?>
								<optgroup label="<?php echo esc_attr( ucfirst( $provider ) ); ?>">
									<?php foreach ( $provider_models as $model_id => $model_name ) : ?>
										<option value="<?php echo esc_attr( $provider . ':' . $model_id ); ?>"
											<?php selected( $current_provider . ':' . $current_model, $provider . ':' . $model_id ); ?>>
											<?php echo esc_html( $model_name ); ?>
										</option>
									<?php endforeach; ?>
								</optgroup>
							<?php endforeach; ?>
						</select>
					</div>

					<?php if ( $is_active ) : ?>
						<button type="button" class="button button-primary button-small saiap-save-autopilot-settings">
							<?php esc_html_e( 'Save', 'clearpost-simple-ai-auto-post' ); ?>
						</button>
					<?php endif; ?>
				</div>
			</div>
		</div>
	</div>
	<?php
}

/**
 * Render the metrics cards (legacy, kept for backward compatibility).
 *
 * @param string $variant The dashboard content variant.
 */
function saiap_render_dashboard_metrics( $variant ) {
	// Now handled by saiap_render_dashboard_top_row().
	// This function is kept for backward compatibility but does nothing.
}

/**
 * Render the upcoming posts list.
 *
 * @param int $limit Maximum posts to show.
 */
function saiap_render_upcoming_posts( $limit = 5 ) {
	$posts = saiap_get_upcoming_scheduled_posts( $limit );

	if ( empty( $posts ) ) {
		?>
		<div class="saiap-upcoming-posts saiap-upcoming-posts--empty">
			<p><?php esc_html_e( 'No posts scheduled yet.', 'clearpost-simple-ai-auto-post' ); ?></p>
		</div>
		<?php
		return;
	}

	?>
	<div class="saiap-upcoming-posts">
		<h3><?php esc_html_e( 'Upcoming Posts', 'clearpost-simple-ai-auto-post' ); ?></h3>
		<ul class="saiap-upcoming-posts__list">
			<?php foreach ( $posts as $post ) : ?>
				<li class="saiap-upcoming-posts__item">
					<span class="saiap-upcoming-posts__title">
						<?php echo esc_html( $post['title'] ); ?>
					</span>
					<span class="saiap-upcoming-posts__date">
						<?php echo esc_html( date_i18n( get_option( 'date_format' ), strtotime( $post['scheduled_at'] ) ) ); ?>
					</span>
					<a href="<?php echo esc_url( $post['edit_url'] ); ?>" class="saiap-upcoming-posts__edit">
						<?php esc_html_e( 'Edit', 'clearpost-simple-ai-auto-post' ); ?>
					</a>
				</li>
			<?php endforeach; ?>
		</ul>
	</div>
	<?php
}

/**
 * Render the trial welcome hero for locked state.
 *
 * Shows different content based on whether user has API keys configured:
 * - no_trial_no_keys: Full trial CTA
 * - no_trial_has_keys: Acknowledges their setup, trial is primary, Generate tab link as secondary
 */
function saiap_render_dashboard_trial_cta() {
	$scenario    = saiap_get_user_scenario();
	$has_api_keys = ( 'no_trial_has_keys' === $scenario );
	?>
	<div class="saiap-trial-welcome-hero <?php echo $has_api_keys ? 'saiap-trial-welcome-hero--has-keys' : ''; ?>">
		<div class="saiap-trial-welcome-hero__content">
			<div class="saiap-trial-welcome-hero__text">
				<?php if ( $has_api_keys ) : ?>
					<h1 class="saiap-trial-welcome-hero__headline">
						<?php esc_html_e( 'Unlock Automated SEO Publishing', 'clearpost-simple-ai-auto-post' ); ?>
					</h1>
					<p class="saiap-trial-welcome-hero__subhead">
						<?php esc_html_e( 'Your API keys are configured for manual generation. Start a free trial to unlock automated SEO research, content calendars, and autopilot publishing.', 'clearpost-simple-ai-auto-post' ); ?>
					</p>

					<div class="saiap-trial-welcome-hero__actions">
						<button type="button" class="button button-primary button-hero saiap-start-trial-btn">
							<?php esc_html_e( 'Start 7-Day Free Trial', 'clearpost-simple-ai-auto-post' ); ?>
						</button>
						<a href="<?php echo esc_url( admin_url( 'admin.php?page=saiap&tab=generate' ) ); ?>" class="saiap-trial-welcome-hero__secondary-link">
							<?php esc_html_e( 'Or start creating content now →', 'clearpost-simple-ai-auto-post' ); ?>
						</a>
					</div>

					<p class="saiap-trial-welcome-hero__footnote">
						<?php esc_html_e( 'No credit card required. Cancel anytime.', 'clearpost-simple-ai-auto-post' ); ?>
					</p>
				<?php else : ?>
					<h1 class="saiap-trial-welcome-hero__headline">
						<?php esc_html_e( 'Organic Traffic on Autopilot', 'clearpost-simple-ai-auto-post' ); ?>
					</h1>
					<p class="saiap-trial-welcome-hero__subhead">
						<?php esc_html_e( 'ClearPost researches what your audience is searching for, writes SEO content, and publishes it — every day, without you lifting a finger.', 'clearpost-simple-ai-auto-post' ); ?>
					</p>

					<div class="saiap-trial-welcome-hero__features">
						<div class="saiap-trial-welcome-hero__feature">
							<span class="dashicons dashicons-chart-line"></span>
							<span><?php esc_html_e( 'Keywords picked for your niche', 'clearpost-simple-ai-auto-post' ); ?></span>
						</div>
						<div class="saiap-trial-welcome-hero__feature">
							<span class="dashicons dashicons-calendar-alt"></span>
							<span><?php esc_html_e( '30 posts planned and scheduled', 'clearpost-simple-ai-auto-post' ); ?></span>
						</div>
						<div class="saiap-trial-welcome-hero__feature">
							<span class="dashicons dashicons-superhero-alt"></span>
							<span><?php esc_html_e( 'Written and published automatically', 'clearpost-simple-ai-auto-post' ); ?></span>
						</div>
						<div class="saiap-trial-welcome-hero__feature">
							<span class="dashicons dashicons-admin-site-alt3"></span>
							<span><?php esc_html_e( 'Sounds like you, not a robot', 'clearpost-simple-ai-auto-post' ); ?></span>
						</div>
					</div>

					<div class="saiap-trial-welcome-hero__actions">
						<button type="button" class="button button-primary button-hero saiap-start-trial-btn">
							<?php esc_html_e( 'Get My Calendar', 'clearpost-simple-ai-auto-post' ); ?>
						</button>
					</div>

					<p class="saiap-trial-welcome-hero__footnote">
						<?php esc_html_e( '7-day free trial. No credit card required.', 'clearpost-simple-ai-auto-post' ); ?>
					</p>
				<?php endif; ?>
			</div>

			<?php if ( ! $has_api_keys ) : ?>
			<div class="saiap-trial-welcome-hero__visual">
				<div class="saiap-trial-welcome-hero__preview">
					<div class="saiap-trial-welcome-hero__preview-header">
						<span class="saiap-trial-welcome-hero__preview-dot"></span>
						<span class="saiap-trial-welcome-hero__preview-dot"></span>
						<span class="saiap-trial-welcome-hero__preview-dot"></span>
					</div>
					<div class="saiap-trial-welcome-hero__preview-content">
						<div class="saiap-trial-welcome-hero__preview-calendar">
							<div class="saiap-trial-welcome-hero__preview-day saiap-trial-welcome-hero__preview-day--active">
								<span class="saiap-trial-welcome-hero__preview-day-num">15</span>
								<span class="saiap-trial-welcome-hero__preview-day-dot"></span>
							</div>
							<div class="saiap-trial-welcome-hero__preview-day">
								<span class="saiap-trial-welcome-hero__preview-day-num">16</span>
								<span class="saiap-trial-welcome-hero__preview-day-dot"></span>
							</div>
							<div class="saiap-trial-welcome-hero__preview-day">
								<span class="saiap-trial-welcome-hero__preview-day-num">17</span>
								<span class="saiap-trial-welcome-hero__preview-day-dot"></span>
							</div>
							<div class="saiap-trial-welcome-hero__preview-day">
								<span class="saiap-trial-welcome-hero__preview-day-num">18</span>
								<span class="saiap-trial-welcome-hero__preview-day-dot"></span>
							</div>
							<div class="saiap-trial-welcome-hero__preview-day">
								<span class="saiap-trial-welcome-hero__preview-day-num">19</span>
								<span class="saiap-trial-welcome-hero__preview-day-dot"></span>
							</div>
						</div>
						<div class="saiap-trial-welcome-hero__preview-stats">
							<div class="saiap-trial-welcome-hero__preview-stat">
								<span class="saiap-trial-welcome-hero__preview-stat-value">29</span>
								<span class="saiap-trial-welcome-hero__preview-stat-label"><?php esc_html_e( 'posts scheduled', 'clearpost-simple-ai-auto-post' ); ?></span>
							</div>
							<div class="saiap-trial-welcome-hero__preview-stat">
								<span class="saiap-trial-welcome-hero__preview-stat-value">57</span>
								<span class="saiap-trial-welcome-hero__preview-stat-label"><?php esc_html_e( 'keywords tracked', 'clearpost-simple-ai-auto-post' ); ?></span>
							</div>
						</div>
					</div>
				</div>
			</div>
			<?php endif; ?>
		</div>
	</div>
	<?php
}

/**
 * Render a small, collapsible license key input for the dashboard.
 *
 * Only shown when user has no trial and no license key saved.
 * Provides a subtle way to enter a license key without dominating the UI.
 */
function saiap_render_license_key_input_mini() {
	$license_key = get_option( 'saiap_license_key', '' );

	// Don't show if license key already exists.
	if ( ! empty( $license_key ) ) {
		return;
	}

	?>
	<div class="saiap-license-mini">
		<button type="button" class="saiap-license-mini__toggle" aria-expanded="false">
			<span class="dashicons dashicons-admin-network"></span>
			<?php esc_html_e( 'Already have a license key?', 'clearpost-simple-ai-auto-post' ); ?>
			<span class="dashicons dashicons-arrow-down-alt2 saiap-license-mini__arrow"></span>
		</button>
		<div class="saiap-license-mini__form" style="display: none;">
			<form id="saiap-license-mini-form" method="post">
				<?php wp_nonce_field( 'saiap_save_license_action', 'saiap_license_form_nonce' ); ?>
				<div class="saiap-license-mini__input-row">
					<input type="text"
						id="saiap-license-key"
						name="license_key"
						class="saiap-license-mini__input"
						placeholder="<?php esc_attr_e( 'Enter license key...', 'clearpost-simple-ai-auto-post' ); ?>"
						autocomplete="off">
					<button type="submit" id="saiap-activate-license" name="saiap_activate_license" class="button button-primary saiap-license-mini__submit">
						<?php esc_html_e( 'Activate', 'clearpost-simple-ai-auto-post' ); ?>
					</button>
				</div>
				<p class="saiap-license-mini__help">
					<?php esc_html_e( 'Purchased a subscription? Enter your license key to unlock premium features.', 'clearpost-simple-ai-auto-post' ); ?>
				</p>
			</form>
		</div>
	</div>
	<style>
		.saiap-license-mini {
			margin: 1.5rem 0;
			text-align: center;
		}
		.saiap-license-mini__toggle {
			background: none;
			border: none;
			color: var(--text-secondary, #6b7280);
			font-size: 0.875rem;
			cursor: pointer;
			display: inline-flex;
			align-items: center;
			gap: 0.5rem;
			padding: 0.5rem 1rem;
			border-radius: 0.375rem;
			transition: color 0.2s, background 0.2s;
		}
		.saiap-license-mini__toggle:hover {
			color: var(--text-primary, #1f2937);
			background: var(--surface-secondary, #f3f4f6);
		}
		.saiap-license-mini__toggle .dashicons {
			font-size: 1rem;
			width: 1rem;
			height: 1rem;
		}
		.saiap-license-mini__arrow {
			transition: transform 0.2s;
		}
		.saiap-license-mini__toggle[aria-expanded="true"] .saiap-license-mini__arrow {
			transform: rotate(180deg);
		}
		.saiap-license-mini__form {
			margin-top: 1rem;
			padding: 1rem;
			background: var(--surface-secondary, #f9fafb);
			border-radius: 0.5rem;
			max-width: 500px;
			margin-left: auto;
			margin-right: auto;
		}
		.saiap-license-mini__input-row {
			display: flex;
			gap: 0.5rem;
		}
		.saiap-license-mini__input {
			flex: 1;
			padding: 0.5rem 0.75rem;
			border: 1px solid var(--border-color, #d1d5db);
			border-radius: 0.375rem;
			font-size: 0.875rem;
		}
		.saiap-license-mini__input:focus {
			outline: none;
			border-color: var(--primary-color, #4f46e5);
			box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.1);
		}
		.saiap-license-mini__submit {
			white-space: nowrap;
		}
		.saiap-license-mini__help {
			margin: 0.75rem 0 0;
			font-size: 0.8125rem;
			color: var(--text-secondary, #6b7280);
		}
	</style>
	<script>
		(function() {
			var toggle = document.querySelector('.saiap-license-mini__toggle');
			var form = document.querySelector('.saiap-license-mini__form');
			if (toggle && form) {
				toggle.addEventListener('click', function() {
					var expanded = toggle.getAttribute('aria-expanded') === 'true';
					toggle.setAttribute('aria-expanded', !expanded);
					form.style.display = expanded ? 'none' : 'block';
					if (!expanded) {
						form.querySelector('input').focus();
					}
				});
			}
		})();
	</script>
	<?php
}

/**
 * Get placeholder titles for the mock calendar preview.
 *
 * Returns cheeky, obviously-placeholder titles that show the calendar
 * structure without pretending to be real content.
 *
 * @param int $count Number of titles to return.
 * @return array Array of placeholder title strings.
 */
function saiap_generate_mock_calendar_titles( $count = 31 ) {
	$placeholders = array(
		'Your first SEO-optimized blog post',
		'This one will bring in customers',
		'Red-hot lead magnet right here',
		'The post that ranks on page 1',
		'Your competitor won\'t see this coming',
		'SEO gold mine',
		'Future traffic driver',
		'The one your audience needs to read',
		'Evergreen content that keeps working',
		'This topic converts like crazy',
		'Your secret ranking weapon',
		'The post that puts you on the map',
		'High-intent keyword content',
		'Blog post your readers will share',
		'Another banger, courtesy of AI',
		'Low competition, high reward',
		'The article your site is missing',
		'Content that builds authority',
		'Your next organic traffic win',
		'A post worth writing home about',
		'Smart content, zero effort',
		'The one Google will love',
		'Conversion-ready content',
		'Your SEO flywheel starts here',
		'Organic traffic on autopilot',
		'The blog post that sells for you',
		'Search-dominating content',
		'Your audience is waiting for this one',
		'AI-powered, human-approved',
		'The post your inbox will thank you for',
		'Content that works while you sleep',
	);

	return array_slice( $placeholders, 0, $count );
}

/**
 * Distribute mock titles across every day in a month.
 *
 * @param array $titles Array of title strings.
 * @param int   $year   Year.
 * @param int   $month  Month (1-12).
 * @return array Associative array of day_number => title string.
 */
function saiap_get_mock_calendar_schedule( $titles, $year, $month ) {
	$days_in_month = (int) gmdate( 't', gmmktime( 0, 0, 0, $month, 1, $year ) );

	// Place one title per day.
	$schedule = array();
	$limit    = min( count( $titles ), $days_in_month );
	for ( $i = 0; $i < $limit; $i++ ) {
		$schedule[ $i + 1 ] = $titles[ $i ];
	}

	return $schedule;
}

/**
 * Render a mock calendar preview for users who haven't started a trial.
 *
 * Shows a populated calendar with personalized article titles based on
 * the user's site data to demonstrate the plugin's value before trial.
 */
function saiap_render_locked_calendar_preview() {
	$year     = (int) gmdate( 'Y' );
	$month    = (int) gmdate( 'n' );
	$titles   = saiap_generate_mock_calendar_titles( 22 );
	$schedule = saiap_get_mock_calendar_schedule( $titles, $year, $month );

	$first_day     = new DateTime( gmdate( 'Y-m-01' ) );
	$day_of_week   = (int) $first_day->format( 'w' ); // Sunday = 0.
	$days_in_month = (int) gmdate( 't' );
	$current_day   = (int) gmdate( 'j' );
	?>
	<div class="saiap-seo-calendar saiap-seo-calendar--preview">
		<div class="saiap-seo-calendar__header">
			<h3><?php esc_html_e( '30-Day Content Calendar', 'clearpost-simple-ai-auto-post' ); ?></h3>
		</div>

		<div class="saiap-seo-calendar__nav">
			<button type="button" class="saiap-calendar-nav-btn" disabled>&lt;</button>
			<span class="saiap-calendar-month-label"><?php echo esc_html( date_i18n( 'F Y' ) ); ?></span>
			<button type="button" class="saiap-calendar-nav-btn" disabled>&gt;</button>
		</div>

		<div class="saiap-seo-calendar__weekdays">
			<span><?php esc_html_e( 'Sun', 'clearpost-simple-ai-auto-post' ); ?></span>
			<span><?php esc_html_e( 'Mon', 'clearpost-simple-ai-auto-post' ); ?></span>
			<span><?php esc_html_e( 'Tue', 'clearpost-simple-ai-auto-post' ); ?></span>
			<span><?php esc_html_e( 'Wed', 'clearpost-simple-ai-auto-post' ); ?></span>
			<span><?php esc_html_e( 'Thu', 'clearpost-simple-ai-auto-post' ); ?></span>
			<span><?php esc_html_e( 'Fri', 'clearpost-simple-ai-auto-post' ); ?></span>
			<span><?php esc_html_e( 'Sat', 'clearpost-simple-ai-auto-post' ); ?></span>
		</div>

		<div class="saiap-seo-calendar__grid">
			<?php
			// Empty cells before first day (Sunday-start grid).
			for ( $i = 0; $i < $day_of_week; $i++ ) {
				echo '<div class="saiap-calendar-day saiap-calendar-day--other-month"><span class="saiap-calendar-day__number"></span></div>';
			}

			for ( $day = 1; $day <= $days_in_month; $day++ ) {
				$has_item = isset( $schedule[ $day ] );
				$is_today = ( $day === $current_day );

				$classes = 'saiap-calendar-day';
				if ( $is_today ) {
					$classes .= ' saiap-calendar-day--today';
				}
				if ( $has_item ) {
					$classes .= ' saiap-calendar-day--has-item';
				}

				echo '<div class="' . esc_attr( $classes ) . '">';
				echo '<span class="saiap-calendar-day__number">' . esc_html( $day ) . '</span>';

				if ( $has_item ) {
					echo '<div class="saiap-calendar-day__items">';
					echo '<div class="saiap-calendar-item-card saiap-calendar-item-card--scheduled saiap-calendar-item-card--mock">';
					echo '<span class="saiap-calendar-item-card__keyword">' . esc_html( $schedule[ $day ] ) . '</span>';
					echo '</div>';
					echo '</div>';
				}

				echo '</div>';
			}
			?>
		</div>

		<div class="saiap-seo-calendar__preview-cta">
			<span class="dashicons dashicons-info-outline"></span>
			<span><?php esc_html_e( 'This is a preview — start your trial to get organic traffic on autopilot.', 'clearpost-simple-ai-auto-post' ); ?></span>
			<button type="button" class="button button-primary button-small saiap-start-trial-btn">
				<?php esc_html_e( 'Get My Calendar', 'clearpost-simple-ai-auto-post' ); ?>
			</button>
		</div>
	</div>
	<?php
}

/**
 * Render the expired trial CTA with published/pending counts.
 *
 * This CTA appears above the calendar (not as overlay) and shows:
 * - How many posts were published during trial (accomplishments)
 * - How many are still pending (FOMO/motivation to subscribe)
 */
function saiap_render_expired_trial_cta() {
	$checkout_url = function_exists( 'saiap_get_checkout_url' ) ? saiap_get_checkout_url() : 'https://buy.stripe.com/7sY6oIfwqgPu1Za7vC3AY06';

	?>
	<div class="saiap-dashboard-expired-notice saiap-dashboard-expired-notice--frozen-world">
		<div class="saiap-expired-notice__content">
			<h3><?php esc_html_e( 'Your trial has ended', 'clearpost-simple-ai-auto-post' ); ?></h3>
			<p class="saiap-expired-notice__message" id="saiap-expired-message">
				<?php esc_html_e( 'Subscribe to continue publishing with ClearPost.', 'clearpost-simple-ai-auto-post' ); ?>
			</p>

			<a href="<?php echo esc_url( $checkout_url ); ?>" class="button button-primary button-hero" target="_blank">
				<?php esc_html_e( 'Subscribe to Continue', 'clearpost-simple-ai-auto-post' ); ?>
			</a>

			<p class="saiap-expired-secondary">
				<?php esc_html_e( 'Or continue manually with your own API keys.', 'clearpost-simple-ai-auto-post' ); ?>
			</p>
		</div>
	</div>
	<?php
}

/**
 * Render trial generation cap progress bar + upgrade CTA when cap reached.
 */
function saiap_render_trial_cap_banner() {
	$post_cap        = get_option( 'saiap_trial_post_cap', 0 );
	$posts_generated = get_option( 'saiap_trial_posts_generated', 0 );

	if ( ! $post_cap ) {
		return;
	}

	$cap_reached = $posts_generated >= $post_cap;
	$percentage  = min( 100, round( ( $posts_generated / $post_cap ) * 100 ) );
	?>
	<div class="saiap-trial-cap-banner" style="margin-bottom: 16px; padding: 12px 16px; border-radius: 8px; background: <?php echo $cap_reached ? '#fef2f2' : '#f0f9ff'; ?>; border: 1px solid <?php echo $cap_reached ? '#fecaca' : '#bae6fd'; ?>;">
		<?php if ( $cap_reached ) : ?>
			<p style="margin: 0 0 8px; font-weight: 600; color: #991b1b;">
				<?php
				printf(
					esc_html__( "You've used all %d free trial posts.", 'clearpost-simple-ai-auto-post' ),
					absint( $post_cap )
				);
				?>
			</p>
			<p style="margin: 0 0 8px; color: #7f1d1d;">
				<?php esc_html_e( 'Upgrade to Premium for unlimited AI-generated posts.', 'clearpost-simple-ai-auto-post' ); ?>
			</p>
			<a href="<?php echo esc_url( saiap_get_checkout_url() ); ?>" class="button button-primary" target="_blank">
				<?php esc_html_e( 'Upgrade to Premium — $99/mo', 'clearpost-simple-ai-auto-post' ); ?>
			</a>
		<?php else : ?>
			<p style="margin: 0 0 6px; font-size: 13px; color: #1e40af;">
				<?php
				printf(
					esc_html__( '%1$d / %2$d free posts used', 'clearpost-simple-ai-auto-post' ),
					absint( $posts_generated ),
					absint( $post_cap )
				);
				?>
			</p>
			<div style="height: 6px; background: #e0f2fe; border-radius: 3px; overflow: hidden;">
				<div style="height: 100%; width: <?php echo absint( $percentage ); ?>%; background: #3b82f6; border-radius: 3px;"></div>
			</div>
		<?php endif; ?>
	</div>
	<?php
}

/**
 * Render the subscribe CTA for trial users.
 */
function saiap_render_trial_subscribe_cta() {
	$days_remaining = saiap_get_trial_days_remaining();
	?>
	<div class="saiap-dashboard-subscribe-cta">
		<p>
			<?php
			printf(
				/* translators: %d: days remaining in trial */
				esc_html__( 'Your trial ends in %d days. Subscribe now to continue after trial ends.', 'clearpost-simple-ai-auto-post' ),
				absint( $days_remaining )
			);
			?>
		</p>
		<a href="<?php echo esc_url( saiap_get_checkout_url() ); ?>" class="button button-secondary" target="_blank">
			<?php esc_html_e( 'Upgrade Now', 'clearpost-simple-ai-auto-post' ); ?>
		</a>
	</div>
	<?php
}

/**
 * Check if the GSC onboarding interstitial should be shown.
 *
 * Returns true if:
 * - The gsc_prompt=1 query param is present (just came from wizard)
 * - OR wizard data exists but setup hasn't been triggered yet (navigated away and came back)
 * AND:
 * - User has a license/trial
 * - Setup hasn't been triggered yet
 *
 * @return bool
 */
function saiap_should_show_gsc_interstitial() {
	// Setup already triggered — no interstitial needed.
	if ( get_option( 'saiap_setup_triggered_at', 0 ) ) {
		return false;
	}

	// Must have wizard data (trial was started and wizard was completed).
	if ( ! get_option( 'saiap_onboarding_wizard_data', null ) ) {
		return false;
	}

	// Must have a license key (trial or paid).
	if ( empty( get_option( 'saiap_license_key', '' ) ) ) {
		return false;
	}

	return true;
}

/**
 * Safety net: auto-trigger setup if the GSC interstitial has been pending too long.
 *
 * Prevents dead trials when JS fails, user navigates away, or an old plugin
 * version doesn't have the saiap_ajax_trigger_setup endpoint. If wizard data
 * exists and setup hasn't triggered within 10 minutes of trial start, trigger
 * it automatically on the next dashboard load.
 */
function saiap_maybe_auto_trigger_setup() {
	// Only relevant if setup hasn't been triggered yet.
	if ( get_option( 'saiap_setup_triggered_at', 0 ) ) {
		return;
	}

	$wizard_data = get_option( 'saiap_onboarding_wizard_data', null );
	if ( ! $wizard_data ) {
		return;
	}

	$license_key = get_option( 'saiap_license_key', '' );
	if ( empty( $license_key ) ) {
		return;
	}

	// Check how long ago the trial started.
	$trial_started_at = get_option( 'saiap_trial_started_at', '' );
	if ( empty( $trial_started_at ) ) {
		return;
	}

	$elapsed_seconds = time() - strtotime( $trial_started_at );
	if ( $elapsed_seconds < 10 * MINUTE_IN_SECONDS ) {
		// Still within the grace period — let the interstitial do its job.
		return;
	}

	// Trial started >10 minutes ago but setup never triggered — fire the safety net.
	saiap_trigger_automated_setup( $wizard_data );
	update_option( 'saiap_setup_triggered_at', time() );
}

/**
 * Render the GSC onboarding interstitial.
 *
 * Shown after wizard submit but before setup triggers. Gives users the
 * opportunity to connect Google Search Console so the strategy session
 * can use real search data.
 */
function saiap_render_gsc_interstitial() {
	$domain          = saiap_get_server_host();
	$premium_api_url = str_replace( 'host.docker.internal', 'localhost', SAIAP_PREMIUM_API_URL );
	$gsc_status_url  = admin_url( 'admin-ajax.php?action=saiap_gsc_status&_wpnonce=' . wp_create_nonce( 'saiap_gsc_nonce' ) );
	$gsc_connect_url = $premium_api_url . '/api/gsc/oauth/start?' . http_build_query(
		array(
			'domain'     => $domain,
			'return_url' => admin_url( 'admin.php?page=saiap&tab=dashboard&gsc_connected=1' ),
		)
	);

	// Calculate remaining seconds before the safety net auto-triggers setup.
	$grace_seconds     = 10 * MINUTE_IN_SECONDS;
	$trial_started_at  = get_option( 'saiap_trial_started_at', '' );
	$remaining_seconds = $grace_seconds;
	if ( ! empty( $trial_started_at ) ) {
		$elapsed           = time() - strtotime( $trial_started_at );
		$remaining_seconds = max( 0, $grace_seconds - $elapsed );
	}

	?>
	<div class="saiap-gsc-interstitial" id="saiap-gsc-interstitial"
		data-gsc-status-url="<?php echo esc_attr( $gsc_status_url ); ?>"
		data-remaining-seconds="<?php echo esc_attr( $remaining_seconds ); ?>">
		<div class="saiap-gsc-interstitial__icon">
			<span class="dashicons dashicons-chart-area"></span>
		</div>
		<h3 class="saiap-gsc-interstitial__title">
			<?php esc_html_e( 'Connect Google Search Console for a smarter strategy', 'clearpost-simple-ai-auto-post' ); ?>
		</h3>
		<p class="saiap-gsc-interstitial__description">
			<?php esc_html_e( 'ClearPost will use your real search data — rankings, clicks, and top queries — to build a content strategy tailored to what\'s actually working.', 'clearpost-simple-ai-auto-post' ); ?>
		</p>
		<div class="saiap-gsc-interstitial__actions">
			<a href="<?php echo esc_url( $gsc_connect_url ); ?>" class="button button-primary button-hero saiap-gsc-interstitial__connect">
				<?php esc_html_e( 'Connect Google Search Console', 'clearpost-simple-ai-auto-post' ); ?>
			</a>
			<button type="button" class="button button-hero saiap-gsc-interstitial__skip" id="saiap-gsc-interstitial-skip">
				<?php esc_html_e( 'Skip — start without GSC', 'clearpost-simple-ai-auto-post' ); ?>
			</button>
		</div>
		<p class="saiap-gsc-interstitial__footnote">
			<?php esc_html_e( 'You can always connect Google Search Console later from Settings.', 'clearpost-simple-ai-auto-post' ); ?>
		</p>
		<p class="saiap-gsc-interstitial__countdown" id="saiap-gsc-countdown">
			<?php
			/* translators: %s is a time string like "9:45" */
			printf( esc_html__( 'Setup will start automatically in %s', 'clearpost-simple-ai-auto-post' ), '<span id="saiap-gsc-countdown-time"></span>' );
			?>
		</p>
	</div>
	<?php
}

/**
 * Render the setup progress loader.
 *
 * Shows animated status text while the automated setup is running.
 */
function saiap_render_setup_loader() {
	$setup_triggered = get_option( 'saiap_setup_triggered_at', 0 );
	$time_elapsed    = $setup_triggered ? ( time() - $setup_triggered ) : 0;
	$timeout_minutes = 10;

	?>
	<div class="saiap-setup-loader" 
		data-setup-triggered="<?php echo esc_attr( $setup_triggered ); ?>"
		data-timeout-minutes="<?php echo esc_attr( $timeout_minutes ); ?>">
		
		<div class="saiap-setup-loader__content">
			<div class="saiap-setup-loader__spinner">
				<svg class="saiap-spinner-svg" viewBox="0 0 50 50">
					<circle class="saiap-spinner-path" cx="25" cy="25" r="20" fill="none" stroke-width="4"></circle>
				</svg>
			</div>
			
			<div class="saiap-setup-loader__text">
				<span class="saiap-setup-loader__status"><?php esc_html_e( 'Analyzing your content...', 'clearpost-simple-ai-auto-post' ); ?></span>
			</div>
			
			<p class="saiap-setup-loader__hint">
				<?php esc_html_e( 'This usually takes 2-5 minutes.', 'clearpost-simple-ai-auto-post' ); ?>
			</p>
		</div>
		
		<div class="saiap-setup-loader__timeout" style="display: none;">
			<span class="dashicons dashicons-clock"></span>
			<h4><?php esc_html_e( 'Taking longer than expected', 'clearpost-simple-ai-auto-post' ); ?></h4>
			<p><?php esc_html_e( 'Your content calendar is still being generated. This can happen for sites with lots of content.', 'clearpost-simple-ai-auto-post' ); ?></p>
			<p>
				<a href="mailto:support@clearpostplugin.com" class="saiap-setup-loader__support-link">
					<?php esc_html_e( 'Contact support if this persists', 'clearpost-simple-ai-auto-post' ); ?>
				</a>
			</p>
		</div>
	</div>
	<?php
}

/**
 * Render the 30-day SEO calendar.
 *
 * For trial_expired variant, we use "frozen world" approach:
 * - Published items remain visible and clickable (user accomplishments)
 * - Planned/pending items are blurred and locked (FOMO)
 * - No full overlay - individual item locking based on status
 *
 * @param string $variant The dashboard content variant.
 */
function saiap_render_seo_calendar( $variant ) {
	// Only fully lock for 'locked' (no trial started) - trial_expired uses per-item locking
	$is_locked       = ( 'locked' === $variant );
	$trial_day_limit = 7; // Days visible during trial before lock.

	// Check if setup is still running. Route through the helper so the
	// first_post_created short-circuit also applies here.
	$is_setup_running = saiap_is_setup_in_progress();

	?>
	<div class="saiap-seo-calendar <?php echo $is_locked ? 'saiap-seo-calendar--locked' : ''; ?>" 
		data-variant="<?php echo esc_attr( $variant ); ?>"
		data-trial-day-limit="<?php echo esc_attr( $trial_day_limit ); ?>"
		data-setup-running="<?php echo $is_setup_running ? 'true' : 'false'; ?>">
		
		<div class="saiap-seo-calendar__header">
			<h3><?php esc_html_e( '30-Day Content Calendar', 'clearpost-simple-ai-auto-post' ); ?></h3>
			
			<?php if ( ! $is_locked ) : ?>
				<div class="saiap-seo-calendar__actions">
					<button type="button" class="button saiap-pipeline-rerun" title="<?php esc_attr_e( 'Re-run keyword research and rebuild calendar from scratch', 'clearpost-simple-ai-auto-post' ); ?>">
						<span class="dashicons dashicons-image-rotate"></span>
						<?php esc_html_e( 'Regenerate', 'clearpost-simple-ai-auto-post' ); ?>
					</button>
				</div>
			<?php endif; ?>
		</div>

		<div class="saiap-seo-calendar__nav">
			<button type="button" class="saiap-calendar-nav-btn saiap-calendar-prev" title="<?php esc_attr_e( 'Previous month', 'clearpost-simple-ai-auto-post' ); ?>">
				<span class="dashicons dashicons-arrow-left-alt2"></span>
			</button>
			<span class="saiap-calendar-month-label"></span>
			<button type="button" class="saiap-calendar-nav-btn saiap-calendar-next" title="<?php esc_attr_e( 'Next month', 'clearpost-simple-ai-auto-post' ); ?>">
				<span class="dashicons dashicons-arrow-right-alt2"></span>
			</button>
		</div>

		<div class="saiap-seo-calendar__weekdays">
			<span><?php esc_html_e( 'Sun', 'clearpost-simple-ai-auto-post' ); ?></span>
			<span><?php esc_html_e( 'Mon', 'clearpost-simple-ai-auto-post' ); ?></span>
			<span><?php esc_html_e( 'Tue', 'clearpost-simple-ai-auto-post' ); ?></span>
			<span><?php esc_html_e( 'Wed', 'clearpost-simple-ai-auto-post' ); ?></span>
			<span><?php esc_html_e( 'Thu', 'clearpost-simple-ai-auto-post' ); ?></span>
			<span><?php esc_html_e( 'Fri', 'clearpost-simple-ai-auto-post' ); ?></span>
			<span><?php esc_html_e( 'Sat', 'clearpost-simple-ai-auto-post' ); ?></span>
		</div>

		<div class="saiap-seo-calendar__grid">
			<!-- Calendar days will be rendered by JavaScript -->
			<div class="saiap-seo-calendar__loading">
				<span class="spinner is-active"></span>
				<span><?php esc_html_e( 'Loading calendar...', 'clearpost-simple-ai-auto-post' ); ?></span>
			</div>
		</div>

		<?php if ( $is_setup_running ) : ?>
			<?php saiap_render_setup_loader(); ?>
		<?php endif; ?>
	</div>

	<!-- Calendar Item Modal -->
	<div id="saiap-calendar-modal" class="saiap-modal" style="display:none;">
		<div class="saiap-modal__backdrop"></div>
		<div class="saiap-modal__content">
			<button type="button" class="saiap-modal__close">&times;</button>
			<div class="saiap-modal__body">
				<!-- Modal content populated by JS -->
			</div>
		</div>
	</div>
	<?php
}

/**
 * Render the autopilot controls (legacy, kept for backward compatibility).
 *
 * @param string $variant The dashboard content variant.
 */
function saiap_render_autopilot_controls( $variant ) {
	// Now handled inline by saiap_render_dashboard_top_row().
	// This function is kept for backward compatibility but does nothing.
}

/**
 * Render the main dashboard tab.
 */
function saiap_render_dashboard_tab() {
	// Sync trial state from server (throttled to once per hour).
	saiap_maybe_sync_trial_state();

	// Safety net: auto-trigger setup if interstitial has been pending too long.
	saiap_maybe_auto_trigger_setup();

	$variant = saiap_get_dashboard_content_variant();

	// Check for GSC-related query params.
	$show_gsc_interstitial = saiap_should_show_gsc_interstitial();
	$gsc_connected         = isset( $_GET['gsc_connected'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
	$gsc_error             = isset( $_GET['gsc_error'] ) ? sanitize_text_field( wp_unslash( $_GET['gsc_error'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

	// Determine if this is an existing user connecting GSC (setup already ran).
	$setup_already_ran  = ! empty( get_option( 'saiap_setup_triggered_at', 0 ) );
	$auto_gsc_review    = $gsc_connected && $setup_already_ran;
	$auto_trigger_setup = $gsc_connected && ! $setup_already_ran;

	// Output JS flags for dashboard.js to handle.
	if ( $auto_gsc_review || $auto_trigger_setup || $show_gsc_interstitial ) :
		?>
		<script>
		<?php if ( $auto_gsc_review ) : ?>
			window.saiapAutoGscReview = true;
		<?php endif; ?>
		<?php if ( $auto_trigger_setup ) : ?>
			window.saiapAutoTriggerSetup = true;
		<?php endif; ?>
		<?php if ( $show_gsc_interstitial ) : ?>
			window.saiapGscInterstitial = true;
		<?php endif; ?>
			window.saiapTriggerSetupNonce = <?php echo wp_json_encode( wp_create_nonce( 'saiap_trigger_setup_nonce' ) ); ?>;
		</script>
		<?php
	endif;

	?>
	<div class="saiap-dashboard saiap-dashboard--<?php echo esc_attr( $variant ); ?>">
		<div class="saiap-dashboard__header">
			<h2><?php esc_html_e( 'Dashboard', 'clearpost-simple-ai-auto-post' ); ?></h2>

			<?php if ( 'trial_active' === $variant ) : ?>
				<?php saiap_render_trial_status_badge(); ?>
			<?php endif; ?>
		</div>

		<?php saiap_render_dashboard_status( $variant ); ?>

		<?php if ( $gsc_error ) : ?>
			<div class="notice notice-error inline" style="margin: 16px 0;">
				<p>
				<?php
				switch ( $gsc_error ) {
					case 'denied':
						esc_html_e( 'Google Search Console access was denied. Please try again or skip to continue.', 'clearpost-simple-ai-auto-post' );
						break;
					case 'no_properties':
						esc_html_e( 'No Search Console properties found. Make sure your site is added to Google Search Console first, or skip to continue.', 'clearpost-simple-ai-auto-post' );
						break;
					case 'no_match':
						esc_html_e( 'Could not match a Search Console property to this site. Check your GSC properties, or skip to continue.', 'clearpost-simple-ai-auto-post' );
						break;
					default:
						esc_html_e( 'Failed to connect Google Search Console. Please try again or skip to continue.', 'clearpost-simple-ai-auto-post' );
				}
				?>
				</p>
			</div>
		<?php endif; ?>

		<?php if ( 'locked' === $variant ) : ?>
			<?php saiap_render_dashboard_trial_cta(); ?>
			<?php saiap_render_license_key_input_mini(); ?>
			<?php saiap_render_locked_calendar_preview(); ?>
		<?php else : ?>
			<?php if ( $show_gsc_interstitial ) : ?>
				<?php saiap_render_gsc_interstitial(); ?>
			<?php endif; ?>

			<?php if ( 'trial_expired' === $variant ) : ?>
				<?php saiap_render_expired_trial_cta(); ?>
			<?php endif; ?>

			<?php if ( saiap_is_setup_in_progress() && function_exists( 'saiap_render_setup_stream_mount' ) ) : ?>
				<?php saiap_render_setup_stream_mount(); ?>
			<?php else : ?>
				<?php saiap_render_dashboard_top_row( $variant ); ?>

				<?php
				if ( function_exists( 'saiap_render_review_nudge' ) ) {
					saiap_render_review_nudge();
				}
				?>

				<?php saiap_render_seo_calendar( $variant ); ?>

				<?php if ( 'trial_active' === $variant ) : ?>
					<?php saiap_render_trial_cap_banner(); ?>
					<?php saiap_render_trial_subscribe_cta(); ?>
				<?php endif; ?>

				<?php saiap_render_rank_tracker( $variant ); ?>
			<?php endif; ?>

			<?php // MCP card moved to Edit with AI tab. ?>
		<?php endif; ?>
	</div>
	<?php

	// Review prompt modal (two-step sentiment gate).
	if ( function_exists( 'saiap_render_review_modal' ) ) {
		saiap_render_review_modal();
	}

	// Mount point for the SEO Agent Chat floating drawer.
	if ( function_exists( 'saiap_render_seo_agent_chat_mount' ) ) {
		saiap_render_seo_agent_chat_mount();
	}
}

/**
 * Render the Keyword Rank Tracker section.
 *
 * Shows tracked keywords with rank badges, changes, and sparklines.
 *
 * @param string $variant The dashboard content variant.
 */
function saiap_render_rank_tracker( $variant ) {
	$is_active = in_array( $variant, array( 'trial_active', 'paid' ), true );

	if ( ! $is_active ) {
		return;
	}
	?>
	<div class="saiap-rank-tracker">
		<div class="saiap-rank-tracker__header">
			<h3><?php esc_html_e( 'Keyword Rank Tracker', 'clearpost-simple-ai-auto-post' ); ?></h3>
			<button type="button" class="button saiap-add-keyword-btn">
				<span class="dashicons dashicons-plus-alt2"></span>
				<?php esc_html_e( 'Add Keyword', 'clearpost-simple-ai-auto-post' ); ?>
			</button>
		</div>

		<p class="saiap-rank-tracker__desc">
			<?php esc_html_e( 'Track up to 10 keywords to monitor your SERP positions daily.', 'clearpost-simple-ai-auto-post' ); ?>
			<span class="saiap-rank-tracker__count">
				<span id="saiap-tracked-count">0</span>/10 <?php esc_html_e( 'tracked', 'clearpost-simple-ai-auto-post' ); ?>
			</span>
		</p>

		<div class="saiap-rank-tracker__table">
			<div class="saiap-rank-tracker__thead">
				<span class="saiap-rank-tracker__th saiap-rank-tracker__th--keyword"><?php esc_html_e( 'Keyword', 'clearpost-simple-ai-auto-post' ); ?></span>
				<span class="saiap-rank-tracker__th saiap-rank-tracker__th--volume"><?php esc_html_e( 'Volume', 'clearpost-simple-ai-auto-post' ); ?></span>
				<span class="saiap-rank-tracker__th saiap-rank-tracker__th--difficulty"><?php esc_html_e( 'Difficulty', 'clearpost-simple-ai-auto-post' ); ?></span>
				<span class="saiap-rank-tracker__th saiap-rank-tracker__th--rank"><?php esc_html_e( 'Rank', 'clearpost-simple-ai-auto-post' ); ?></span>
				<span class="saiap-rank-tracker__th saiap-rank-tracker__th--change"><?php esc_html_e( 'Change', 'clearpost-simple-ai-auto-post' ); ?></span>
				<span class="saiap-rank-tracker__th saiap-rank-tracker__th--trend"><?php esc_html_e( '30d Trend', 'clearpost-simple-ai-auto-post' ); ?></span>
				<span class="saiap-rank-tracker__th saiap-rank-tracker__th--track"><?php esc_html_e( 'Track', 'clearpost-simple-ai-auto-post' ); ?></span>
			</div>
			<div class="saiap-rank-tracker__list">
				<div class="saiap-rank-tracker__loading">
					<span class="spinner is-active"></span>
					<span><?php esc_html_e( 'Loading tracked keywords...', 'clearpost-simple-ai-auto-post' ); ?></span>
				</div>
			</div>
		</div>

		<div class="saiap-rank-tracker__empty" style="display: none;">
			<p><?php esc_html_e( 'No keywords being tracked yet. Click "Add Keyword" to start monitoring your SERP positions.', 'clearpost-simple-ai-auto-post' ); ?></p>
		</div>
	</div>

	<!-- Add Keyword Modal -->
	<div class="saiap-add-keyword-modal" style="display: none;">
		<div class="saiap-add-keyword-modal__backdrop"></div>
		<div class="saiap-add-keyword-modal__content">
			<div class="saiap-add-keyword-modal__header">
				<h3><?php esc_html_e( 'Add Keyword to Track', 'clearpost-simple-ai-auto-post' ); ?></h3>
				<button type="button" class="saiap-add-keyword-modal__close" aria-label="<?php esc_attr_e( 'Close', 'clearpost-simple-ai-auto-post' ); ?>">
					<span class="dashicons dashicons-no-alt"></span>
				</button>
			</div>
			<div class="saiap-add-keyword-modal__body">
				<div class="saiap-add-keyword-modal__tabs">
					<button type="button" class="saiap-add-keyword-tab active" data-tab="existing">
						<?php esc_html_e( 'Select Existing', 'clearpost-simple-ai-auto-post' ); ?>
					</button>
					<button type="button" class="saiap-add-keyword-tab" data-tab="new">
						<?php esc_html_e( 'Add New', 'clearpost-simple-ai-auto-post' ); ?>
					</button>
				</div>
				<div class="saiap-add-keyword-panel" data-panel="existing">
					<p class="description"><?php esc_html_e( 'Select from keywords we discovered during your site analysis:', 'clearpost-simple-ai-auto-post' ); ?></p>
					<select id="saiap-existing-keyword-select" class="saiap-add-keyword-select">
						<option value=""><?php esc_html_e( 'Loading keywords...', 'clearpost-simple-ai-auto-post' ); ?></option>
					</select>
				</div>
				<div class="saiap-add-keyword-panel" data-panel="new" style="display: none;">
					<p class="description"><?php esc_html_e( 'Enter a keyword you want to track:', 'clearpost-simple-ai-auto-post' ); ?></p>
					<input type="text" id="saiap-new-keyword-input" class="regular-text" placeholder="<?php esc_attr_e( 'e.g., orthopedic surgeon atlanta', 'clearpost-simple-ai-auto-post' ); ?>">
				</div>
			</div>
			<div class="saiap-add-keyword-modal__footer">
				<button type="button" class="button saiap-add-keyword-cancel"><?php esc_html_e( 'Cancel', 'clearpost-simple-ai-auto-post' ); ?></button>
				<button type="button" class="button button-primary saiap-add-keyword-submit"><?php esc_html_e( 'Add & Track', 'clearpost-simple-ai-auto-post' ); ?></button>
			</div>
		</div>
	</div>

	<style>
		.saiap-rank-tracker {
			margin-top: 2rem;
			background: var(--surface-primary, #fff);
			border: 1px solid var(--border-color, #e5e7eb);
			border-radius: 0.5rem;
			padding: 1.5rem;
		}
		.saiap-rank-tracker__header {
			display: flex;
			justify-content: space-between;
			align-items: center;
			margin-bottom: 0.5rem;
		}
		.saiap-rank-tracker__header h3 {
			margin: 0;
			font-size: 1.125rem;
			font-weight: 600;
		}
		.saiap-add-keyword-btn {
			display: flex !important;
			align-items: center !important;
			justify-content: center;
			gap: 4px;
			height: 32px;
			padding: 0 12px !important;
		}
		.saiap-add-keyword-btn .dashicons {
			font-size: 16px;
			width: 16px;
			height: 16px;
		}
		.saiap-rank-tracker__desc {
			color: var(--text-secondary, #6b7280);
			font-size: 0.875rem;
			margin: 0 0 1rem;
		}
		.saiap-rank-tracker__count {
			font-weight: 500;
			color: var(--text-primary, #1f2937);
		}
		.saiap-rank-tracker__loading {
			display: flex;
			align-items: center;
			gap: 0.5rem;
			padding: 1rem;
			color: var(--text-secondary, #6b7280);
		}
		.saiap-rank-tracker__empty {
			padding: 2rem;
			text-align: center;
			color: var(--text-secondary, #6b7280);
		}
		.saiap-rank-tracker__table {
			border: 1px solid var(--border-color, #e5e7eb);
			border-radius: 0.375rem;
			overflow: hidden;
		}
		.saiap-rank-tracker__thead {
			display: grid;
			grid-template-columns: 1fr 55px 65px 80px 55px 80px 50px;
			gap: 0.5rem;
			padding: 0.625rem 1rem;
			background: var(--surface-secondary, #f9fafb);
			border-bottom: 1px solid var(--border-color, #e5e7eb);
		}
		.saiap-rank-tracker__th {
			font-size: 0.6875rem;
			font-weight: 600;
			color: var(--text-secondary, #6b7280);
			text-transform: uppercase;
			letter-spacing: 0.025em;
		}
		.saiap-rank-tracker__th--volume,
		.saiap-rank-tracker__th--difficulty,
		.saiap-rank-tracker__th--rank,
		.saiap-rank-tracker__th--change,
		.saiap-rank-tracker__th--trend,
		.saiap-rank-tracker__th--track {
			text-align: center;
		}
		.saiap-rank-tracker__list {
			display: flex;
			flex-direction: column;
		}
		.saiap-rank-keyword {
			display: grid;
			grid-template-columns: 1fr 55px 65px 80px 55px 80px 50px;
			gap: 0.5rem;
			align-items: center;
			padding: 0.75rem 1rem;
			border-bottom: 1px solid var(--border-color, #e5e7eb);
			transition: background 0.15s;
		}
		.saiap-rank-keyword:last-child {
			border-bottom: none;
		}
		.saiap-rank-keyword:hover {
			background: var(--surface-secondary, #f9fafb);
		}
		.saiap-rank-keyword__name {
			font-weight: 500;
			overflow: hidden;
			text-overflow: ellipsis;
			white-space: nowrap;
			min-width: 0;
		}
		.saiap-rank-keyword__badge {
			display: inline-flex;
			align-items: center;
			justify-content: center;
			padding: 0.25rem 0.5rem;
			font-size: 0.8125rem;
			font-weight: 600;
			border-radius: 0.25rem;
		}
		.saiap-rank-keyword__badge--top10 {
			background: #dcfce7;
			color: #166534;
		}
		.saiap-rank-keyword__badge--top20 {
			background: #fef9c3;
			color: #854d0e;
		}
		.saiap-rank-keyword__badge--other {
			background: #fee2e2;
			color: #991b1b;
		}
		.saiap-rank-keyword__badge--unranked {
			background: transparent;
			color: #9ca3af;
			font-size: 0.6875rem;
			font-weight: 400;
			padding: 0;
			white-space: nowrap;
		}
		.saiap-rank-keyword__change {
			font-size: 0.8125rem;
			font-weight: 600;
			text-align: center;
		}
		.saiap-rank-keyword__change--up {
			color: #16a34a;
		}
		.saiap-rank-keyword__change--down {
			color: #dc2626;
		}
		.saiap-rank-keyword__change--none {
			color: #d1d5db;
		}
		.saiap-rank-keyword__sparkline-wrap {
			display: flex;
			align-items: center;
			justify-content: center;
		}
		.saiap-rank-keyword__sparkline {
			width: 80px;
			height: 24px;
			flex-shrink: 0;
		}
		.saiap-rank-keyword__sparkline--empty {
			background: #f3f4f6;
			border-radius: 0.125rem;
		}
		.saiap-rank-keyword__no-data {
			font-size: 0.6875rem;
			color: #9ca3af;
			text-align: center;
		}
		.saiap-rank-keyword__track-toggle {
			display: flex;
			justify-content: center;
		}
		/* Volume and KD column styles */
		.saiap-rank-keyword__volume,
		.saiap-rank-keyword__difficulty {
			font-size: 0.8125rem;
			text-align: center;
			color: #6b7280;
		}
		.saiap-rank-keyword__difficulty--easy {
			color: #16a34a;
		}
		.saiap-rank-keyword__difficulty--medium {
			color: #d97706;
		}
		.saiap-rank-keyword__difficulty--hard {
			color: #dc2626;
		}
		/* Add Keyword Modal */
		.saiap-add-keyword-modal {
			position: fixed;
			top: 0;
			left: 0;
			right: 0;
			bottom: 0;
			z-index: 100000;
			display: flex;
			align-items: center;
			justify-content: center;
		}
		.saiap-add-keyword-modal__backdrop {
			position: absolute;
			top: 0;
			left: 0;
			right: 0;
			bottom: 0;
			background: rgba(0, 0, 0, 0.5);
		}
		.saiap-add-keyword-modal__content {
			position: relative;
			background: #fff;
			border-radius: 0.5rem;
			box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
			width: 100%;
			max-width: 28rem;
			max-height: 90vh;
			overflow: auto;
		}
		.saiap-add-keyword-modal__header {
			display: flex;
			justify-content: space-between;
			align-items: center;
			padding: 1rem 1.5rem;
			border-bottom: 1px solid #e5e7eb;
		}
		.saiap-add-keyword-modal__header h3 {
			margin: 0;
			font-size: 1.125rem;
		}
		.saiap-add-keyword-modal__close {
			background: none;
			border: none;
			cursor: pointer;
			padding: 0.25rem;
			color: #6b7280;
		}
		.saiap-add-keyword-modal__close:hover {
			color: #111827;
		}
		.saiap-add-keyword-modal__body {
			padding: 1.5rem;
		}
		.saiap-add-keyword-modal__tabs {
			display: flex;
			gap: 0.5rem;
			margin-bottom: 1rem;
		}
		.saiap-add-keyword-tab {
			flex: 1;
			padding: 0.5rem 1rem;
			border: 1px solid #d1d5db;
			background: #f9fafb;
			border-radius: 0.375rem;
			cursor: pointer;
			font-size: 0.875rem;
			transition: all 0.15s;
		}
		.saiap-add-keyword-tab:hover {
			background: #f3f4f6;
		}
		.saiap-add-keyword-tab.active {
			background: #2271b1;
			border-color: #2271b1;
			color: #fff;
		}
		.saiap-add-keyword-panel .description {
			margin-bottom: 0.75rem;
			color: #6b7280;
		}
		.saiap-add-keyword-select {
			width: 100%;
			padding: 0.5rem;
			border: 1px solid #d1d5db;
			border-radius: 0.375rem;
			font-size: 0.875rem;
		}
		.saiap-add-keyword-modal__footer {
			display: flex;
			justify-content: flex-end;
			gap: 0.5rem;
			padding: 1rem 1.5rem;
			border-top: 1px solid #e5e7eb;
			background: #f9fafb;
		}
	</style>
	<?php
}

/**
 * Get "orphaned" ClearPost-generated posts that don't have matching calendar items.
 *
 * These posts can occur when:
 * - Plugin is uninstalled then reinstalled (calendar records lost, WP posts remain)
 * - User manually generates posts via BYOK/free tier before premium trial
 * - Calendar is regenerated, orphaning previously scheduled posts
 *
 * @param array  $existing_calendar_ids Calendar item IDs from the API response.
 * @param array  $existing_wp_post_ids  WP post IDs already linked to calendar items.
 * @param string $start_date            Start date filter (Y-m-d format).
 * @param string $end_date              End date filter (Y-m-d format).
 * @return array Synthetic calendar entries for orphaned posts.
 */
function saiap_get_orphaned_posts( $existing_calendar_ids, $existing_wp_post_ids, $start_date, $end_date ) {
	// Query all ClearPost-generated posts in the date range.
	$args = array(
		'post_type'      => 'post',
		'post_status'    => array( 'draft', 'publish', 'pending', 'future' ),
		'posts_per_page' => 100, // Reasonable limit.
		'meta_key'       => '_saiap_generated',
		'meta_value'     => '1',
		'date_query'     => array(
			array(
				'after'     => $start_date,
				'before'    => $end_date,
				'inclusive' => true,
			),
		),
	);

	$posts = get_posts( $args );
	if ( empty( $posts ) ) {
		return array();
	}

	$orphaned = array();
	foreach ( $posts as $post ) {
		// Skip if this post is already linked to a calendar item via wp_post_id.
		// This handles cases where calendar was regenerated with new IDs but the
		// Supabase calendar item still tracks the correct wp_post_id.
		if ( in_array( $post->ID, $existing_wp_post_ids, true ) ) {
			continue;
		}

		$calendar_item_id = get_post_meta( $post->ID, '_saiap_calendar_item_id', true );

		// Skip if this post is linked to an existing calendar item via meta.
		if ( $calendar_item_id && in_array( $calendar_item_id, $existing_calendar_ids, true ) ) {
			continue;
		}

		// Create synthetic calendar entry for this orphaned post.
		// Use post_date for scheduled_for since we don't have the original calendar date.
		$orphaned[] = array(
			'id'            => 'orphan_' . $post->ID, // Prefix to distinguish from real IDs.
			'is_orphan'     => true,                  // Flag for frontend styling.
			'scheduled_for' => gmdate( 'Y-m-d', strtotime( $post->post_date ) ),
			'status'        => 'publish' === $post->post_status ? 'published' : 'pending_review',
			'title'         => $post->post_title,
			'wp_post_id'    => $post->ID,
			'keyword'       => array(
				'keyword' => $post->post_title, // Use title as keyword stand-in.
			),
		);
	}

	return $orphaned;
}

/**
 * AJAX handler: Get SEO calendar items.
 */
function saiap_ajax_get_calendar_items() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$start_date = isset( $_POST['start_date'] ) ? sanitize_text_field( wp_unslash( $_POST['start_date'] ) ) : gmdate( 'Y-m-d' );
	$end_date   = isset( $_POST['end_date'] ) ? sanitize_text_field( wp_unslash( $_POST['end_date'] ) ) : gmdate( 'Y-m-d', strtotime( '+30 days' ) );

	// Get calendar items from premium API.
	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$response = wp_remote_get(
		SAIAP_PREMIUM_API_URL . '/api/seo/calendar?' . http_build_query(
			array(
				'domain'      => $domain,
				'license_key' => $license_key,
				'start_date'  => $start_date,
				'end_date'    => $end_date,
			)
		),
		array(
			'timeout' => 30,
			'headers' => array(
				'Content-Type' => 'application/json',
			),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error(
			array(
				'message' => 'Failed to fetch calendar: ' . $response->get_error_message(),
			)
		);
	}

	$body = json_decode( wp_remote_retrieve_body( $response ), true );
	$code = wp_remote_retrieve_response_code( $response );

	if ( 200 !== $code ) {
		wp_send_json_error(
			array(
				'message'    => isset( $body['error'] ) ? $body['error'] : 'Failed to fetch calendar',
				'error_code' => isset( $body['error_code'] ) ? $body['error_code'] : 'unknown',
			)
		);
	}

	// Cache the calendar items count for use in dashboard widget.
	if ( isset( $body['items'] ) && is_array( $body['items'] ) ) {
		set_transient( 'saiap_calendar_items_count', count( $body['items'] ), HOUR_IN_SECONDS );

		// Use backend-provided total planned count (all planned items, not filtered by date).
		if ( isset( $body['total_planned_count'] ) ) {
			set_transient( 'saiap_planned_calendar_items_count', (int) $body['total_planned_count'], HOUR_IN_SECONDS );
		}

		if ( isset( $body['plan_cadence_cap'] ) ) {
			update_option( 'saiap_plan_cadence_cap', (int) $body['plan_cadence_cap'] );
		}

		// Enrich calendar items with local WP post IDs.
		// Look up WP posts that have matching _saiap_calendar_item_id meta.
		$calendar_ids = array_filter( array_column( $body['items'], 'id' ) );
		if ( ! empty( $calendar_ids ) ) {
			$wp_posts = get_posts(
				array(
					'post_type'      => 'post',
					'post_status'    => array( 'draft', 'publish', 'pending' ),
					'posts_per_page' => count( $calendar_ids ),
					'meta_query'     => array(
						array(
							'key'     => '_saiap_calendar_item_id',
							'value'   => $calendar_ids,
							'compare' => 'IN',
						),
					),
				)
			);

			// Build a map of calendar_item_id => wp_post_id.
			$calendar_to_wp = array();
			foreach ( $wp_posts as $wp_post ) {
				$cal_id = get_post_meta( $wp_post->ID, '_saiap_calendar_item_id', true );
				if ( $cal_id ) {
					$calendar_to_wp[ $cal_id ] = $wp_post->ID;
				}
			}

			// Add wp_post_id to matching calendar items.
			foreach ( $body['items'] as &$item ) {
				if ( isset( $item['id'] ) && isset( $calendar_to_wp[ $item['id'] ] ) ) {
					$item['wp_post_id'] = $calendar_to_wp[ $item['id'] ];
				}
			}
			unset( $item );
		}

		// Find "orphaned" posts - ClearPost-generated posts that don't have matching calendar items.
		// These can occur after reinstall, manual generation, or BYOK/free tier usage.
		// Collect wp_post_ids already linked to calendar items (from Supabase response).
		$linked_wp_post_ids = array_filter( array_map( 'intval', array_column( $body['items'], 'wp_post_id' ) ) );
		$orphaned_posts     = saiap_get_orphaned_posts( $calendar_ids, $linked_wp_post_ids, $start_date, $end_date );
		if ( ! empty( $orphaned_posts ) ) {
			$body['items'] = array_merge( $body['items'], $orphaned_posts );
		}
	}

	wp_send_json_success( $body );
}
add_action( 'wp_ajax_saiap_get_calendar_items', 'saiap_ajax_get_calendar_items' );

/**
 * AJAX handler: Clear the setup flag.
 *
 * Called when setup completes to prevent stale "in progress" state on page refresh.
 */
function saiap_ajax_clear_setup_flag() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	delete_option( 'saiap_setup_triggered_at' );

	wp_send_json_success();
}
add_action( 'wp_ajax_saiap_clear_setup_flag', 'saiap_ajax_clear_setup_flag' );

/**
 * AJAX handler: Update calendar item.
 */
function saiap_ajax_update_calendar_item() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$item_id = isset( $_POST['item_id'] ) ? sanitize_text_field( wp_unslash( $_POST['item_id'] ) ) : '';
	if ( empty( $item_id ) ) {
		wp_send_json_error( array( 'message' => 'Missing item ID' ) );
	}

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$update_data = array(
		'domain'      => $domain,
		'license_key' => $license_key,
	);

	// Collect optional update fields.
	if ( isset( $_POST['title'] ) ) {
		$update_data['title'] = sanitize_text_field( wp_unslash( $_POST['title'] ) );
	}
	if ( isset( $_POST['prompt'] ) ) {
		$update_data['prompt'] = sanitize_textarea_field( wp_unslash( $_POST['prompt'] ) );
	}
	if ( isset( $_POST['scheduled_for'] ) ) {
		$update_data['scheduled_for'] = sanitize_text_field( wp_unslash( $_POST['scheduled_for'] ) );
	}

	$response = wp_remote_request(
		SAIAP_PREMIUM_API_URL . '/api/seo/calendar/' . $item_id,
		array(
			'method'  => 'PUT',
			'timeout' => 30,
			'headers' => array(
				'Content-Type' => 'application/json',
			),
			'body'    => wp_json_encode( $update_data ),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error( array( 'message' => $response->get_error_message() ) );
	}

	$body = json_decode( wp_remote_retrieve_body( $response ), true );
	$code = wp_remote_retrieve_response_code( $response );

	if ( 200 !== $code ) {
		wp_send_json_error(
			array(
				'message' => isset( $body['error'] ) ? $body['error'] : 'Failed to update item',
			)
		);
	}

	wp_send_json_success( $body );
}
add_action( 'wp_ajax_saiap_update_calendar_item', 'saiap_ajax_update_calendar_item' );

/**
 * AJAX handler: Replace calendar item with a different keyword.
 *
 * Archives the current keyword, picks a new one (preferring different location),
 * and creates a new calendar item for the same date.
 */
function saiap_ajax_replace_calendar_item() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$item_id = isset( $_POST['item_id'] ) ? sanitize_text_field( wp_unslash( $_POST['item_id'] ) ) : '';
	if ( empty( $item_id ) ) {
		wp_send_json_error( array( 'message' => 'Missing item ID' ) );
	}

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$response = wp_remote_post(
		SAIAP_PREMIUM_API_URL . '/api/seo/calendar/' . $item_id . '/replace',
		array(
			'timeout' => 60, // AI generation can take time
			'headers' => array(
				'Content-Type' => 'application/json',
			),
			'body'    => wp_json_encode(
				array(
					'domain'      => $domain,
					'license_key' => $license_key,
				)
			),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error( array( 'message' => $response->get_error_message() ) );
	}

	$body = json_decode( wp_remote_retrieve_body( $response ), true );
	$code = wp_remote_retrieve_response_code( $response );

	if ( 200 !== $code ) {
		wp_send_json_error(
			array(
				'message' => isset( $body['error'] ) ? $body['error'] : 'Failed to replace item',
			)
		);
	}

	wp_send_json_success( $body );
}
add_action( 'wp_ajax_saiap_replace_calendar_item', 'saiap_ajax_replace_calendar_item' );

/**
 * AJAX handler: Generate post from calendar item.
 */
/**
 * AJAX handler: Start async content generation from calendar item.
 * Returns job_id and stream_url for SSE connection.
 */
function saiap_ajax_generate_from_calendar() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$item_id       = isset( $_POST['item_id'] ) ? sanitize_text_field( wp_unslash( $_POST['item_id'] ) ) : '';
	$prompt        = isset( $_POST['prompt'] ) ? sanitize_textarea_field( wp_unslash( $_POST['prompt'] ) ) : '';
	$content_brief = isset( $_POST['content_brief'] ) ? sanitize_textarea_field( wp_unslash( $_POST['content_brief'] ) ) : '';
	$title         = isset( $_POST['title'] ) ? sanitize_text_field( wp_unslash( $_POST['title'] ) ) : '';

	if ( empty( $item_id ) || empty( $prompt ) ) {
		wp_send_json_error( array( 'message' => 'Missing required fields' ), 400 );
	}

	// Get provider and model settings.
	$provider    = get_option( 'saiap_default_provider', 'openai' );
	$model       = get_option( "saiap_{$provider}_model" );
	$license_key = get_option( 'saiap_license_key', '' );
	$domain      = saiap_get_server_host();

	// Build request data for async generation.
	$request_data = array(
		'model'         => $model,
		'provider'      => $provider,
		'license_key'   => $license_key,
		'domain'        => $domain,
		'content_brief' => $content_brief,
		'messages'      => array(
			array(
				'role'    => 'system',
				'content' => saiap_get_system_prompt(),
			),
			array(
				'role'    => 'user',
				'content' => $prompt,
			),
		),
	);

	// Call async generation endpoint.
	$response = wp_remote_post(
		SAIAP_PREMIUM_API_URL . '/api/generate/async',
		array(
			'headers' => array( 'Content-Type' => 'application/json' ),
			'body'    => wp_json_encode( $request_data ),
			'timeout' => 30, // Just need to start the job.
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error( array( 'message' => $response->get_error_message() ), 500 );
	}

	$body = wp_remote_retrieve_body( $response );
	$data = json_decode( $body, true );

	if ( ! isset( $data['job_id'] ) ) {
		$error_msg = isset( $data['error'] ) ? $data['error'] : 'Failed to start generation';
		wp_send_json_error( array( 'message' => $error_msg ), 500 );
	}

	// Construct stream URL using the premium API URL that the browser can access.
	// Transform host.docker.internal to localhost for local development.
	$browser_api_url = str_replace( 'host.docker.internal', 'localhost', SAIAP_PREMIUM_API_URL );
	$stream_url      = $browser_api_url . '/api/generate/stream/' . $data['job_id'];

	// Return job info - JS will connect to stream.
	wp_send_json_success(
		array(
			'job_id'     => $data['job_id'],
			'stream_url' => $stream_url,
			'item_id'    => $item_id,
			'title'      => $title,
		)
	);
}
add_action( 'wp_ajax_saiap_generate_from_calendar', 'saiap_ajax_generate_from_calendar' );

/**
 * AJAX handler: Proxy GSC connection status to the premium backend.
 * Browsers can't call the backend directly (cross-origin), so the plugin
 * proxies the request server-side and forwards the license key for auth.
 */
function saiap_ajax_gsc_status() {
	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}
	check_ajax_referer( 'saiap_gsc_nonce', '_wpnonce' );

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$url      = SAIAP_PREMIUM_API_URL . '/api/gsc/status?' . http_build_query( array( 'domain' => $domain ) );
	$response = wp_remote_get(
		$url,
		array(
			'timeout' => 10,
			'headers' => array( 'X-License-Key' => $license_key ),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json( array( 'connected' => false ) );
	}

	$data = json_decode( wp_remote_retrieve_body( $response ), true );
	wp_send_json( is_array( $data ) ? $data : array( 'connected' => false ) );
}
add_action( 'wp_ajax_saiap_gsc_status', 'saiap_ajax_gsc_status' );

/**
 * AJAX handler: Proxy GSC daily chart data to the premium backend.
 */
function saiap_ajax_gsc_chart() {
	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}
	check_ajax_referer( 'saiap_gsc_nonce', '_wpnonce' );

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );
	$days        = isset( $_GET['days'] ) ? max( 1, min( 90, intval( wp_unslash( $_GET['days'] ) ) ) ) : 28;

	$url      = SAIAP_PREMIUM_API_URL . '/api/gsc/chart?' . http_build_query(
		array(
			'domain' => $domain,
			'days'   => $days,
		)
	);
	$response = wp_remote_get(
		$url,
		array(
			'timeout' => 15,
			'headers' => array( 'X-License-Key' => $license_key ),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json( array( 'connected' => false ) );
	}

	$data = json_decode( wp_remote_retrieve_body( $response ), true );
	wp_send_json( is_array( $data ) ? $data : array( 'connected' => false ) );
}
add_action( 'wp_ajax_saiap_gsc_chart', 'saiap_ajax_gsc_chart' );

/**
 * AJAX handler: Proxy GSC disconnect to the premium backend.
 */
function saiap_ajax_gsc_disconnect() {
	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}
	check_ajax_referer( 'saiap_gsc_nonce', '_wpnonce' );

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$url      = SAIAP_PREMIUM_API_URL . '/api/gsc/disconnect?' . http_build_query( array( 'domain' => $domain ) );
	$response = wp_remote_request(
		$url,
		array(
			'method'  => 'DELETE',
			'timeout' => 10,
			'headers' => array( 'X-License-Key' => $license_key ),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error( array( 'message' => 'Failed to disconnect' ), 500 );
	}

	$data = json_decode( wp_remote_retrieve_body( $response ), true );
	wp_send_json( is_array( $data ) ? $data : array( 'success' => true ) );
}
add_action( 'wp_ajax_saiap_gsc_disconnect', 'saiap_ajax_gsc_disconnect' );

/**
 * AJAX handler: Create WP post from async-generated content.
 * Called by JS after SSE stream completes with generated content.
 */
function saiap_ajax_create_calendar_post() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$item_id = isset( $_POST['item_id'] ) ? sanitize_text_field( wp_unslash( $_POST['item_id'] ) ) : '';
	$title   = isset( $_POST['title'] ) ? sanitize_text_field( wp_unslash( $_POST['title'] ) ) : '';
	$content = isset( $_POST['content'] ) ? wp_kses_post( wp_unslash( $_POST['content'] ) ) : '';
	$link    = isset( $_POST['link'] ) ? esc_url_raw( wp_unslash( $_POST['link'] ) ) : '';
	// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- linkTitle can contain special chars.
	$link_title          = isset( $_POST['linkTitle'] ) ? sanitize_text_field( wp_unslash( $_POST['linkTitle'] ) ) : '';
	$inline_image_tasks  = isset( $_POST['inline_image_tasks'] ) ? json_decode( wp_unslash( $_POST['inline_image_tasks'] ), true ) : array();
	$session_id          = isset( $_POST['session_id'] ) ? sanitize_text_field( wp_unslash( $_POST['session_id'] ) ) : '';

	if ( empty( $item_id ) || empty( $content ) ) {
		wp_send_json_error( array( 'message' => 'Missing required fields' ), 400 );
	}

	// Get provider and model for tracking.
	$provider  = get_option( 'saiap_default_provider', 'openai' );
	$model     = get_option( "saiap_{$provider}_model" );
	$post_type = get_option( 'saiap_post_type', 'post' );

	// Prepare content.
	$prepared_content = saiap_prepare_post_content( $content );

	// Determine post status based on "Review first" setting.
	$review_first = get_option( 'saiap_review_before_publish', false );
	$post_status  = $review_first ? 'draft' : 'publish';

	// Create post.
	$post_data = array(
		'post_title'   => $title,
		'post_content' => $prepared_content,
		'post_status'  => $post_status,
		'post_type'    => $post_type,
	);

	$post_id = wp_insert_post( $post_data );

	if ( is_wp_error( $post_id ) ) {
		wp_send_json_error( array( 'message' => $post_id->get_error_message() ), 500 );
	}

	// Mark post as generated by ClearPost.
	update_post_meta( $post_id, '_saiap_generated', true );
	update_post_meta( $post_id, '_saiap_generated_at', current_time( 'mysql' ) );

	// Link calendar item to WP post.
	update_post_meta( $post_id, '_saiap_calendar_item_id', $item_id );

	// Track post generation.
	saiap_track_post_generation( $provider, $model, $post_type, array() );

	// Handle custom fields (ACF link field).
	if ( ! empty( $link ) && function_exists( 'update_field' ) ) {
		$link_field_name = get_option( 'saiap_link_field_name', '' );

		if ( ! empty( $link_field_name ) ) {
			if ( strpos( $link_field_name, '|' ) !== false ) {
				list($repeater_name, $subfield_name) = explode( '|', $link_field_name );
				$rows   = get_field( $repeater_name, $post_id ) ?: array();
				$rows[] = array(
					$subfield_name => array(
						'title'  => $link_title,
						'url'    => $link,
						'target' => '',
					),
				);
				update_field( $repeater_name, $rows, $post_id );
			} else {
				update_field( $link_field_name, $link, $post_id );
			}
		}
	}

	// Apply automatic taxonomy.
	saiap_edit_post_taxonomy( $post_id );

	// Image handling: Use agentic pipeline if session_id available, otherwise fall back to legacy.
	if ( ! empty( $session_id ) && function_exists( 'saiap_trigger_image_agent' ) ) {
		// Agentic image pipeline - call image agent with session continuation.
		update_post_meta( $post_id, '_saiap_image_agent_status', 'queued' );
		saiap_trigger_image_agent( $post_id, $session_id );
	} else {
		// Legacy: Queue inline image insertion if tasks available.
		if ( ! empty( $inline_image_tasks ) && is_array( $inline_image_tasks ) && function_exists( 'saiap_trigger_inline_images_async' ) ) {
			update_post_meta( $post_id, '_saiap_inline_images_tasks_v1', wp_json_encode( $inline_image_tasks ) );
			update_post_meta( $post_id, '_saiap_inline_images_status', 'queued' );
			saiap_trigger_inline_images_async( $post_id );
		}

		// Legacy: Auto-attach featured image.
		try {
			$has_thumbnail = has_post_thumbnail( $post_id );
			if ( ! $has_thumbnail && function_exists( 'saiap_attach_first_image_result' ) ) {
				$search_query = get_the_title( $post_id );
				$attach_res   = saiap_attach_first_image_result( $post_id, $search_query );
				if ( is_int( $attach_res ) && $attach_res > 0 ) {
					do_action( 'saiap_auto_image_attached', $post_id, $attach_res );
				} elseif ( is_wp_error( $attach_res ) ) {
					do_action( 'saiap_auto_image_failed', $post_id, $attach_res );
				}
			}
		} catch ( Exception $e ) {
			do_action( 'saiap_auto_image_failed', $post_id, new WP_Error( 'auto_image_exception', $e->getMessage() ) );
		}
	}

	// Update calendar item status in backend.
	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );
	$new_status  = 'publish' === $post_status ? 'published' : 'pending_review';

	wp_remote_request(
		SAIAP_PREMIUM_API_URL . '/api/seo/calendar/' . $item_id,
		array(
			'method'  => 'PUT',
			'timeout' => 30,
			'headers' => array( 'Content-Type' => 'application/json' ),
			'body'    => wp_json_encode(
				array(
					'domain'      => $domain,
					'license_key' => $license_key,
					'status'      => $new_status,
					'wp_post_id'  => $post_id,
				)
			),
		)
	);

	// Mark premium onboarding step complete.
	if ( function_exists( 'saiap_premium_onboarding_mark_step_complete' ) ) {
		saiap_premium_onboarding_mark_step_complete( 2 );
	}

	wp_send_json_success(
		array(
			'post_id'     => $post_id,
			'edit_url'    => get_edit_post_link( $post_id, 'raw' ),
			'post_status' => $post_status,
		)
	);
}
add_action( 'wp_ajax_saiap_create_calendar_post', 'saiap_ajax_create_calendar_post' );

/**
 * AJAX handler: Save autopilot settings.
 */
function saiap_ajax_save_autopilot_settings() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$settings = array(
		'domain'      => $domain,
		'license_key' => $license_key,
	);

	if ( isset( $_POST['autopilot_enabled'] ) ) {
		$settings['autopilot_enabled'] = ( 'true' === $_POST['autopilot_enabled'] || '1' === $_POST['autopilot_enabled'] );
		update_option( 'saiap_autopilot_enabled', $settings['autopilot_enabled'] );
	}
	if ( isset( $_POST['posts_per_week'] ) ) {
		$settings['posts_per_week'] = absint( $_POST['posts_per_week'] );
		update_option( 'saiap_posts_per_week', $settings['posts_per_week'] );
	}
	if ( isset( $_POST['review_before_publish'] ) ) {
		$settings['review_before_publish'] = ( 'true' === $_POST['review_before_publish'] || '1' === $_POST['review_before_publish'] );
		update_option( 'saiap_review_before_publish', $settings['review_before_publish'] );
	}
	if ( isset( $_POST['model'] ) ) {
		$model_value = sanitize_text_field( wp_unslash( $_POST['model'] ) );
		// Format: "provider:model_id" (e.g., "anthropic:claude-opus-4-5").
		if ( strpos( $model_value, ':' ) !== false ) {
			list( $provider, $model ) = explode( ':', $model_value, 2 );
			$allowed_providers = array( 'openai', 'anthropic', 'gemini' );
			if ( in_array( $provider, $allowed_providers, true ) ) {
				update_option( 'saiap_default_provider', $provider );
				update_option( "saiap_{$provider}_model", $model );
			}
		}
	}

	// Send to premium API.
	$response = wp_remote_request(
		SAIAP_PREMIUM_API_URL . '/api/seo/settings',
		array(
			'method'  => 'PUT',
			'timeout' => 30,
			'headers' => array(
				'Content-Type' => 'application/json',
			),
			'body'    => wp_json_encode( $settings ),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error( array( 'message' => $response->get_error_message() ) );
	}

	$body = json_decode( wp_remote_retrieve_body( $response ), true );
	$code = wp_remote_retrieve_response_code( $response );

	if ( 200 !== $code ) {
		// Still save locally even if remote fails.
		wp_send_json_success(
			array(
				'message'  => 'Settings saved locally',
				'settings' => $settings,
			)
		);
	}

	// Store plan cadence cap from backend so the dropdown can be limited on next load.
	if ( isset( $body['plan_cadence_cap'] ) && is_numeric( $body['plan_cadence_cap'] ) ) {
		update_option( 'saiap_plan_cadence_cap', absint( $body['plan_cadence_cap'] ) );
	}

	wp_send_json_success( $body );
}
add_action( 'wp_ajax_saiap_save_autopilot_settings', 'saiap_ajax_save_autopilot_settings' );

// =============================================================================
// Rank Tracking AJAX Handlers
// =============================================================================

/**
 * AJAX handler: Get tracked keywords with rank data.
 */
function saiap_ajax_get_tracked_keywords() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$response = wp_remote_get(
		SAIAP_PREMIUM_API_URL . '/api/seo/ranks?' . http_build_query(
			array(
				'domain'      => $domain,
				'license_key' => $license_key,
			)
		),
		array(
			'timeout' => 30,
			'headers' => array(
				'Content-Type' => 'application/json',
			),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error( array( 'message' => $response->get_error_message() ) );
	}

	$body = json_decode( wp_remote_retrieve_body( $response ), true );
	$code = wp_remote_retrieve_response_code( $response );

	if ( 200 !== $code ) {
		wp_send_json_error(
			array(
				'message' => isset( $body['error'] ) ? $body['error'] : 'Failed to fetch tracked keywords',
			)
		);
	}

	wp_send_json_success( $body );
}
add_action( 'wp_ajax_saiap_get_tracked_keywords', 'saiap_ajax_get_tracked_keywords' );

/**
 * AJAX handler: Toggle keyword tracking.
 */
function saiap_ajax_toggle_keyword_tracking() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$keyword_id = isset( $_POST['keyword_id'] ) ? sanitize_text_field( wp_unslash( $_POST['keyword_id'] ) ) : '';
	$enabled    = isset( $_POST['enabled'] ) && ( 'true' === $_POST['enabled'] || '1' === $_POST['enabled'] );

	if ( empty( $keyword_id ) ) {
		wp_send_json_error( array( 'message' => 'Missing keyword ID' ) );
	}

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$response = wp_remote_request(
		SAIAP_PREMIUM_API_URL . '/api/seo/keywords/' . $keyword_id . '/tracking',
		array(
			'method'  => 'PUT',
			'timeout' => 30,
			'headers' => array(
				'Content-Type' => 'application/json',
			),
			'body'    => wp_json_encode(
				array(
					'domain'      => $domain,
					'license_key' => $license_key,
					'enabled'     => $enabled,
				)
			),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error( array( 'message' => $response->get_error_message() ) );
	}

	$body = json_decode( wp_remote_retrieve_body( $response ), true );
	$code = wp_remote_retrieve_response_code( $response );

	if ( 200 !== $code ) {
		wp_send_json_error(
			array(
				'message' => isset( $body['error'] ) ? $body['error'] : 'Failed to update tracking',
			)
		);
	}

	wp_send_json_success( $body );
}
add_action( 'wp_ajax_saiap_toggle_keyword_tracking', 'saiap_ajax_toggle_keyword_tracking' );

/**
 * AJAX handler: Get rank history for sparkline.
 */
function saiap_ajax_get_rank_history() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$keyword_id = isset( $_POST['keyword_id'] ) ? sanitize_text_field( wp_unslash( $_POST['keyword_id'] ) ) : '';
	$days       = isset( $_POST['days'] ) ? absint( $_POST['days'] ) : 30;

	if ( empty( $keyword_id ) ) {
		wp_send_json_error( array( 'message' => 'Missing keyword ID' ) );
	}

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$response = wp_remote_get(
		SAIAP_PREMIUM_API_URL . '/api/seo/ranks/' . $keyword_id . '/history?' . http_build_query(
			array(
				'domain'      => $domain,
				'license_key' => $license_key,
				'days'        => $days,
			)
		),
		array(
			'timeout' => 30,
			'headers' => array(
				'Content-Type' => 'application/json',
			),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error( array( 'message' => $response->get_error_message() ) );
	}

	$body = json_decode( wp_remote_retrieve_body( $response ), true );
	$code = wp_remote_retrieve_response_code( $response );

	if ( 200 !== $code ) {
		wp_send_json_error(
			array(
				'message' => isset( $body['error'] ) ? $body['error'] : 'Failed to fetch rank history',
			)
		);
	}

	wp_send_json_success( $body );
}
add_action( 'wp_ajax_saiap_get_rank_history', 'saiap_ajax_get_rank_history' );

/**
 * AJAX handler: Manual rank check.
 */
function saiap_ajax_manual_rank_check() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$response = wp_remote_post(
		SAIAP_PREMIUM_API_URL . '/api/seo/ranks/check',
		array(
			'timeout' => 120, // Rank checking can take time.
			'headers' => array(
				'Content-Type' => 'application/json',
			),
			'body'    => wp_json_encode(
				array(
					'domain'      => $domain,
					'license_key' => $license_key,
				)
			),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error( array( 'message' => $response->get_error_message() ) );
	}

	$body = json_decode( wp_remote_retrieve_body( $response ), true );
	$code = wp_remote_retrieve_response_code( $response );

	if ( 200 !== $code ) {
		wp_send_json_error(
			array(
				'message' => isset( $body['error'] ) ? $body['error'] : 'Failed to check ranks',
			)
		);
	}

	wp_send_json_success( $body );
}
add_action( 'wp_ajax_saiap_manual_rank_check', 'saiap_ajax_manual_rank_check' );

/**
 * AJAX handler: Get untracked keywords for the Add Keyword modal.
 */
function saiap_ajax_get_untracked_keywords() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$response = wp_remote_get(
		add_query_arg(
			array(
				'domain'      => $domain,
				'license_key' => $license_key,
				'tracked'     => 'false',
			),
			SAIAP_PREMIUM_API_URL . '/api/seo/keywords'
		),
		array(
			'timeout' => 30,
			'headers' => array(
				'Content-Type' => 'application/json',
			),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error( array( 'message' => $response->get_error_message() ) );
	}

	$body = json_decode( wp_remote_retrieve_body( $response ), true );
	$code = wp_remote_retrieve_response_code( $response );

	if ( 200 !== $code ) {
		wp_send_json_error(
			array(
				'message' => isset( $body['error'] ) ? $body['error'] : 'Failed to fetch keywords',
			)
		);
	}

	wp_send_json_success( $body );
}
add_action( 'wp_ajax_saiap_get_untracked_keywords', 'saiap_ajax_get_untracked_keywords' );

/**
 * AJAX handler: Add a keyword to tracking.
 *
 * Handles both existing keywords (set is_tracked=true) and new keywords (insert + track).
 */
function saiap_ajax_add_tracked_keyword() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );
	$is_new      = isset( $_POST['is_new'] ) && 'true' === $_POST['is_new'];

	$request_body = array(
		'domain'      => $domain,
		'license_key' => $license_key,
		'is_new'      => $is_new,
	);

	if ( $is_new ) {
		$keyword_text = isset( $_POST['keyword_text'] ) ? sanitize_text_field( wp_unslash( $_POST['keyword_text'] ) ) : '';
		if ( empty( $keyword_text ) ) {
			wp_send_json_error( array( 'message' => 'Keyword text is required' ) );
		}
		$request_body['keyword'] = $keyword_text;
	} else {
		$keyword_id = isset( $_POST['keyword_id'] ) ? sanitize_text_field( wp_unslash( $_POST['keyword_id'] ) ) : '';
		if ( empty( $keyword_id ) ) {
			wp_send_json_error( array( 'message' => 'Keyword ID is required' ) );
		}
		$request_body['keyword_id'] = $keyword_id;
	}

	$response = wp_remote_post(
		SAIAP_PREMIUM_API_URL . '/api/seo/keywords/track',
		array(
			'timeout' => 30,
			'headers' => array(
				'Content-Type' => 'application/json',
			),
			'body'    => wp_json_encode( $request_body ),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error( array( 'message' => $response->get_error_message() ) );
	}

	$body = json_decode( wp_remote_retrieve_body( $response ), true );
	$code = wp_remote_retrieve_response_code( $response );

	if ( 200 !== $code && 201 !== $code ) {
		wp_send_json_error(
			array(
				'message' => isset( $body['error'] ) ? $body['error'] : 'Failed to add keyword',
			)
		);
	}

	wp_send_json_success( $body );
}
add_action( 'wp_ajax_saiap_add_tracked_keyword', 'saiap_ajax_add_tracked_keyword' );

/**
 * AJAX handler: Regenerate calendar.
 *
 * Deletes all 'planned' calendar items and regenerates with latest pipeline logic.
 * Items in other statuses (pending_review, completed, etc.) are preserved.
 */
function saiap_ajax_regenerate_calendar() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$request_data = array(
		'domain'      => $domain,
		'license_key' => $license_key,
		'days'        => 30,
	);

	// Optional parameters.
	if ( isset( $_POST['start_date'] ) ) {
		$request_data['start_date'] = sanitize_text_field( wp_unslash( $_POST['start_date'] ) );
	}
	if ( isset( $_POST['posts_per_week'] ) ) {
		$request_data['posts_per_week'] = absint( $_POST['posts_per_week'] );
	}

	$response = wp_remote_post(
		SAIAP_PREMIUM_API_URL . '/api/seo/calendar/regenerate',
		array(
			'timeout' => 120, // Longer timeout for regeneration.
			'headers' => array(
				'Content-Type' => 'application/json',
			),
			'body'    => wp_json_encode( $request_data ),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error(
			array(
				'message' => 'Failed to regenerate calendar: ' . $response->get_error_message(),
			)
		);
	}

	$body = json_decode( wp_remote_retrieve_body( $response ), true );
	$code = wp_remote_retrieve_response_code( $response );

	if ( 200 !== $code ) {
		wp_send_json_error(
			array(
				'message'    => isset( $body['error'] ) ? $body['error'] : 'Failed to regenerate calendar',
				'error_code' => isset( $body['error_code'] ) ? $body['error_code'] : 'unknown',
			)
		);
	}

	// Update the calendar items count cache.
	if ( isset( $body['items'] ) && is_array( $body['items'] ) ) {
		set_transient( 'saiap_calendar_items_count', count( $body['items'] ), HOUR_IN_SECONDS );
	}

	// Update the planned count cache from backend response.
	if ( isset( $body['total_planned_count'] ) ) {
		set_transient( 'saiap_planned_calendar_items_count', (int) $body['total_planned_count'], HOUR_IN_SECONDS );
	}

	wp_send_json_success( $body );
}
add_action( 'wp_ajax_saiap_regenerate_calendar', 'saiap_ajax_regenerate_calendar' );

/**
 * AJAX handler: Re-run SEO pipeline from scratch.
 *
 * Archives all keywords, deletes planned calendar items, and re-runs the full
 * strategy session → keyword research → classification → calendar pipeline.
 */
function saiap_ajax_rerun_pipeline() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
	}

	$domain      = saiap_get_server_host();
	$license_key = get_option( 'saiap_license_key', '' );

	$request_data = array(
		'domain'      => $domain,
		'license_key' => $license_key,
	);

	$response = wp_remote_post(
		SAIAP_PREMIUM_API_URL . '/api/seo/pipeline/rerun',
		array(
			'timeout' => 600, // 10 minute timeout — full pipeline takes a while.
			'headers' => array(
				'Content-Type' => 'application/json',
			),
			'body'    => wp_json_encode( $request_data ),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error(
			array(
				'message' => 'Failed to re-run pipeline: ' . $response->get_error_message(),
			)
		);
	}

	$body = json_decode( wp_remote_retrieve_body( $response ), true );
	$code = wp_remote_retrieve_response_code( $response );

	if ( 200 !== $code ) {
		wp_send_json_error(
			array(
				'message'    => isset( $body['error'] ) ? $body['error'] : 'Failed to re-run pipeline',
				'error_code' => isset( $body['error_code'] ) ? $body['error_code'] : 'unknown',
			)
		);
	}

	// Update caches.
	if ( isset( $body['items'] ) && is_array( $body['items'] ) ) {
		set_transient( 'saiap_calendar_items_count', count( $body['items'] ), HOUR_IN_SECONDS );
	}
	if ( isset( $body['total_planned_count'] ) ) {
		set_transient( 'saiap_planned_calendar_items_count', (int) $body['total_planned_count'], HOUR_IN_SECONDS );
	}

	wp_send_json_success( $body );
}
add_action( 'wp_ajax_saiap_rerun_pipeline', 'saiap_ajax_rerun_pipeline' );

