<?php
/**
 * Author Kit - Custom Functions and Hooks
 *
 * This file contains custom WordPress functions and hook implementations
 * used in the Author Kit plugin/theme to extend default WordPress behavior.
 *
 * @package Author_Kit
 * @version 1.0.0
 */

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

// remove the default WordPress footer.
add_action( 'admin_enqueue_scripts', 'author_kit_remove_wp_footer' );

// to add custom meta box for posts.
add_action( 'init', 'author_kit_initialize_meta_box' );

// Hook our custom avatar into WordPress avatar.
add_filter( 'get_avatar_url', 'author_kit_get_custom_avatar_url', 10, 3 );

add_filter( 'get_avatar', 'author_kit_get_avatar', 999, 5 );

// Hook into the login process to prevent login for "Guest" users.
add_filter( 'authenticate', 'author_kit_block_guest_login', 30, 3 );

// Enqueue the scirpts for Author Kit toast.
add_action( 'admin_enqueue_scripts', 'author_kit_toast' );

add_action( 'customize_preview_init', 'author_kit_enqueue_customizer_script' );


add_filter( 'map_meta_cap', 'author_kit_map_add_edit_user_cap', 10, 4 );

// Add Guest users in posts authors dropdown in Classic Editor.
add_filter( 'wp_dropdown_users_args', 'author_kit_include_custom_roles_in_author_dropdown' );

// Hook for when the Customizer preview loads.
add_action( 'customize_preview_init', 'author_kit_clear_customizer_css_cache' );

// Hook for when Customizer settings are saved.
add_action( 'customize_save_after', 'author_kit_clear_customizer_css_cache' );

// Hooks to clear cache when specific options are updated.
add_action( 'update_option_author_kit_author_bio_template', 'author_kit_clear_css_cache_on_option_change', 10, 2 );
add_action( 'update_option_author_kit_author_archive_template', 'author_kit_clear_css_cache_on_option_change', 10, 2 );
add_action( 'update_option_author_kit_custom_byline_template', 'author_kit_clear_css_cache_on_option_change', 10, 2 );

// Add Guest users in posts authors dropdown in Gutenberg Editor.
add_action(
	'init',
	function () {
		add_filter( 'rest_user_query', 'author_kit_safely_add_guest_to_author_dropdown', 30, 2 );
	}
);

// Handles Post request for downloading of log file.
add_action(
	'admin_post_author_kit_download_log',
	function () {
		// Security check.
		if ( ! current_user_can( 'manage_options' ) || ! check_admin_referer( 'author_kit_download_log' ) ) {
			wp_die( 'Unauthorized', 403 );
		}

		Author_Kit_Logger::download_log_file();
	}
);

// Handles Post request for downloading of system report file.
add_action(
	'admin_post_author_kit_download_sys_report',
	function () {
		// Security check.
		if ( ! current_user_can( 'manage_options' ) || ! check_admin_referer( 'author_kit_download_sys_report' ) ) {
			wp_die( 'Unauthorized access', 403 );
		}

		Author_Kit_Logger::download_system_report();
	}
);


/**
 * Map `edit_user` and `create_users` to a custom capability.
 *
 * @param array  $caps       Array of primitive capabilities for the requested meta capability.
 * @param string $cap        The meta capability being checked (e.g., 'edit_user', 'create_users').
 * @param int    $user_id    The ID of the user performing the capability check.
 * @param array  $args       Arguments passed to the current capability check.
 * @return array             Modified array of primitive capabilities.
 */
function author_kit_map_add_edit_user_cap( $caps, $cap, $user_id, $args ) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter
	switch ( $cap ) {
		case 'author_kit_add_edit_user':
			// Allow if the user has either `edit_users` or `create_users` capability.
			if ( user_can( $user_id, 'edit_users' ) || user_can( $user_id, 'create_users' ) ) {
				$caps = array(); // Empty array grants permission to the custom capability.
			} else {
				$caps = array( 'do_not_allow' ); // Deny access if neither capability is present.
			}
			break;
	}

	return $caps;
}

/**
 * Enqueues the Author Kit script for the WordPress Customizer preview.
 *
 * This script allows for live previewing of Author Kit changes within the Customizer.
 * It is loaded with dependencies on jQuery and customize-preview.
 *
 * @return void
 */
function author_kit_enqueue_customizer_script() {
	wp_enqueue_script( 'customizer-preview', AUTHOR_KIT_PLUGIN_URL . 'admin/assets/js/author-kit-customizer-preview.js', array( 'jquery', 'customize-preview' ), AUTHOR_KIT_VERSION, true );
}

