<?php
/**
 * Trial State Detection and Management
 *
 * This file contains all functions related to trial state management.
 * The architecture follows a client-optimistic, server-authoritative pattern:
 * - Local state (wp_options) is used for fast UI rendering
 * - Server validates on actual feature use
 * - Server responses sync back to local state
 *
 * @package Simple_AI_Auto_Post
 * @since 2.5.0
 */

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

/**
 * Get the current trial status from local state.
 *
 * @return string One of: 'none', 'active', 'expired'
 */
function saiap_get_trial_status() {
	return get_option( 'saiap_trial_status', 'none' );
}

/**
 * Check if the trial is currently active (within the 7-day window).
 *
 * Note: This reads local state only. Call saiap_maybe_expire_trial() once
 * per request before using this function to ensure status is current.
 *
 * @return bool True if trial is active and within the 7-day window.
 */
function saiap_is_trial_active() {
	$trial_status = get_option( 'saiap_trial_status', 'none' );
	if ( 'active' !== $trial_status ) {
		return false;
	}

	// Use server-provided expires_at if available.
	$trial_expires = get_option( 'saiap_trial_expires_at', '' );
	if ( ! empty( $trial_expires ) ) {
		return time() < strtotime( $trial_expires );
	}

	// Fallback: calculate from started_at + 7 days (backwards compatibility).
	$trial_started = get_option( 'saiap_trial_started_at', 0 );
	if ( empty( $trial_started ) ) {
		return false;
	}

	$trial_end = strtotime( $trial_started ) + ( 7 * DAY_IN_SECONDS );
	return time() < $trial_end;
}

/**
 * Check if the user needs to complete the onboarding wizard.
 *
 * Returns true when:
 * 1. Trial is active (has license key and valid trial)
 * 2. No wizard data has been saved yet
 * 3. Setup hasn't been triggered
 *
 * This handles the post-checkout flow where users enter a license key
 * but haven't gone through the wizard yet.
 *
 * @return bool True if wizard should be shown.
 */
function saiap_needs_onboarding_wizard() {
	// Must have an active trial or license
	$trial_status = get_option( 'saiap_trial_status', 'none' );
	$license_key  = get_option( 'saiap_license_key', '' );

	if ( 'active' !== $trial_status && empty( $license_key ) ) {
		return false;
	}

	// Check if wizard data already exists
	$web_wizard_data    = get_option( 'saiap_web_wizard_data', null );
	$plugin_wizard_data = get_option( 'saiap_onboarding_wizard_data', null );

	if ( ! empty( $web_wizard_data ) || ! empty( $plugin_wizard_data ) ) {
		return false;
	}

	// Check if setup has already been triggered
	$setup_triggered = get_option( 'saiap_setup_triggered_at', '' );
	if ( ! empty( $setup_triggered ) ) {
		return false;
	}

	return true;
}

/**
 * Get the number of days remaining in the trial.
 *
 * Uses server-provided expires_at if available, otherwise falls back
 * to calculating from started_at + 7 days for backwards compatibility.
 *
 * @return int Days remaining. Returns 0 if no active trial.
 */
function saiap_get_trial_days_remaining() {
	// Use server-provided expires_at if available.
	$trial_expires = get_option( 'saiap_trial_expires_at', '' );
	if ( ! empty( $trial_expires ) ) {
		$remaining = strtotime( $trial_expires ) - time();
		return max( 0, ceil( $remaining / DAY_IN_SECONDS ) );
	}

	// Fallback: calculate from started_at + 7 days (backwards compatibility).
	$trial_started = get_option( 'saiap_trial_started_at', '' );
	if ( empty( $trial_started ) ) {
		return 0;
	}

	$trial_end = strtotime( $trial_started ) + ( 7 * DAY_IN_SECONDS );
	$remaining = $trial_end - time();
	return max( 0, ceil( $remaining / DAY_IN_SECONDS ) );
}

/**
 * Get the total number of days in the trial period.
 *
 * Calculates from started_at to expires_at. Returns 7 if dates not available.
 *
 * @return int Total trial days.
 */
function saiap_get_trial_total_days() {
	$trial_started = get_option( 'saiap_trial_started_at', '' );
	$trial_expires = get_option( 'saiap_trial_expires_at', '' );

	if ( ! empty( $trial_started ) && ! empty( $trial_expires ) ) {
		$total = strtotime( $trial_expires ) - strtotime( $trial_started );
		return max( 1, ceil( $total / DAY_IN_SECONDS ) );
	}

	// Default to 7 days if we can't calculate.
	return 7;
}

/**
 * Get the trial expiration date.
 *
 * @return string|null ISO 8601 formatted expiration date, or null if no trial.
 */
function saiap_get_trial_expires_at() {
	// Use server-provided expires_at if available.
	$trial_expires = get_option( 'saiap_trial_expires_at', '' );
	if ( ! empty( $trial_expires ) ) {
		return $trial_expires;
	}

	// Fallback: calculate from started_at + 7 days (backwards compatibility).
	$trial_started = get_option( 'saiap_trial_started_at', '' );
	if ( empty( $trial_started ) ) {
		return null;
	}

	$trial_end = strtotime( $trial_started ) + ( 7 * DAY_IN_SECONDS );
	return gmdate( 'c', $trial_end );
}

/**
 * Check if the user is eligible to start a trial.
 *
 * A user can start a trial if:
 * - They don't have a license key (not paid)
 * - They haven't already started or completed a trial
 *
 * @return bool True if eligible to start trial.
 */
function saiap_can_start_trial() {
	// Already has a license key - no need for trial.
	$license_key = get_option( 'saiap_license_key', '' );
	if ( ! empty( $license_key ) ) {
		return false;
	}

	// Check if trial has ever been started.
	$trial_status = get_option( 'saiap_trial_status', 'none' );
	return 'none' === $trial_status;
}

/**
 * Check if trial needs to be marked as expired and update if so.
 *
 * This is the ONLY function that modifies trial state based on time.
 * It performs "self-healing" by checking the time and updating status.
 *
 * Should be called once per request (e.g., on admin_init) before reading scenario.
 *
 * @return bool True if trial was expired during this call, false otherwise.
 */
function saiap_maybe_expire_trial() {
	$trial_status = get_option( 'saiap_trial_status', 'none' );

	if ( 'active' === $trial_status && ! saiap_is_trial_active() ) {
		// Trial period has passed - update status.
		update_option( 'saiap_trial_status', 'expired' );
		return true;
	}

	return false;
}

/**
 * Sync trial state from server if needed (throttled).
 *
 * Called on Dashboard tab load to keep trial expiration date fresh.
 * Syncs for active trial users and expired trial users with a license key
 * (who may have upgraded). Throttled to once per hour.
 *
 * Use ?refresh_trial=1 query param to force a sync (bypasses throttle).
 */