/**
 * Enqueues the CSS and JS assets for Author Kit toast notifications in the admin area.
 *
 * This includes a custom stylesheet and script to display toast-style messages,
 * and depends on jQuery and WordPress Heartbeat API for real-time functionality.
 *
 * @return void
 */
function author_kit_toast() {
	wp_enqueue_style(
		'author-kit-toast-lib-style',
		AUTHOR_KIT_PLUGIN_URL . 'admin/assets/css/author-kit-toast.css',
		array(), // No dependencies (or specify other styles if necessary).
		AUTHOR_KIT_VERSION, // or false if no versioning.
		'all' // This defines the media (all, screen, print, etc.).
	);

	wp_enqueue_script(
		'author-kit-toast-lib-script',
		AUTHOR_KIT_PLUGIN_URL . 'admin/assets/js/author-kit-toast.js',
		array( 'jquery', 'heartbeat' ),
		AUTHOR_KIT_VERSION, // This should be your plugin's version constant for proper cache busting.
		true // Load in footer.
	);
}

/**
 * Removes the default WordPress admin footer styling.
 *
 * This function hides the #wpfooter element and removes bottom padding from
 * #wpbody-content to clean up the admin UI.
 *
 * @return void
 */
function author_kit_remove_wp_footer() {
	// Register a dummy stylesheet handle.
	wp_register_style( 'author-kit-remove-footer', false, array(), AUTHOR_KIT_VERSION, 'all' );
	wp_enqueue_style( 'author-kit-remove-footer' );

	$custom_css = '
        #wpfooter {
            display: none;
        }
        #wpbody-content {
            padding-bottom: 0px;
        }
    ';
	wp_add_inline_style( 'author-kit-remove-footer', $custom_css );
}

/**
 * Initializes custom meta boxes for posts.
 *
 * This function includes the meta box class file and instantiates the
 * `Author_Kit_Meta_Boxes` class to add custom meta boxes in the post editor.
 *
 * @return void
 */
function author_kit_initialize_meta_box() {
	include AUTHOR_KIT_PLUGIN_PATH . 'includes/class/class-author-kit-meta-boxes.php';
	if ( class_exists( 'Author_Kit_Meta_Boxes' ) ) {
		new Author_Kit_Meta_Boxes();
	}
}

/**
 * Adds custom user roles (including Guest) to the Classic Editor's author dropdown.
 *
 * Modifies the query arguments for the user dropdown shown in post editing screens
 * to include specific roles like 'guest', 'author', 'editor', and 'administrator'.
 *
 * @param array $args Arguments passed to `wp_dropdown_users()`.
 * @return array Modified arguments including custom roles for author selection.
 */
function author_kit_include_custom_roles_in_author_dropdown( $args ) {

	global $pagenow;

	if ( in_array( $pagenow, array( 'post-new.php', 'post.php' ), true ) ) {
		unset( $args['who'] ); // Don't limit to default 'authors'.
		$args['role__in'] = array( 'guest', 'author', 'editor', 'administrator' ); // Limit to known good roles.
	}

	return $args;
}

/**
 * Adds specific user roles, including 'guest', to the author dropdown in Gutenberg.
 *
 * This function filters the REST API user query to include additional roles such as
 * 'guest', ensuring they appear in the author selection dropdown within Gutenberg editor.
 *
 * @param array           $args    Arguments passed to the user query.
 * @param WP_REST_Request $request The current REST request.
 * @return array Modified query arguments including custom user roles.
 */
function author_kit_safely_add_guest_to_author_dropdown( $args, $request ) {
	// Only apply this for the author dropdown API request.
	$route = $request->get_route();
	if ( strpos( $route, '/wp/v2/users' ) === false ) {
		return $args;
	}

	// Remove 'who' to prevent it from overriding 'role__in'.
	unset( $args['who'] );

	// Define the allowed roles you want in the dropdown.
	$required_roles = array( 'administrator', 'editor', 'author', 'guest' );

	// Merge with existing roles if set.
	if ( isset( $args['role__in'] ) && is_array( $args['role__in'] ) ) {
		$args['role__in'] = array_unique( array_merge( $args['role__in'], $required_roles ) );
	} else {
		$args['role__in'] = $required_roles;
	}

	return $args;
}

/**
 * Filters the avatar URL to use a custom avatar if set for the user.
 *
 * This function checks if the user has a custom avatar URL stored in user meta
 * (`author_kit_custom_avatar_url`) and returns it if available. Falls back to
 * the default avatar if not found.
 *
 * Hooked to the `get_avatar_url` filter.
 *
 * @param string            $url         The default avatar URL.
 * @param int|string|object $id_or_email User ID, email address, or comment object.
 * @param array             $args        Arguments passed to get_avatar_data().
 * @return string Modified avatar URL if custom avatar is set, otherwise the original URL.
 */