function saiap_maybe_sync_trial_state() {
	$trial_status = get_option( 'saiap_trial_status', 'none' );
	$license_key  = get_option( 'saiap_license_key', '' );

	// Sync for active trial users OR expired trial users with a license key
	// (they may have upgraded and need to sync their paid status).
	$should_sync = 'active' === $trial_status
		|| ( 'expired' === $trial_status && ! empty( $license_key ) );

	if ( ! $should_sync ) {
		return;
	}

	// Check for force refresh parameter.
	// phpcs:ignore WordPress.Security.NonceVerification.Recommended
	$force_refresh = isset( $_GET['refresh_trial'] ) && '1' === $_GET['refresh_trial'];

	// Expired trial with license key = possible conversion. Always sync immediately.
	// This detects when user paid and their license is now valid.
	$is_possible_conversion = 'expired' === $trial_status && ! empty( $license_key );

	// Throttle to once per hour (unless forced or possible conversion).
	if ( ! $force_refresh && ! $is_possible_conversion ) {
		$last_sync = get_transient( 'saiap_trial_last_sync' );
		if ( $last_sync ) {
			return;
		}
	}

	// Mark sync time (1 hour TTL).
	set_transient( 'saiap_trial_last_sync', time(), HOUR_IN_SECONDS );

	// Fire-and-forget validation to sync trial state.
	saiap_validate_premium_access();
}

/**
 * Determine the current user scenario based on LOCAL STATE ONLY.
 *
 * IMPORTANT: This is a PURE GETTER - it makes no database writes and no API calls.
 * Call saiap_maybe_expire_trial() once per request before using this function
 * to ensure trial status is current.
 *
 * Scenarios:
 * - 'paid': User has a license key (optimistic assumption it's valid)
 * - 'active_trial': User has an active trial within 7-day window
 * - 'expired_trial': User had a trial that has expired
 * - 'no_trial_has_keys': No trial, but user has set up their own API keys
 * - 'no_trial_no_keys': No trial, no API keys (new user or never configured)
 *
 * @return string One of: 'paid', 'active_trial', 'expired_trial', 'no_trial_has_keys', 'no_trial_no_keys'
 */
function saiap_get_user_scenario() {
	$trial_status = get_option( 'saiap_trial_status', 'none' );
	$license_key  = get_option( 'saiap_license_key', '' );

	// Check trial status FIRST - trial users have license keys for API auth.
	if ( 'active' === $trial_status ) {
		return 'active_trial';
	}

	if ( 'expired' === $trial_status ) {
		return 'expired_trial';
	}

	// No active/expired trial - license key means paid.
	if ( ! empty( $license_key ) ) {
		return 'paid';
	}

	// No trial, no license - check for BYOK API keys.
	$has_api_keys = ! empty( get_option( 'saiap_openai_api_key', '' ) )
				|| ! empty( get_option( 'saiap_anthropic_api_key', '' ) )
				|| ! empty( get_option( 'saiap_gemini_api_key', '' ) );

	return $has_api_keys ? 'no_trial_has_keys' : 'no_trial_no_keys';
}

/**
 * Check if the user has premium access (either paid license or active trial).
 *
 * This is a convenience function for feature gating.
 *
 * @return bool True if user has premium access.
 */
function saiap_has_premium_access() {
	$scenario = saiap_get_user_scenario();
	return in_array( $scenario, array( 'paid', 'active_trial' ), true );
}

/**
 * Handle premium API responses and sync local state with server truth.
 *
 * Call this after every premium API call (generate, context update, etc.)
 * to ensure local state stays in sync with server state.
 *
 * @param array|WP_Error $response The response from a premium API call.
 * @return array|WP_Error The original response (unchanged).
 */
function saiap_handle_premium_response( $response ) {
	// Don't process WP_Error.
	if ( is_wp_error( $response ) ) {
		return $response;
	}

	// Handle error responses.
	if ( isset( $response['error_code'] ) ) {
		switch ( $response['error_code'] ) {
			case 'trial_expired':
				update_option( 'saiap_trial_status', 'expired' );
				break;

			case 'license_invalid':
				update_option( 'saiap_license_invalid', true );
				break;

			case 'trial_not_found':
			case 'no_access':
				// Server doesn't recognize this trial - reset local state.
				update_option( 'saiap_trial_status', 'none' );
				delete_option( 'saiap_trial_started_at' );
				break;
		}
	}

	// On success responses, sync trial status and clear error flags.
	if ( isset( $response['isValid'] ) && $response['isValid'] ) {
		delete_option( 'saiap_license_invalid' );

		// If accessType is 'license', user has paid - clear trial status.
		if ( isset( $response['accessType'] ) && 'license' === $response['accessType'] ) {
			$current_trial_status = get_option( 'saiap_trial_status', 'none' );
			if ( 'none' !== $current_trial_status ) {
				update_option( 'saiap_trial_status', 'none' );
			}
		}

		// Sync trial generation cap from server response.
		if ( isset( $response['post_cap'] ) ) {
			update_option( 'saiap_trial_post_cap', absint( $response['post_cap'] ) );
			update_option( 'saiap_trial_posts_generated', absint( $response['posts_generated'] ) );
			update_option( 'saiap_trial_posts_remaining', absint( $response['posts_remaining'] ) );
		}

		// Sync trial data from server response.
		if ( isset( $response['trial'] ) ) {
			$trial = $response['trial'];

			// Sync status.
			if ( isset( $trial['status'] ) ) {
				$server_status = $trial['status'];
				if ( 'active' === $server_status ) {
					update_option( 'saiap_trial_status', 'active' );
				} elseif ( 'expired' === $server_status ) {
					update_option( 'saiap_trial_status', 'expired' );
				} elseif ( 'converted' === $server_status ) {
					// Converted trial = paid user, clear trial status.
					update_option( 'saiap_trial_status', 'none' );
				}
			}

			// Sync expires_at (server is source of truth for trial end date).
			if ( isset( $trial['expires_at'] ) ) {
				update_option( 'saiap_trial_expires_at', $trial['expires_at'] );
			}
		}
	}

	return $response;
}

/**
 * Collect WordPress site content for wizard prefill.
 *
 * Gathers site name, tagline, recent posts, categories, and pages
 * to send to the backend for LLM-based prefill of wizard fields.
 *
 * @return array Site content for backend analysis.
 */