function author_kit_get_custom_avatar_url( $url, $id_or_email, $args ) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter
	$user = false;

	if ( is_numeric( $id_or_email ) ) {
		$user = get_user_by( 'id', (int) $id_or_email );
	} elseif ( is_object( $id_or_email ) && ! empty( $id_or_email->user_id ) ) {
		$user = get_user_by( 'id', (int) $id_or_email->user_id );
	} elseif ( is_string( $id_or_email ) ) {
		$user = get_user_by( 'email', $id_or_email );
	}

	if ( $user ) {
		// Check user's avatar preference.
		$custom_avatar = get_user_meta( $user->ID, 'author_kit_custom_avatar_url', true ); // Assume 'custom_avatar' is the meta key for custom avatar URL.

		if ( ! empty( $custom_avatar ) ) {
			return esc_url( $custom_avatar ); // Return custom avatar URL if selected.
		}
	}

	return $url; // Default to Gravatar or WordPress default avatar.
}

/**
 * Blocks login for users with the "guest" role.
 *
 * Hooked into the `authenticate` filter to prevent users with the "guest" role
 * from logging in to the WordPress dashboard. Returns a `WP_Error` if blocked.
 *
 * @param WP_User|WP_Error|null $user     The authenticated user object or error.
 * @param string                $username The username used for login.
 * @param string                $password The password used for login.
 * @return WP_User|WP_Error The user object if not a guest, otherwise a WP_Error.
 */
function author_kit_block_guest_login( $user, $username, $password ) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter
	if ( is_wp_error( $user ) ) {
		return $user;
	}

	// Check if the user has the "Guest" role.
	if ( in_array( 'guest', (array) $user->roles, true ) ) {
		return new WP_Error(
			'guest_login_blocked',
			__( 'Login is not allowed for Guest users.', 'author-kit' )
		);
	}

	return $user;
}

/**
 * Retrieve all co-authors for a given post.
 *
 * @param int $post_id The ID of the post.
 * @return array|false An array of co-author user IDs on success, false on failure.
 */
function author_kit_get_coauthors_by_post( $post_id ) {
	// create a global of coauthors class.
	global $author_kit_coauthors;

	// Retrieve existing co-authors against specific post ID.
	$coauthors_ids = $author_kit_coauthors->get_coauthors_by_post( $post_id );
	$coauthors_ids = is_array( $coauthors_ids ) ? $coauthors_ids : array();

	return $coauthors_ids;
}


/**
 * Safe wrapper for str_contains() that works in PHP < 8.0.
 *
 * Uses PHP's built-in str_contains() if available, otherwise falls back to strpos().
 *
 * @param string $haystack The string to search in.
 * @param string $needle   The substring to search for.
 * @return bool True if $needle is found in $haystack, false otherwise.
 */
function author_kit_str_contains( string $haystack, string $needle ): bool {
	if ( function_exists( 'str_contains' ) ) {
		return str_contains( $haystack, $needle );
	}

	return '' !== $needle && strpos( $haystack, $needle ) !== false;
}


/**
 * Retrieves the selected author sub-info value (email, company, or job title)
 * based on the active bio template and its associated theme mod setting.
 *
 * @param int $author_id The author user ID.
 * @return string The selected sub-info value, or an empty string on failure.
 */
function author_kit_get_selected_sub_info_field( $author_id ) {
	if ( ! is_numeric( $author_id ) || $author_id <= 0 ) {
		return '';
	}

	// Allowed fields and their corresponding user meta keys.
	$meta_keys = array(
		'email'     => 'author_kit_user_contact_email',
		'company'   => 'author_kit_user_company',
		'job_title' => 'author_kit_author_job_title',
	);

	// Get the currently active bio template (from option).
	$active_template = get_option( 'author_kit_author_bio_template', 'template-default' );

	// Map templates to their corresponding theme mod keys.
	$theme_mod_keys = array(
		'template-default' => 'author_kit_subinfo_default_field_default',
		'template-memoir'  => 'author_kit_subinfo_memoir_field_memoir',
		'template-monarch' => 'author_kit_subinfo_monarch_field_monarch',
	);

	// Get the theme mod key for the selected template.
	$theme_mod_key = $theme_mod_keys[ $active_template ] ?? null;
	if ( ! $theme_mod_key ) {
		return '';
	}

	// Sanitize and validate the selected sub-info field.
	$selected_field = strtolower( trim( get_theme_mod( $theme_mod_key, 'job_title' ) ) );

	// Fallback to 'job_title' if the selected field is invalid.
	if ( ! array_key_exists( $selected_field, $meta_keys ) ) {
		$selected_field = 'job_title';
	}

	// Fetch and return the user meta value.
	$value = get_user_meta( $author_id, $meta_keys[ $selected_field ], true );
	return is_string( $value ) ? $value : '';
}



/**
 * Sorts the template list by moving the activated template to the top.
 *
 * @param array  $templates          Array of templates with 'template_id' keys.
 * @param string $activated_template ID of the currently activated template.
 *
 * @return array Sorted array with the activated template first.
 */
function author_kit_sort_templates( $templates, $activated_template ) {
	usort(
		$templates,
		function ( $a, $b ) use ( $activated_template ) {
			if ( $a['template_id'] === $activated_template ) {
				return -1; // $a comes before $b.
			}
			if ( $b['template_id'] === $activated_template ) {
				return 1; // $b comes before $a.
			}
			return 0; // Keep original order if neither is activated.
		}
	);
	return $templates;
}







/**
 * Filters the default WordPress avatar to display a custom user avatar if available.
 *
 * Replaces the avatar with a user-defined image stored in the `avatar` user meta,
 * falling back to the default avatar if none is set.
 *
 * @param string            $avatar      Default avatar HTML.
 * @param int|object|string $id_or_email User ID, email, or WP_Comment object.
 * @param int               $size        Avatar size in pixels.
 * @param string            $default     Default avatar URL.
 * @param string            $alt         Alternative text for the avatar image.
 *
 * @return string Custom or default avatar HTML.
 */
function author_kit_get_avatar(
	$avatar,
	$id_or_email,
	$size, // phpcs:disable
	$default, 
	$alt // phpcs:enable
) {
	$user = false;

	if ( is_numeric( $id_or_email ) ) {
		// If it's a numeric ID, fetch the user.
		$user = get_user_by( 'id', (int) $id_or_email );
	} elseif ( $id_or_email instanceof WP_Comment ) {
		// If it's a WP_Comment object, extract user ID.
		if ( ! empty( $id_or_email->user_id ) ) {
			$user = get_user_by( 'id', (int) $id_or_email->user_id );
		}
	} elseif ( is_object( $id_or_email ) && property_exists( $id_or_email, 'user_id' ) ) {
		// Fallback check if it's another object with a user_id.
		$user = get_user_by( 'id', (int) $id_or_email->user_id );
	} elseif ( is_string( $id_or_email ) || filter_var( $id_or_email, FILTER_VALIDATE_EMAIL ) ) {
		// If it's an email, fetch user by email.
		$user = get_user_by( 'email', $id_or_email );
	}

	if ( $user ) {
		// Fetch custom avatar URL if available.
		$custom_avatar = get_user_meta( $user->ID, 'avatar', true );

		if ( $custom_avatar ) {
			// Return custom avatar wrapped in a circular div with a specified size.
            // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage
			return '<img src="' . esc_url( $custom_avatar ) . '" alt="' . esc_attr( $alt ) . '" class="custom-avatar" style="width: ' . esc_attr( $size ) . 'px; height: ' . esc_attr( $size ) . 'px; border-radius: 50%; object-fit: cover; align-items: center;">';
		}
	}

	// Return default avatar if no custom avatar is set.
	return $avatar;
}

/**
 * Get the formatted display name for a given author.
 *
 * This function returns the author's display name wrapped in a span element,
 * with proper escaping for HTML output and error handling for invalid author ID.
 *
 * @param int $author_id The ID of the author.
 * @return string HTML-formatted author name or an empty string if invalid.
 */
function author_kit_display_name( $author_id ) {
	// Validate author ID.
	if ( ! is_numeric( $author_id ) || $author_id <= 0 ) {
		return '';
	}

	// Get and escape the display name.
	$author_name = get_the_author_meta( 'display_name', (int) $author_id );

	if ( empty( $author_name ) ) {
		return '';
	}

	$author_name = esc_html( $author_name );

	// Return formatted HTML.
	return "<span class='author-name' itemprop='name'>{$author_name}</span>";
}





/**
 * Outputs styled pagination links for archive pages.
 *
 * Generates pagination with custom classes and safely renders
 * allowed HTML tags using `wp_kses`.
 *
 * @return void
 */