function saiap_collect_site_content_for_prefill() {
	$content = array(
		'site_name'        => get_bloginfo( 'name' ),
		'tagline'          => get_bloginfo( 'description' ),
		'description'      => get_bloginfo( 'description' ),
		'homepage_content' => '',
		'recent_posts'     => array(),
		'categories'       => array(),
		'pages'            => array(),
	);

	// Get homepage content if a static front page is set.
	$front_page_id = get_option( 'page_on_front' );
	if ( $front_page_id ) {
		$front_page = get_post( $front_page_id );
		if ( $front_page && 'publish' === $front_page->post_status ) {
			$content['homepage_content'] = wp_strip_all_tags( $front_page->post_content );
		}
	}

	// Get recent posts (up to 10).
	$recent_posts = get_posts(
		array(
			'post_type'      => 'post',
			'post_status'    => 'publish',
			'numberposts'    => 10,
			'orderby'        => 'date',
			'order'          => 'DESC',
		)
	);

	foreach ( $recent_posts as $post ) {
		// Skip default "Hello world!" post.
		if ( 'Hello world!' === $post->post_title ) {
			continue;
		}
		$content['recent_posts'][] = array(
			'title'   => $post->post_title,
			'content' => wp_strip_all_tags( $post->post_content ),
		);
	}

	// Get categories.
	$categories = get_categories(
		array(
			'hide_empty' => false,
			'exclude'    => array( 1 ), // Exclude "Uncategorized".
		)
	);

	foreach ( $categories as $category ) {
		$content['categories'][] = $category->name;
	}

	// Get pages (up to 5, excluding homepage if already fetched).
	$exclude_ids = $front_page_id ? array( $front_page_id ) : array();
	$pages       = get_posts(
		array(
			'post_type'      => 'page',
			'post_status'    => 'publish',
			'numberposts'    => 5,
			'orderby'        => 'menu_order',
			'order'          => 'ASC',
			'exclude'        => $exclude_ids,
		)
	);

	foreach ( $pages as $page ) {
		// Skip default "Sample Page".
		if ( 'Sample Page' === $page->post_title ) {
			continue;
		}
		$content['pages'][] = array(
			'title'   => $page->post_title,
			'content' => wp_strip_all_tags( $page->post_content ),
		);
	}

	return $content;
}

/**
 * Start a free trial by calling the premium service.
 *
 * This is called when user clicks "Start Free Trial" CTA.
 * On success, updates local state with trial information.
 *
 * @param string $email Optional email for follow-up communications.
 * @return array|WP_Error Response from server or error.
 */
function saiap_start_trial( $email = '' ) {
	// Check eligibility first.
	if ( ! saiap_can_start_trial() ) {
		return new WP_Error(
			'trial_ineligible',
			__( 'You are not eligible to start a trial.', 'clearpost-simple-ai-auto-post' )
		);
	}

	$domain = wp_parse_url( home_url(), PHP_URL_HOST );

	// Collect site content for wizard prefill.
	$site_content = saiap_collect_site_content_for_prefill();

	// If we have a stored PromoteKit referral code (e.g. from a previous
	// web-source trial that was claimed by this site), pass it through so
	// the backend can stamp it on this trial for affiliate attribution.
	$body_payload = array(
		'domain'       => $domain,
		'email'        => $email,
		'source'       => 'plugin',
		'site_content' => $site_content,
	);
	$stored_referral = get_option( 'saiap_promotekit_referral', '' );
	if ( ! empty( $stored_referral ) ) {
		$body_payload['promotekit_referral'] = $stored_referral;
	}

	$response = wp_remote_post(
		SAIAP_PREMIUM_API_URL . '/api/trial/start',
		array(
			'timeout' => 60, // Longer timeout for LLM prefill.
			'body'    => wp_json_encode( $body_payload ),
			'headers' => array(
				'Content-Type' => 'application/json',
			),
		)
	);

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

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

	// 409 means trial already exists for this domain - treat as success and sync state.
	if ( 409 === $code ) {
		// Trial exists - validate to sync local state with server.
		$validation = saiap_validate_premium_access();
		if ( ! is_wp_error( $validation ) && isset( $validation['isValid'] ) && $validation['isValid'] ) {
			// Update local trial status to match server.
			if ( isset( $validation['trial'] ) ) {
				update_option( 'saiap_trial_status', 'active' );
				update_option( 'saiap_trial_started_at', $validation['trial']['started_at'] );
				if ( isset( $validation['trial']['expires_at'] ) ) {
					update_option( 'saiap_trial_expires_at', $validation['trial']['expires_at'] );
				}
			}
			return array(
				'success' => true,
				'message' => __( 'Trial already active for this site.', 'clearpost-simple-ai-auto-post' ),
				'trial'   => isset( $validation['trial'] ) ? $validation['trial'] : null,
			);
		}
		// If validation fails, return a user-friendly message.
		return new WP_Error(
			'trial_exists',
			__( 'A trial already exists for this site. Please refresh the page.', 'clearpost-simple-ai-auto-post' )
		);
	}

	if ( 200 !== $code && 201 !== $code ) {
		$error_message = isset( $body['error'] ) ? $body['error'] : __( 'Failed to start trial.', 'clearpost-simple-ai-auto-post' );
		$error_code    = isset( $body['error_code'] ) ? $body['error_code'] : 'trial_start_failed';
		return new WP_Error( $error_code, $error_message );
	}

	// Success! Update local state.
	if ( isset( $body['trial'] ) ) {
		update_option( 'saiap_trial_status', 'active' );
		update_option( 'saiap_trial_started_at', $body['trial']['started_at'] );
		if ( isset( $body['trial']['expires_at'] ) ) {
			update_option( 'saiap_trial_expires_at', $body['trial']['expires_at'] );
		}
		// Cache PromoteKit referral locally as a backup source for the
		// checkout redirect. Backend remains authoritative, but this lets
		// the upgrade flow work even if backend storage gets wiped/rotated.
		if ( ! empty( $body['trial']['promotekit_referral'] ) ) {
			update_option( 'saiap_promotekit_referral', sanitize_text_field( $body['trial']['promotekit_referral'] ) );
		}
	}

	// Store the license key if returned by the server.
	if ( isset( $body['license_key'] ) ) {
		update_option( 'saiap_license_key', $body['license_key'] );
	}

	return $body;
}

/**
 * Validate premium access with the server.
 *
 * This is a validation-only call that checks current access status.
 * Should be called sparingly (not on every page load).
 *
 * On successful validation, stores:
 * - saiap_trial_source: 'plugin' or 'website' (how the trial was started)
 * - saiap_web_wizard_data: wizard data if trial was started via website
 *
 * @return array|WP_Error Response with access status or error.
 */
function saiap_validate_premium_access() {
	$domain      = wp_parse_url( home_url(), PHP_URL_HOST );
	$license_key = get_option( 'saiap_license_key', '' );

	$response = wp_remote_post(
		SAIAP_PREMIUM_API_URL . '/api/trial/validate',
		array(
			'timeout' => 30,
			'body'    => wp_json_encode(
				array(
					'domain'         => $domain,
					'license_key'    => $license_key,
					'plugin_version' => defined( 'SAIAP_VERSION' ) ? SAIAP_VERSION : null,
				)
			),
			'headers' => array(
				'Content-Type' => 'application/json',
			),
		)
	);

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

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

	// Store source and wizard_data from trial response if present.
	if ( isset( $body['trial'] ) ) {
		if ( isset( $body['trial']['source'] ) ) {
			update_option( 'saiap_trial_source', $body['trial']['source'] );
		}
		if ( isset( $body['trial']['wizard_data'] ) && ! empty( $body['trial']['wizard_data'] ) ) {
			update_option( 'saiap_web_wizard_data', $body['trial']['wizard_data'] );
		}
	}

	// Sync local state with server response.
	return saiap_handle_premium_response( $body );
}

/**
 * Get the domain for API calls.
 *
 * @return string The site domain.
 */
function saiap_get_domain() {
	return wp_parse_url( home_url(), PHP_URL_HOST );
}