function author_kit_pagination() {
	$allowed_tags = array(
		'span' => array( 'class' => array() ),
		'a'    => array(
			'class' => array(),
			'href'  => array(),
		),
	);

	$args = array(
		'mid_size'           => 2,
		'prev_text'          => '<span class="author-kit-pagination-prev">« Previous</span>',
		'next_text'          => '<span class="author-kit-pagination-next">Next »</span>',
		'before_page_number' => '<span class="author-kit-pagination-page">',
		'after_page_number'  => '</span>',
	);

	printf( '<nav class="author-kit-pagination clearfix">%s</nav>', wp_kses( paginate_links( $args ), $allowed_tags ) );
}

/**
 * Retrieves and caches author social profiles with enriched platform data.
 *
 * @param int $author_id The author ID.
 * @return array<string, array{url: string, name: string, fa_icon: string, color: string}>
 */
function author_kit_get_social_profiles( $author_id ) {
	static $cache = array();

	// Ensure $author_id is valid.
	$author_id = (int) $author_id;
	if ( $author_id <= 0 ) {
		return array();
	}

	if ( isset( $cache[ $author_id ] ) ) {
		return $cache[ $author_id ];
	}

	// Step 1: Get user-entered URLs from meta.
	$raw_user_links = get_user_meta( $author_id, 'author_kit_user_social_profiles', true );
	if ( ! is_array( $raw_user_links ) ) {
		$raw_user_links = array();
	}

	// Step 2: Get platform meta (icon, color, name).
	$platform_meta = get_transient( 'author_kit_selected_platforms_meta' );
	if ( ! is_array( $platform_meta ) ) {
		$platform_meta = get_option( 'author_kit_selected_platforms_meta', array() );
	}

	$final_profiles = array();

	foreach ( $raw_user_links as $platform_slug => $url ) {
		if ( ! is_string( $url ) || empty( $url ) ) {
			// continue;
		}

		// Get platform metadata.
		$meta = is_array( $platform_meta[ $platform_slug ] ?? null ) ? $platform_meta[ $platform_slug ] : array();

		$final_profiles[ $platform_slug ] = array(
			'url'     => esc_url_raw( $url ),
			'name'    => sanitize_text_field( $meta['name'] ?? ucfirst( $platform_slug ) ),
			'fa_icon' => sanitize_text_field( $meta['fa_icon'] ?? '' ),
			'color'   => sanitize_hex_color( $meta['color'] ?? '#000000' ),
		);
	}

	$cache[ $author_id ] = $final_profiles;

	return $final_profiles;
}


/**
 * Retrieves link attributes for author kit links.
 *
 * @return array Associative array of link attributes.
 */
function author_kit_get_link_attributes() {
	static $cache = null;

	// Use in-memory cache.
	if ( null !== $cache ) {
		return $cache;
	}

	// Fetch from transient or fallback to option.
	$saved_link_attributes = get_transient( 'author_kit_link_attributes' );

	if ( false === $saved_link_attributes || ! is_array( $saved_link_attributes ) ) {
		$saved_link_attributes = get_option(
			'author_kit_link_attributes',
			array(
				'target' => '_blank',
				'rel'    => array( 'noopener', 'noreferrer' ),
			)
		);

		// Ensure array structure.
		if ( ! is_array( $saved_link_attributes ) ) {
			$saved_link_attributes = array(
				'target' => '_blank',
				'rel'    => array( 'noopener', 'noreferrer' ),
			);
		}

		// Store in transient for future performance optimization.
		set_transient( 'author_kit_link_attributes', $saved_link_attributes, HOUR_IN_SECONDS );
	}

	// Store in static cache.
	$cache = $saved_link_attributes;

	return $saved_link_attributes;
}


/**
 * Retrieves the preferred URL for a given author based on their saved preference.
 *
 * @param int $author_id The ID of the author.
 * @return string The preferred URL (custom, author archive, or home page).
 */
function author_kit_get_preferred_url( $author_id ) {
	// Validate and sanitize author ID.
	$author_id = absint( $author_id );
	if ( ! $author_id ) {
		return home_url(); // Default to home page if invalid ID.
	}

	// Fetch the author's link preference.
	$preference = get_user_meta( $author_id, 'author_kit_name_link_preference', true );

	switch ( $preference ) {
		case 'custom_url':
			// Fetch and validate custom URL.
			$custom_url = esc_url( get_user_meta( $author_id, 'author_kit_custom_url', true ) );
			return ! empty( $custom_url ) ? $custom_url : home_url();

		case 'author_archive':
			return get_author_posts_url( $author_id );

		case 'home_page':
		default:
			return home_url();
	}
}


/**
 * Clears cached customizer CSS for selected templates.
 *
 * Deletes transients storing inline CSS for author bio, archive, and byline templates
 * to ensure updated styles are applied.
 *
 * @return void
 */
function author_kit_clear_customizer_css_cache() {
	$bio_template     = get_option( 'author_kit_author_bio_template', 'template-default' );
	$archive_template = get_option( 'author_kit_author_archive_template', 'archive-template-default' );
	$byline_template  = get_option( 'author_kit_custom_byline_template', 'template-default' );

	$cache_keys = array(
		'author_kit_inline_css_' . $bio_template,
		'author_kit_inline_css_' . $archive_template,
		'author_kit_byline_inline_css_' . $byline_template,
	);

	foreach ( $cache_keys as $cache_key ) {
		delete_transient( $cache_key );
	}
}

/**
 * Clears customizer CSS cache when a related option value changes.
 *
 * Invokes the cache clearing function only if the option value is updated.
 *
 * @param mixed $old_value Previous option value.
 * @param mixed $new_value New option value.
 *
 * @return void
 */
function author_kit_clear_css_cache_on_option_change( $old_value, $new_value ) {
	// Only clear if value actually changed.
	if ( $old_value !== $new_value ) {
		author_kit_clear_customizer_css_cache();
	}
}

/**
 * Checks if the current admin screen is part of the Author Kit plugin.
 *
 * Returns true if the current admin page belongs to Author Kit based on screen ID.
 *
 * @return bool True if it's an Author Kit admin page, false otherwise.
 */
function author_kit_admin_page() {
	if ( ! is_admin() ) {
		return false; // Only check in the admin panel.
	}

	$screen = get_current_screen(); // Get the current screen object.

	if ( ! $screen || empty( $screen->id ) ) {
		return false;
	}

	return strpos( $screen->id, 'author-kit' ) !== false;
}

/**
 * Retrieves bio template settings for the Author Kit bio box.
 *
 * Fetches style and display settings from the Customizer for the given template.
 * If no template is specified, uses the currently activated template.
 * Falls back to default values if customizer settings are not set.
 *
 * @param string|null $template Optional. Template ID (e.g., 'template-default').
 * @return array Associative array of bio box settings including icons style, heading visibility, text, and colors.
 */
function author_kit_get_bio_template_settings( $template = null ) {
	if ( ! $template ) {
		$template = get_option( 'author_kit_author_bio_template', 'template-default' );
	}

	$template     = sanitize_text_field( $template );
	$template_key = str_replace( 'template-', '', $template );

	$defaults = array(
		'default' => array(
			'icons_style'     => 'author-kit-circle',
			'hide_heading'    => 0,
			'heading_text'    => 'About Author',
			'icons_color'     => '#ffffff',
			'container_color' => '#000000',
		),
		'monarch' => array(
			'icons_style'     => 'author-kit-square',
			'hide_heading'    => 0,
			'heading_text'    => 'About Me',
			'icons_color'     => '#ffffff',
			'container_color' => '#677D6A',
		),
		'memoir'  => array(
			'icons_style'     => 'author-kit-square',
			'hide_heading'    => 0,
			'heading_text'    => 'About Writer',
			'icons_color'     => '#ffffff',
			'container_color' => '#1e73be',
		),
	);

	// Get fallback values.
	$default_values = $defaults[ $template_key ] ?? $defaults['default'];

	// Map of Customizer keys.
	$customizer_keys = array(
		'icons_style'     => "author_kit_icons_style_{$template_key}",
		'hide_heading'    => "author_kit_bio_box_hide_heading_{$template_key}",
		'heading_text'    => "author_kit_bio_box_heading_text_{$template_key}",
		'icons_color'     => "author_kit_icons_color_{$template_key}",
		'container_color' => "author_kit_icons_container_color_{$template_key}",
	);

	// Fetch values from Customizer with fallback.
	$settings = array();
	foreach ( $customizer_keys as $key => $theme_mod_key ) {
		$default          = $default_values[ $key ] ?? '';
		$settings[ $key ] = get_theme_mod( $theme_mod_key, $default );
	}

	return $settings;
}

/**
 * Get a preview URL for the given user based on type.
 *
 * @param int|null $user_id Optional. Specify a user ID. Defaults to current user.
 * @param string   $type     'bio' or 'archive_page'. Defaults to 'bio'.
 * @return string|false      URL or false on failure.
 */