/**
 * Check if a WordPress site is "empty" and needs the onboarding wizard.
 *
 * A site is considered "empty" if ALL of these are true:
 * - No real posts (only default "Hello world!" or posts with <100 chars)
 * - No real pages (only default "Sample Page" or pages with <100 chars)
 * - No meaningful site description (empty or "Just another WordPress site")
 *
 * @return bool True if site is empty and wizard should be shown.
 */
function saiap_is_site_empty() {
	// Check posts - only has default "Hello World" or no substantive posts.
	$posts = get_posts(
		array(
			'post_type'   => 'post',
			'post_status' => 'publish',
			'numberposts' => 5,
		)
	);

	$has_real_posts = false;
	foreach ( $posts as $post ) {
		// Skip if it's the default Hello World post or too short to be meaningful.
		if ( 'Hello world!' !== $post->post_title && strlen( $post->post_content ) > 100 ) {
			$has_real_posts = true;
			break;
		}
	}

	// Check pages.
	$pages = get_posts(
		array(
			'post_type'   => 'page',
			'post_status' => 'publish',
			'numberposts' => 5,
		)
	);

	$has_real_pages = false;
	foreach ( $pages as $page ) {
		// Skip sample page or pages too short to be meaningful.
		if ( 'Sample Page' !== $page->post_title && strlen( $page->post_content ) > 100 ) {
			$has_real_pages = true;
			break;
		}
	}

	// Check site description.
	$description     = get_bloginfo( 'description' );
	$has_description = ! empty( $description ) && 'Just another WordPress site' !== $description;

	// Site is empty if it has no real content AND no meaningful description.
	return ! $has_real_posts && ! $has_real_pages && ! $has_description;
}

/**
 * Check and potentially show the "trial available after update" notice.
 *
 * Called on admin_init to detect plugin version changes.
 */
function saiap_check_version_update_notice() {
	$current_version = defined( 'SAIAP_VERSION' ) ? SAIAP_VERSION : '0.0.0';
	$last_version    = get_option( 'saiap_last_version_seen', '' );

	if ( $current_version !== $last_version ) {
		// Version changed - update stored version.
		update_option( 'saiap_last_version_seen', $current_version );

		// If user has API keys but no trial (existing user updating), show notice.
		$scenario = saiap_get_user_scenario();
		if ( 'no_trial_has_keys' === $scenario && ! empty( $last_version ) ) {
			set_transient( 'saiap_show_trial_update_notice', true, 7 * DAY_IN_SECONDS );
		}
	}
}

/**
 * Check if the trial update notice should be shown.
 *
 * @return bool True if notice should be displayed.
 */
function saiap_should_show_trial_update_notice() {
	return (bool) get_transient( 'saiap_show_trial_update_notice' );
}

/**
 * Dismiss the trial update notice.
 *
 * Called via AJAX when user dismisses the notice.
 */
function saiap_dismiss_trial_update_notice() {
	delete_transient( 'saiap_show_trial_update_notice' );
}

/**
 * AJAX handler for starting a trial.
 *
 * Always returns show_wizard: true with prefill_data so the user can
 * verify/customize their business context before setup runs.
 */
function saiap_ajax_start_trial() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => __( 'Permission denied.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	$email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
	if ( empty( $email ) ) {
		// Fall back to WordPress admin email if JS didn't provide one.
		$email = get_option( 'admin_email', '' );
	}
	$result = saiap_start_trial( $email );

	if ( is_wp_error( $result ) ) {
		wp_send_json_error(
			array(
				'message'    => $result->get_error_message(),
				'error_code' => $result->get_error_code(),
			)
		);
	}

	// Store prefill data for wizard if returned by backend.
	$prefill_data = null;
	if ( isset( $result['prefill_data'] ) && is_array( $result['prefill_data'] ) ) {
		$prefill_data = $result['prefill_data'];
		update_option( 'saiap_wizard_prefill_data', $prefill_data );
	}

	// Always show wizard for plugin-first trials so user can confirm/edit context.
	wp_send_json_success(
		array(
			'show_wizard'    => true,
			'prefill_data'   => $prefill_data,
			'message'        => __( 'Confirm your site details to get started.', 'clearpost-simple-ai-auto-post' ),
			'trial'          => isset( $result['trial'] ) ? $result['trial'] : null,
			'days_remaining' => saiap_get_trial_days_remaining(),
		)
	);
}
add_action( 'wp_ajax_saiap_start_trial', 'saiap_ajax_start_trial' );

/**
 * AJAX handler for dismissing the trial update notice.
 */
function saiap_ajax_dismiss_trial_update_notice() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => __( 'Permission denied.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	saiap_dismiss_trial_update_notice();
	wp_send_json_success();
}
add_action( 'wp_ajax_saiap_dismiss_trial_update_notice', 'saiap_ajax_dismiss_trial_update_notice' );

/**
 * AJAX handler for submitting the onboarding wizard.
 *
 * This is called after trial is started and user confirms/edits the wizard data.
 * It stores wizard data, sends it to the backend, and triggers automated setup.
 */