function author_kit_get_customizer_preview_url( $user_id = null, $type = 'bio' ) {
	if ( ! $user_id ) {
		$user_id = get_current_user_id();
	}

	$user = get_userdata( $user_id );

	if ( ! $user || ! ( $user instanceof WP_User ) || empty( $user->ID ) ) {
		return false;
	}

	switch ( $type ) {
		case 'archive_page':
			// Use built-in WordPress function to get author archive URL.
			$author_url = get_author_posts_url( $user->ID );
			if ( $author_url && filter_var( $author_url, FILTER_VALIDATE_URL ) ) {
				return $author_url;
			}
			return false;

		case 'bio':
			// Get latest published post from the user.
			$posts = get_posts(
				array(
					'author'         => $user->ID,
					'post_type'      => 'post',
					'post_status'    => 'publish',
					'posts_per_page' => 1,
					'orderby'        => 'date',
					'order'          => 'DESC',
					'fields'         => 'ids',
				)
			);

			if ( ! empty( $posts ) ) {
				return get_permalink( $posts[0] );
			}
			return false;

		default:
			return false;
	}
}



/**
 * Check and update the byline compatibility status for the current theme.
 *
 * Compares the current normalized theme name with the last checked theme.
 * If different, updates the compatibility status option based on availability
 * in the known compatible themes list, and saves the current theme as last checked.
 *
 * Does not remove any manual selectors on theme change.
 *
 * @return void
 */
function author_kit_update_compatibility_status() {
	$available_options = include AUTHOR_KIT_PLUGIN_PATH . 'includes/core/compatible-themes.php';

	$normalized_theme   = ucwords( strtolower( wp_get_theme()->get( 'Name' ) ) );
	$last_checked_theme = get_option( 'author_kit_last_checked_theme' );

	if ( $last_checked_theme !== $normalized_theme ) {
		$status = isset( $available_options[ $normalized_theme ] ) ? 'Compatible' : 'Incompatible';
		update_option( 'author_kit_byline_compatibility_status', $status );
		update_option( 'author_kit_last_checked_theme', $normalized_theme );
		// Do not delete manual selector on theme change.
	}
}

/**
 * Hook into 'init' to ensure theme compatibility status is updated if theme has changed.
 *
 * This serves as a fallback to handle cases where the 'after_switch_theme' hook
 * or plugin activation hook might be missed (e.g., during multisite activation or manual DB reset).
 *
 * Checks if the current theme is different from the last one recorded,
 * and triggers a compatibility status update if needed.
 *
 * @hook init
 */
add_action(
	'init',
	function () {
		$normalized_theme   = ucwords( strtolower( wp_get_theme()->get( 'Name' ) ) );
		$last_checked_theme = get_option( 'author_kit_last_checked_theme' );

		if ( $last_checked_theme !== $normalized_theme ) {
			author_kit_update_compatibility_status();
		}
	},
	20
);


/**
 * Refresh Author Kit byline compatibility and selector cache on theme switch.
 */
function author_kit_on_theme_switch() {
	$available_options = include AUTHOR_KIT_PLUGIN_PATH . 'includes/core/compatible-themes.php';
	$theme_object      = wp_get_theme();
	$normalized_theme  = ucwords( strtolower( $theme_object->get( 'Name' ) ) );

	// Get selector for this theme or fallback to Default.
	$selector = $available_options[ $normalized_theme ] ?? $available_options['Default'];

	// Cache theme-based selector.
	set_transient( 'author_kit_theme_byline_selector', $selector, MONTH_IN_SECONDS );

	// Store user-defined selector per theme (if exists).
	$current_user_selector = get_option( 'author_kit_byline_display_location' );
	if ( ! empty( $current_user_selector ) ) {
		$user_defined_selectors                      = get_option( 'author_kit_byline_custom_selectors', array() );
		$user_defined_selectors[ $normalized_theme ] = sanitize_text_field( $current_user_selector );
		update_option( 'author_kit_byline_custom_selectors', $user_defined_selectors );
	}
}
add_action( 'after_switch_theme', 'author_kit_on_theme_switch' );





/**
 * Renders the Author Kit admin page notices related to Kirki dependency.
 *
 * This function checks the availability and version of the Kirki plugin, which is required
 * for Customizer-based features (like template customization). Based on its status
 * (not installed, installed but inactive, outdated, or active but broken),
 * the appropriate admin notice is displayed.
 *
 * @return void
 */