function saiap_ajax_submit_onboarding_wizard() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => __( 'Permission denied.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	// Validate required fields.
	$site_name             = isset( $_POST['site_name'] ) ? sanitize_text_field( wp_unslash( $_POST['site_name'] ) ) : '';
	$site_description      = isset( $_POST['site_description'] ) ? sanitize_textarea_field( wp_unslash( $_POST['site_description'] ) ) : '';
	$niche                 = isset( $_POST['niche'] ) ? sanitize_text_field( wp_unslash( $_POST['niche'] ) ) : '';
	$target_audience       = isset( $_POST['target_audience'] ) ? sanitize_textarea_field( wp_unslash( $_POST['target_audience'] ) ) : '';
	$seed_topics           = isset( $_POST['seed_topics'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['seed_topics'] ) ) : array();
	$locations             = isset( $_POST['locations'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['locations'] ) ) : array();
	$competitor_urls       = isset( $_POST['competitor_urls'] ) ? array_map( 'esc_url_raw', wp_unslash( $_POST['competitor_urls'] ) ) : array();
	$example_posts         = isset( $_POST['example_posts'] ) ? array_map( 'esc_url_raw', wp_unslash( $_POST['example_posts'] ) ) : array();
	$publishing_preference = isset( $_POST['review_before_publish'] ) ? sanitize_text_field( wp_unslash( $_POST['review_before_publish'] ) ) : '';

	// Filter empty values.
	$seed_topics     = array_filter( $seed_topics );
	$locations       = array_filter( $locations );
	$competitor_urls = array_filter( $competitor_urls );
	$example_posts   = array_filter( $example_posts );

	// Validate minimum requirements.
	if ( empty( $site_description ) ) {
		wp_send_json_error( array( 'message' => __( 'Please describe what your site is about.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	if ( empty( $niche ) ) {
		wp_send_json_error( array( 'message' => __( 'Please enter your niche or industry.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	if ( count( $seed_topics ) < 3 ) {
		wp_send_json_error( array( 'message' => __( 'Please enter at least 3 seed topics.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	if ( 'draft' !== $publishing_preference && 'publish' !== $publishing_preference ) {
		wp_send_json_error( array( 'message' => __( 'Please choose a publishing preference.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	$review_before_publish = ( 'draft' === $publishing_preference );

	// Apply publishing preference to the plugin option that gates publish-vs-draft.
	update_option( 'saiap_review_before_publish', $review_before_publish );

	// Build wizard data.
	$wizard_data = array(
		'site_name'             => $site_name,
		'site_description'      => $site_description,
		'niche'                 => $niche,
		'target_audience'       => $target_audience,
		'seed_topics'           => array_values( $seed_topics ),
		'locations'             => array_values( $locations ),
		'competitor_urls'       => array_values( $competitor_urls ),
		'example_posts'         => array_values( $example_posts ),
		'review_before_publish' => $review_before_publish,
	);

	// Store wizard data in options for reference.
	update_option( 'saiap_onboarding_wizard_data', $wizard_data );

	// Get license key for API calls.
	$domain      = wp_parse_url( home_url(), PHP_URL_HOST );
	$license_key = get_option( 'saiap_license_key', '' );

	// Save wizard data to backend.
	if ( ! empty( $license_key ) ) {
		$save_response = wp_remote_post(
			SAIAP_PREMIUM_API_URL . '/api/trial/wizard-data',
			array(
				'timeout' => 30,
				'body'    => wp_json_encode(
					array(
						'domain'      => $domain,
						'license_key' => $license_key,
						'wizard_data' => $wizard_data,
					)
				),
				'headers' => array(
					'Content-Type' => 'application/json',
				),
			)
		);

		// If save to backend fails, continue silently - wizard data is saved locally.
	}

	// Don't trigger setup yet — the dashboard will show a GSC interstitial first,
	// giving users the chance to connect Google Search Console before the strategy
	// session runs. Setup is triggered via saiap_ajax_trigger_setup after GSC
	// connect or skip.

	wp_send_json_success(
		array(
			'message'        => __( 'Setup started! Creating your personalized content strategy...', 'clearpost-simple-ai-auto-post' ),
			'days_remaining' => saiap_get_trial_days_remaining(),
		)
	);
}
add_action( 'wp_ajax_saiap_submit_onboarding_wizard', 'saiap_ajax_submit_onboarding_wizard' );

/**
 * AJAX handler for triggering automated setup on demand.
 *
 * Called after the GSC interstitial (either user connected GSC or clicked Skip).
 * This is the deferred setup trigger that used to happen inside the wizard submit.
 */
function saiap_ajax_trigger_setup() {
	check_ajax_referer( 'saiap_trigger_setup_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => __( 'Permission denied.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	// Don't re-trigger if already running.
	$setup_triggered_at = get_option( 'saiap_setup_triggered_at', 0 );
	if ( $setup_triggered_at ) {
		wp_send_json_success( array( 'message' => __( 'Setup already in progress.', 'clearpost-simple-ai-auto-post' ) ) );
		return;
	}

	// Get wizard data saved during wizard submit.
	$wizard_data = get_option( 'saiap_onboarding_wizard_data', null );

	// Trigger automated setup.
	saiap_trigger_automated_setup( $wizard_data );
	update_option( 'saiap_setup_triggered_at', time() );

	wp_send_json_success(
		array(
			'message' => __( 'Setup started! Creating your personalized content strategy...', 'clearpost-simple-ai-auto-post' ),
		)
	);
}
add_action( 'wp_ajax_saiap_trigger_setup', 'saiap_ajax_trigger_setup' );

/**
 * AJAX handler for submitting wizard data when user already has a license key.
 *
 * This is called when user entered a license key for a web-started trial
 * that doesn't have wizard data yet (user abandoned web wizard at step 2).
 * It stores wizard data and triggers automated setup WITHOUT starting a new trial.
 */
function saiap_ajax_submit_wizard_with_license() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => __( 'Permission denied.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	// Verify user has a license key.
	$license_key = get_option( 'saiap_license_key', '' );
	if ( empty( $license_key ) ) {
		wp_send_json_error( array( 'message' => __( 'No license key found. Please enter your license key first.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	// Validate required fields.
	$site_name        = isset( $_POST['site_name'] ) ? sanitize_text_field( wp_unslash( $_POST['site_name'] ) ) : '';
	$site_description = isset( $_POST['site_description'] ) ? sanitize_textarea_field( wp_unslash( $_POST['site_description'] ) ) : '';
	$niche            = isset( $_POST['niche'] ) ? sanitize_text_field( wp_unslash( $_POST['niche'] ) ) : '';
	$target_audience  = isset( $_POST['target_audience'] ) ? sanitize_textarea_field( wp_unslash( $_POST['target_audience'] ) ) : '';
	$seed_topics      = isset( $_POST['seed_topics'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['seed_topics'] ) ) : array();
	$locations        = isset( $_POST['locations'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['locations'] ) ) : array();
	$competitor_urls  = isset( $_POST['competitor_urls'] ) ? array_map( 'esc_url_raw', wp_unslash( $_POST['competitor_urls'] ) ) : array();
	$example_posts    = isset( $_POST['example_posts'] ) ? array_map( 'esc_url_raw', wp_unslash( $_POST['example_posts'] ) ) : array();

	// Filter empty values.
	$seed_topics     = array_filter( $seed_topics );
	$locations       = array_filter( $locations );
	$competitor_urls = array_filter( $competitor_urls );
	$example_posts   = array_filter( $example_posts );

	// Validate minimum requirements.
	if ( empty( $site_description ) ) {
		wp_send_json_error( array( 'message' => __( 'Please describe what your site is about.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	if ( empty( $niche ) ) {
		wp_send_json_error( array( 'message' => __( 'Please enter your niche or industry.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	if ( count( $seed_topics ) < 3 ) {
		wp_send_json_error( array( 'message' => __( 'Please enter at least 3 seed topics.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	// Build wizard data.
	$wizard_data = array(
		'site_name'        => $site_name,
		'site_description' => $site_description,
		'niche'            => $niche,
		'target_audience'  => $target_audience,
		'seed_topics'      => array_values( $seed_topics ),
		'locations'        => array_values( $locations ),
		'competitor_urls'  => array_values( $competitor_urls ),
		'example_posts'    => array_values( $example_posts ),
	);

	// Store wizard data in options.
	update_option( 'saiap_onboarding_wizard_data', $wizard_data );

	// Trigger automated setup with wizard data (no trial start needed - user has license).
	saiap_trigger_automated_setup( $wizard_data );

	// Mark that setup was triggered so Dashboard can show loader.
	update_option( 'saiap_setup_triggered_at', time() );

	wp_send_json_success(
		array(
			'message' => __( 'Setup started! Creating your personalized content strategy...', 'clearpost-simple-ai-auto-post' ),
		)
	);
}
add_action( 'wp_ajax_saiap_submit_wizard_with_license', 'saiap_ajax_submit_wizard_with_license' );

/**
 * AJAX handler: Create first post draft from pre-generated content.
 *
 * This is called after automated setup completes to create a WordPress draft
 * from the pre-generated first post content.
 */
function saiap_ajax_create_first_post_draft() {
	// Verify nonce.
	if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'saiap_form_action' ) ) {
		wp_send_json_error( array( 'message' => __( 'Security check failed.', 'clearpost-simple-ai-auto-post' ) ) );
	}

	// Idempotency guard: if we already created a first post on this site, return its ID
	// instead of creating a duplicate. The `saiap_first_post_created` option is written at
	// the bottom of this handler on success, so repeated polls/refreshes reuse the existing
	// draft rather than spawning fresh drafts on every call.
	$existing_id = (int) get_option( 'saiap_first_post_created', 0 );
	if ( $existing_id > 0 && get_post( $existing_id ) ) {
		wp_send_json_success(
			array(
				'message'  => __( 'First post already created.', 'clearpost-simple-ai-auto-post' ),
				'post_id'  => $existing_id,
				'edit_url' => get_edit_post_link( $existing_id, '' ),
				'title'    => get_the_title( $existing_id ),
			)
		);
	}

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

	// Fetch first post data from backend.
	$response = wp_remote_post(
		SAIAP_PREMIUM_API_URL . '/api/trial/first-post',
		array(
			'timeout' => 30,
			'body'    => wp_json_encode(
				array(
					'domain'      => $domain,
					'license_key' => $license_key,
				)
			),
			'headers' => array(
				'Content-Type' => 'application/json',
			),
		)
	);

	if ( is_wp_error( $response ) ) {
		wp_send_json_error(
			array(
				'message' => __( 'Failed to fetch first post data.', 'clearpost-simple-ai-auto-post' ),
				'error'   => $response->get_error_message(),
			)
		);
	}

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

	if ( 200 !== $code || ! is_array( $body ) ) {
		wp_send_json_error(
			array(
				'message'   => __( 'First post not available yet.', 'clearpost-simple-ai-auto-post' ),
				'available' => false,
			)
		);
	}

	// State 1: backend already pushed the post to WordPress. Surface the existing post ID
	// instead of creating a duplicate via wp_insert_post. This is the happy path for new trials.
	if ( ! empty( $body['alreadyCreated'] ) && ! empty( $body['wpPostId'] ) ) {
		$wp_post_id = absint( $body['wpPostId'] );

		// Remember so subsequent polls/refreshes can short-circuit via the idempotency guard at the top.
		update_option( 'saiap_first_post_created', $wp_post_id );

		wp_send_json_success(
			array(
				'message'          => __( 'Your first post is ready to review!', 'clearpost-simple-ai-auto-post' ),
				'post_id'          => $wp_post_id,
				'edit_url'         => get_edit_post_link( $wp_post_id, '' ),
				'title'            => isset( $body['title'] ) ? sanitize_text_field( $body['title'] ) : '',
				'calendar_item_id' => isset( $body['calendarItemId'] ) ? sanitize_text_field( $body['calendarItemId'] ) : null,
			)
		);
	}

	// State 3: not ready yet (no wp_post_id, no fallback content).
	if ( empty( $body['available'] ) ) {
		wp_send_json_error(
			array(
				'message'   => __( 'First post not available yet.', 'clearpost-simple-ai-auto-post' ),
				'available' => false,
			)
		);
	}

	// Create WordPress draft from the generated content.
	$title   = isset( $body['title'] ) ? sanitize_text_field( $body['title'] ) : __( 'Your First ClearPost Article', 'clearpost-simple-ai-auto-post' );
	$content = isset( $body['content'] ) ? wp_kses_post( $body['content'] ) : '';

	if ( empty( $content ) ) {
		wp_send_json_error(
			array(
				'message' => __( 'First post has no content.', 'clearpost-simple-ai-auto-post' ),
			)
		);
	}

	$post_id = wp_insert_post(
		array(
			'post_title'   => $title,
			'post_content' => $content,
			'post_status'  => 'draft', // Always draft - first post needs human review.
			'post_type'    => 'post',
		)
	);

	if ( is_wp_error( $post_id ) ) {
		wp_send_json_error(
			array(
				'message' => __( 'Failed to create draft post.', 'clearpost-simple-ai-auto-post' ),
				'error'   => $post_id->get_error_message(),
			)
		);
	}

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

	// Store calendar item ID for reference.
	$calendar_item_id = null;
	if ( ! empty( $body['calendarItemId'] ) ) {
		$calendar_item_id = sanitize_text_field( $body['calendarItemId'] );
		update_post_meta( $post_id, '_saiap_calendar_item_id', $calendar_item_id );
	}

	// Sync wp_post_id back to the backend calendar item.
	if ( $calendar_item_id ) {
		wp_remote_request(
			SAIAP_PREMIUM_API_URL . '/api/prompts/update/' . $calendar_item_id . '/status',
			array(
				'method'  => 'PUT',
				'timeout' => 10,
				'body'    => wp_json_encode(
					array(
						'domain'      => $domain,
						'license_key' => $license_key,
						'status'      => 'pending_review',
						'wp_post_id'  => $post_id,
					)
				),
				'headers' => array(
					'Content-Type' => 'application/json',
				),
			)
		);
	}

	// Remember that we created the first post (don't create duplicates on refresh).
	update_option( 'saiap_first_post_created', $post_id );

	wp_send_json_success(
		array(
			'message'          => __( 'Your first post is ready to review!', 'clearpost-simple-ai-auto-post' ),
			'post_id'          => $post_id,
			'edit_url'         => get_edit_post_link( $post_id, '' ),
			'title'            => $title,
			'calendar_item_id' => isset( $body['calendarItemId'] ) ? sanitize_text_field( $body['calendarItemId'] ) : null,
		)
	);
}
add_action( 'wp_ajax_saiap_create_first_post_draft', 'saiap_ajax_create_first_post_draft' );

/**
 * AJAX handler to retry automated setup.
 *
 * Clears the previous setup flag and re-triggers automated setup.
 */
function saiap_ajax_retry_setup() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => 'Insufficient permissions' ) );
		return;
	}

	// Clear the setup triggered flag so we can re-trigger.
	delete_option( 'saiap_setup_triggered_at' );

	// Get wizard data if available.
	$source             = get_option( 'saiap_trial_source', 'plugin' );
	$web_wizard_data    = get_option( 'saiap_web_wizard_data', null );
	$plugin_wizard_data = get_option( 'saiap_onboarding_wizard_data', null );

	// Determine which wizard data to use.
	$wizard_data = null;
	if ( 'website' === $source && ! empty( $web_wizard_data ) ) {
		$wizard_data = $web_wizard_data;
	} elseif ( ! empty( $plugin_wizard_data ) ) {
		$wizard_data = $plugin_wizard_data;
	}

	// Re-trigger automated setup.
	$result = saiap_trigger_automated_setup( $wizard_data );

	// Track retry event.
	saiap_track_event(
		'setup_retried',
		array(
			'source'          => $source,
			'has_wizard_data' => ! empty( $wizard_data ) ? 'yes' : 'no',
		)
	);

	// Check for errors.
	if ( is_wp_error( $result ) ) {
		wp_send_json_error(
			array(
				'message' => $result->get_error_message(),
			)
		);
		return;
	}

	// Set the setup flag.
	update_option( 'saiap_setup_triggered_at', time() );

	wp_send_json_success(
		array(
			'message' => 'Setup re-triggered successfully.',
		)
	);
}
add_action( 'wp_ajax_saiap_retry_setup', 'saiap_ajax_retry_setup' );

/**
 * AJAX handler to track setup-related events.
 */
function saiap_ajax_track_setup_event() {
	check_ajax_referer( 'saiap_trial_nonce', 'nonce' );

	$event_name   = isset( $_POST['event_name'] ) ? sanitize_text_field( wp_unslash( $_POST['event_name'] ) ) : '';
	$event_params = isset( $_POST['event_params'] ) ? json_decode( wp_unslash( $_POST['event_params'] ), true ) : array(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized

	if ( empty( $event_name ) ) {
		wp_send_json_error( array( 'message' => 'Event name is required' ) );
		return;
	}

	// Add trial source to params.
	$event_params['trial_source'] = get_option( 'saiap_trial_source', 'plugin' );

	saiap_track_event( $event_name, $event_params );

	wp_send_json_success( array( 'tracked' => true ) );
}
add_action( 'wp_ajax_saiap_track_setup_event', 'saiap_ajax_track_setup_event' );

/**
 * Check if the trial welcome hero should be displayed.
 *
 * @deprecated 2.6.0 Use Dashboard tab instead - trial CTA is now shown on Dashboard for fresh users.
 *
 * @return bool Always returns false - legacy function kept for backward compatibility.
 */
function saiap_should_show_trial_welcome() {
	// Deprecated: Trial welcome is now handled by the Dashboard tab.
	return false;
}

/**
 * Render the trial welcome hero component.
 *
 * @deprecated 2.6.0 Use saiap_render_dashboard_trial_cta() instead - now part of Dashboard.
 *
 * This function is kept for backward compatibility but is no longer called.
 * The trial welcome hero is now rendered as part of the Dashboard tab for
 * users in the 'locked' state (no_trial_no_keys, no_trial_has_keys).
 */
function saiap_render_trial_welcome_hero() {
	// Deprecated: This is now handled by saiap_render_dashboard_trial_cta() in dashboard.php.
	return;
}

/**
 * Render the trial upgrade banner (for users with API keys but no trial).
 *
 * Less intrusive than the welcome hero.
 */
function saiap_render_trial_upgrade_banner() {
	$scenario = saiap_get_user_scenario();

	// Only show for users with API keys but no trial.
	if ( 'no_trial_has_keys' !== $scenario ) {
		return;
	}

	?>
	<div class="saiap-trial-upgrade-banner">
		<div class="saiap-trial-upgrade-banner__content">
			<span class="dashicons dashicons-update-alt saiap-trial-upgrade-banner__icon"></span>
			<div class="saiap-trial-upgrade-banner__text">
				<strong><?php esc_html_e( 'You\'re set up for manual generation.', 'clearpost-simple-ai-auto-post' ); ?></strong>
				<span><?php esc_html_e( 'Try automated SEO-driven publishing free for 7 days.', 'clearpost-simple-ai-auto-post' ); ?></span>
			</div>
			<button type="button" class="button button-primary saiap-start-trial-btn">
				<?php esc_html_e( 'Start Free Trial', 'clearpost-simple-ai-auto-post' ); ?>
			</button>
		</div>
	</div>
	<?php
}

/**
 * Render the trial status badge (for active trial users).
 *
 * Shows "Day X of Y" with a progress indicator.
 */
function saiap_render_trial_status_badge() {
	$scenario = saiap_get_user_scenario();

	if ( 'active_trial' !== $scenario ) {
		return;
	}

	// Hide on premium tab (it has its own trial banner).
	// phpcs:ignore WordPress.Security.NonceVerification.Recommended
	$current_tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : '';
	if ( 'premium' === $current_tab ) {
		return;
	}

	$days_remaining = saiap_get_trial_days_remaining();
	$total_days     = saiap_get_trial_total_days();
	$current_day    = max( 1, $total_days - $days_remaining + 1 );
	$progress       = ( $current_day / $total_days ) * 100;

	$upgrade_url = saiap_get_checkout_url();
	?>
	<div class="saiap-trial-status-badge">
		<span class="saiap-trial-status-badge__dot"></span>
		<span class="saiap-trial-status-badge__text">
			<?php
			printf(
				/* translators: %1$d: current day, %2$d: total days */
				esc_html__( 'Trial: Day %1$d of %2$d', 'clearpost-simple-ai-auto-post' ),
				absint( $current_day ),
				absint( $total_days )
			);
			?>
		</span>
		<div class="saiap-trial-status-badge__progress">
			<div class="saiap-trial-status-badge__progress-fill" style="width: <?php echo esc_attr( $progress ); ?>%"></div>
		</div>
		<span class="saiap-trial-status-badge__separator">|</span>
		<a href="<?php echo esc_url( $upgrade_url ); ?>" class="saiap-trial-status-badge__upgrade" target="_blank">
			<?php esc_html_e( 'Upgrade Now', 'clearpost-simple-ai-auto-post' ); ?>
		</a>
	</div>
	<?php
}

/**
 * Render the expired trial paywall notice.
 */
function saiap_render_expired_trial_paywall() {
	$scenario = saiap_get_user_scenario();

	if ( 'expired_trial' !== $scenario ) {
		return;
	}

	$pricing_url  = saiap_get_checkout_url();
	$has_api_keys = ! empty( get_option( 'saiap_openai_api_key', '' ) )
				|| ! empty( get_option( 'saiap_anthropic_api_key', '' ) )
				|| ! empty( get_option( 'saiap_gemini_api_key', '' ) );

	?>
	<div class="saiap-expired-trial-paywall">
		<div class="saiap-expired-trial-paywall__icon">
			<span class="dashicons dashicons-clock"></span>
		</div>
		<div class="saiap-expired-trial-paywall__content">
			<h3><?php esc_html_e( 'Your free automation period has ended', 'clearpost-simple-ai-auto-post' ); ?></h3>
			<p><?php esc_html_e( 'ClearPost has paused automated publishing. Subscribe to continue with SEO-driven content generation.', 'clearpost-simple-ai-auto-post' ); ?></p>
			<div class="saiap-expired-trial-paywall__actions">
				<a href="<?php echo esc_url( $pricing_url ); ?>" class="button button-primary button-hero" target="_blank">
					<?php esc_html_e( 'Continue Publishing', 'clearpost-simple-ai-auto-post' ); ?>
				</a>
				<?php if ( $has_api_keys ) : ?>
					<p class="saiap-expired-trial-paywall__secondary">
						<?php esc_html_e( 'Or continue generating manually with your API keys', 'clearpost-simple-ai-auto-post' ); ?>
					</p>
				<?php else : ?>
					<p class="saiap-expired-trial-paywall__secondary">
						<a href="<?php echo esc_url( admin_url( 'admin.php?page=saiap&tab=ai-settings' ) ); ?>">
							<?php esc_html_e( 'Or add your own API keys to generate manually', 'clearpost-simple-ai-auto-post' ); ?>
						</a>
					</p>
				<?php endif; ?>
			</div>
		</div>
	</div>
	<?php
}

/**
 * Trigger automated setup after trial start.
 *
 * This function collects site data and posts, then sends them to the premium
 * service to kick off the automated setup process (site context, keyword
 * research, calendar generation). It's fire-and-forget with a short timeout.
 *
 * @param array|null $wizard_data Optional wizard data for empty sites.
 * @return array|WP_Error Response from server or error.
 */
function saiap_trigger_automated_setup( $wizard_data = null ) {
	$domain = wp_parse_url( home_url(), PHP_URL_HOST );

	// Collect site data (reusing logic from saiap_get_site_context).
	$homepage_id = get_option( 'page_on_front' );
	if ( ! $homepage_id ) {
		$homepage_id = get_option( 'page_for_posts' );
	}

	$homepage_content = '';
	if ( $homepage_id ) {
		$homepage = get_post( $homepage_id );
		if ( $homepage ) {
			$homepage_content = wp_strip_all_tags( $homepage->post_content );
		}
	}

	$site_description = get_bloginfo( 'description' );

	$site_data = array(
		'domain'           => $domain,
		'homepage_content' => $homepage_content,
		'site_description' => $site_description,
	);

	// Get recent posts (limit to most recent 50 for initial setup).
	$public_post_types = get_post_types( array( 'public' => true ), 'names' );
	unset( $public_post_types['attachment'] );

	$query = new WP_Query(
		array(
			'post_type'      => array_values( $public_post_types ),
			'posts_per_page' => 50,
			'post_status'    => 'publish',
			'orderby'        => 'date',
			'order'          => 'DESC',
		)
	);

	$posts = array();
	if ( $query->have_posts() ) {
		while ( $query->have_posts() ) {
			$query->the_post();
			$post          = get_post();
			$post_date     = get_post_time( 'c', true, $post );
			$post_modified = get_post_modified_time( 'c', true, $post );
			$post_type     = get_post_type( $post );

			// Get taxonomy data for this post.
			$all_taxonomies = get_object_taxonomies( $post_type, 'objects' );
			$taxonomy_data  = array();

			foreach ( $all_taxonomies as $tax_slug => $taxonomy ) {
				$terms = wp_get_post_terms( $post->ID, $tax_slug, array( 'fields' => 'all' ) );
				if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
					$raw_term_data = array();
					foreach ( $terms as $term ) {
						$raw_term_data[] = array(
							'term_id'     => $term->term_id,
							'name'        => $term->name,
							'slug'        => $term->slug,
							'parent'      => $term->parent,
							'description' => $term->description,
						);
					}
					$taxonomy_data[ $tax_slug ] = array(
						'terms'        => $raw_term_data,
						'hierarchical' => $taxonomy->hierarchical,
					);
				}
			}

			$posts[] = array(
				'ID'            => $post->ID,
				'title'         => $post->post_title,
				'content'       => wp_strip_all_tags( $post->post_content ),
				'published_at'  => $post_date,
				'modified_at'   => $post_modified,
				'post_type'     => $post_type,
				'taxonomy_data' => $taxonomy_data,
			);
		}
		wp_reset_postdata();
	}

	// Build request body.
	$request_body = array(
		'domain'    => $domain,
		'site_data' => $site_data,
		'posts'     => $posts,
	);

	// Include wizard data if provided (for empty sites).
	if ( ! empty( $wizard_data ) ) {
		$request_body['wizard_data'] = $wizard_data;
	}

	// Send to premium service (fire-and-forget with short timeout).
	$response = wp_remote_post(
		SAIAP_PREMIUM_API_URL . '/api/trial/setup',
		array(
			'timeout' => 15, // Short timeout - we don't wait for completion.
			'body'    => wp_json_encode( $request_body ),
			'headers' => array(
				'Content-Type' => 'application/json',
			),
		)
	);

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

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

	return $body;
}

/**
 * Render a generic trial CTA card for use on various tabs.
 *
 * @param string $context The context where this CTA is shown (e.g., 'generate', 'context').
 * @param bool   $compact Whether to show a compact version.
 */
function saiap_render_trial_cta_card( $context = 'default', $compact = false ) {
	$scenario = saiap_get_user_scenario();

	// Don't show for users with access.
	if ( in_array( $scenario, array( 'active_trial', 'paid' ), true ) ) {
		return;
	}

	// For expired trial, show paywall instead.
	if ( 'expired_trial' === $scenario ) {
		saiap_render_expired_trial_paywall();
		return;
	}

	$class = $compact ? 'saiap-trial-cta-card saiap-trial-cta-card--compact' : 'saiap-trial-cta-card';

	// Customize messaging based on context.
	$headline    = __( 'Unlock Automated Publishing', 'clearpost-simple-ai-auto-post' );
	$description = __( 'Start your free trial to get SEO-driven content on autopilot.', 'clearpost-simple-ai-auto-post' );

	switch ( $context ) {
		case 'generate':
			$headline    = __( 'Generate Smarter with Trial', 'clearpost-simple-ai-auto-post' );
			$description = __( 'Let AI research keywords and generate posts that rank.', 'clearpost-simple-ai-auto-post' );
			break;

		case 'context':
			$headline    = __( 'Start Trial to Unlock Site Context', 'clearpost-simple-ai-auto-post' );
			$description = __( 'Let ClearPost learn your site\'s style, keywords, and audience.', 'clearpost-simple-ai-auto-post' );
			break;

		case 'dashboard':
			$headline    = __( 'Start Trial to Unlock Your Content Command Center', 'clearpost-simple-ai-auto-post' );
			$description = __( 'See your 30-day content calendar, SEO keywords, and autopilot controls.', 'clearpost-simple-ai-auto-post' );
			break;

		case 'editor':
			$headline    = __( 'Unlock AI Editing', 'clearpost-simple-ai-auto-post' );
			$description = __( 'Get intelligent editing suggestions powered by your site context.', 'clearpost-simple-ai-auto-post' );
			break;
	}

	?>
	<div class="<?php echo esc_attr( $class ); ?>">
		<?php if ( ! $compact ) : ?>
			<span class="dashicons dashicons-superhero-alt saiap-trial-cta-card__icon"></span>
		<?php endif; ?>
		<div class="saiap-trial-cta-card__content">
			<h4 class="saiap-trial-cta-card__headline"><?php echo esc_html( $headline ); ?></h4>
			<p class="saiap-trial-cta-card__description"><?php echo esc_html( $description ); ?></p>
		</div>
		<button type="button" class="button button-primary saiap-start-trial-btn">
			<?php esc_html_e( 'Start Free Trial', 'clearpost-simple-ai-auto-post' ); ?>
		</button>
	</div>
	<?php
}