function author_kit_render_error() {
	echo '<div class="wrap">';

	// Ensure required functions are loaded
	if ( ! function_exists( 'is_plugin_active' ) || ! function_exists( 'get_plugins' ) ) {
		require_once ABSPATH . 'wp-admin/includes/plugin.php';
	}

	$kirki_plugin       = 'kirki/kirki.php';
	$all_plugins        = get_plugins();
	$is_kirki_installed = isset( $all_plugins[ $kirki_plugin ] );
	$is_kirki_active    = is_plugin_active( $kirki_plugin );
	$kirki_version      = $is_kirki_installed ? $all_plugins[ $kirki_plugin ]['Version'] : null;
	$required_version   = '5.1.0'; // Required minimum Kirki version

	// Case: Kirki class not loaded
	if ( ! class_exists( 'Kirki' ) ) {

		if ( $is_kirki_active ) {
			printf(
				'<div class="notice notice-error is-dismissible"><p>%s</p></div>',
				esc_html__( 'Author Kit relies on the Kirki Customizer Framework (v5.1.0) for template customization, but Kirki appears to be active and not properly initialized. Please check for plugin conflicts or reinstall Kirki.', 'author-kit' )
			);
		} elseif ( $is_kirki_installed ) {
			printf(
				'<div class="notice notice-warning is-dismissible"><p>%s</p></div>',
				esc_html__( 'Author Kit uses the Kirki Customizer Framework (v5.1.0) for template customization. Please activate the Kirki plugin to enable customizer features.', 'author-kit' )
			);
		} else {
			printf(
				'<div class="notice notice-error is-dismissible"><p>%s</p></div>',
				esc_html__( 'Author Kit uses the Kirki Customizer Framework (v5.1.0) for template customization. Please install it from WordPress.org and activate to customize.', 'author-kit' )
			);
		}

		// Case: Kirki is active but version is outdated
	} elseif ( version_compare( $kirki_version, $required_version, '<' ) ) {
		printf(
			'<div class="notice notice-warning is-dismissible"><p>%s</p></div>',
			sprintf(
				/* translators: 1: required Kirki version, 2: current Kirki version */
				esc_html__( 'Author Kit requires Kirki version %1$s or higher. You are using version %2$s. Please update the Kirki plugin to ensure compatibility with template customization features.', 'author-kit' ),
				esc_html( $required_version ),
				esc_html( $kirki_version )
			)
		);
	}

	echo '</div>';
}


/**
 * Check if the Kirki plugin is installed, active, and meets the required version.
 *
 * @return bool True if Kirki is installed, active, and version is >= required; false otherwise.
 */
function author_kit_kirki_active() {
	$kirki_plugin     = 'kirki/kirki.php';
	$required_version = '5.0.0';

	$all_plugins        = get_plugins();
	$is_kirki_installed = isset( $all_plugins[ $kirki_plugin ] );
	$is_kirki_active    = is_plugin_active( $kirki_plugin );
	$kirki_version      = $is_kirki_installed ? $all_plugins[ $kirki_plugin ]['Version'] : null;

	return ( $is_kirki_installed && $is_kirki_active && version_compare( $kirki_version, $required_version, '>=' ) );
}





/**
 * Display a warning notice if Kirki is not installed or not active.
 *
 * This notice is shown on the Plugins admin page only to users with the `activate_plugins` capability.
 * It informs users that the Kirki plugin is required for template customization in Author Kit.
 *
 * @since 1.0.0
 */
add_action( 'admin_notices', 'author_kit_show_kirki_notice_on_plugins_page' );
function author_kit_show_kirki_notice_on_plugins_page() {
	global $pagenow;

	// Show only on the plugins page for users who can activate plugins
	if ( $pagenow !== 'plugins.php' || ! current_user_can( 'activate_plugins' ) ) {
		return;
	}

	$kirki_plugin       = 'kirki/kirki.php';
	$all_plugins        = get_plugins();
	$is_kirki_installed = isset( $all_plugins[ $kirki_plugin ] );
	$is_kirki_active    = is_plugin_active( $kirki_plugin );

	if ( ! $is_kirki_installed ) {
		?>
		<div class="notice notice-warning is-dismissible">
			<p>
				<strong><?php esc_html_e( 'Author Kit:', 'author-kit' ); ?></strong>
				<?php esc_html_e( 'The Kirki Customizer plugin is not installed. Author Kit uses Kirki for template customization. Please install it from WordPress.org to enable these features.', 'author-kit' ); ?>
			</p>
		</div>
		<?php
	} elseif ( ! $is_kirki_active ) {
		?>
		<div class="notice notice-warning is-dismissible">
			<p>
				<strong><?php esc_html_e( 'Author Kit:', 'author-kit' ); ?></strong>
				<?php esc_html_e( 'The Kirki Customizer plugin is installed but not active. Author Kit uses Kirki for template customization. Please activate it to enable these features.', 'author-kit' ); ?>
			</p>
		</div>
		<?php
	}
}
