<?php
/**
 * Apple touch icon generation and root-path delivery.
 *
 * @package FansPaysite
 * @since   2.7.6
 */

/**
 * Get the Media Library attachment used to build a touch icon.
 *
 * A custom touch icon takes priority. When it is missing, the WordPress Site
 * Icon is used, followed by the site logo, unless automatic generation has
 * been disabled in Customizer.
 *
 * @return int Attachment ID, or zero when no usable source is configured.
 */
function fanspaysite_get_touch_icon_source_id() {
	$attachment_id = absint( get_theme_mod( 'fanspaysite_apple_touch_icon', 0 ) );

	if ( $attachment_id && wp_attachment_is_image( $attachment_id ) ) {
		return $attachment_id;
	}

	if ( ! get_theme_mod( 'fanspaysite_generate_touch_icons', true ) ) {
		return 0;
	}

	$site_icon_id = absint( get_option( 'site_icon', 0 ) );
	if ( $site_icon_id && wp_attachment_is_image( $site_icon_id ) ) {
		return $site_icon_id;
	}

	$logo_id = absint( get_theme_mod( 'custom_logo', 0 ) );
	return $logo_id && wp_attachment_is_image( $logo_id ) ? $logo_id : 0;
}

/**
 * Get the generated PNG path for a touch icon, creating it when necessary.
 *
 * @return string Empty string when no icon can be generated.
 */
function fanspaysite_get_touch_icon_path() {
	$source_id = fanspaysite_get_touch_icon_source_id();

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

	$source_path = get_attached_file( $source_id );
	if ( ! $source_path || ! is_readable( $source_path ) ) {
		return '';
	}

	$uploads = wp_upload_dir();
	if ( ! empty( $uploads['error'] ) || empty( $uploads['basedir'] ) ) {
		return '';
	}

	$cache_dir    = trailingslashit( $uploads['basedir'] ) . 'fanspaysite-touch-icons';
	$cache_path   = trailingslashit( $cache_dir ) . 'apple-touch-icon.png';
	$source_mtime = filemtime( $source_path );
	$source_size  = filesize( $source_path );
	$signature    = $source_id . ':' . (int) $source_mtime . ':' . (int) $source_size;
	$cache_meta   = get_option( 'fanspaysite_touch_icon_cache', array() );

	if ( is_readable( $cache_path ) && isset( $cache_meta['shared'] ) && hash_equals( (string) $cache_meta['shared'], $signature ) ) {
		return $cache_path;
	}

	if ( ! wp_mkdir_p( $cache_dir ) ) {
		return '';
	}

	$image = wp_get_image_editor( $source_path );
	if ( is_wp_error( $image ) ) {
		return '';
	}

	$size = $image->get_size();
	if ( empty( $size['width'] ) || empty( $size['height'] ) ) {
		return '';
	}

	// Apple touch icons are square. Use a centered square crop without distortion.
	$crop_size = min( (int) $size['width'], (int) $size['height'] );
	$crop_x    = (int) floor( ( (int) $size['width'] - $crop_size ) / 2 );
	$crop_y    = (int) floor( ( (int) $size['height'] - $crop_size ) / 2 );
	$cropped   = $image->crop( $crop_x, $crop_y, $crop_size, $crop_size, 180, 180 );

	if ( is_wp_error( $cropped ) ) {
		return '';
	}

	$saved = $image->save( $cache_path, 'image/png' );
	if ( is_wp_error( $saved ) || empty( $saved['path'] ) || ! is_readable( $saved['path'] ) ) {
		return '';
	}

	$cache_meta['shared'] = $signature;
	update_option( 'fanspaysite_touch_icon_cache', $cache_meta, false );

	return $saved['path'];
}

/**
 * Generate the shared touch icon after Customizer settings are saved.
 *
 * @return void
 */
function fanspaysite_refresh_touch_icons() {
	fanspaysite_get_touch_icon_path();
}
add_action( 'customize_save_after', 'fanspaysite_refresh_touch_icons' );

/**
 * Remove WordPress's Media Library apple-touch-icon tag when the theme's
 * canonical root-path icon is available.
 *
 * @param string[] $meta_tags Site icon meta tags.
 * @return string[]
 */
function fanspaysite_filter_site_icon_meta_tags( $meta_tags ) {
	if ( ! fanspaysite_get_touch_icon_path() ) {
		return $meta_tags;
	}

	foreach ( $meta_tags as $key => $meta_tag ) {
		if ( false !== strpos( $meta_tag, 'rel="apple-touch-icon"' ) ) {
			unset( $meta_tags[ $key ] );
		}
	}

	return $meta_tags;
}
add_filter( 'site_icon_meta_tags', 'fanspaysite_filter_site_icon_meta_tags' );

/**
 * Advertise the exact root-path touch icon URLs in the document head.
 *
 * @return void
 */
function fanspaysite_output_touch_icon_links() {
	if ( fanspaysite_get_touch_icon_path() ) {
		echo '<link rel="apple-touch-icon" sizes="180x180" href="' . esc_url( home_url( '/apple-touch-icon.png' ) ) . '">' . "\n";
		echo '<link rel="apple-touch-icon-precomposed" sizes="180x180" href="' . esc_url( home_url( '/apple-touch-icon-precomposed.png' ) ) . '">' . "\n";
	}
}
add_action( 'wp_head', 'fanspaysite_output_touch_icon_links', 99 );

/**
 * Identify a touch icon request at the site's root path.
 *
 * @return string Icon type, or an empty string for unrelated requests.
 */
function fanspaysite_get_requested_touch_icon_type() {
	if ( empty( $_SERVER['REQUEST_URI'] ) ) {
		return '';
	}

	$request_uri  = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) );
	$request_path = wp_parse_url( $request_uri, PHP_URL_PATH );
	$home_path    = wp_parse_url( home_url( '/' ), PHP_URL_PATH );
	$home_path    = '/' . trim( (string) $home_path, '/' );
	$home_path    = '/' === $home_path ? '/' : trailingslashit( $home_path );

	if ( $request_path === $home_path . 'apple-touch-icon.png' ) {
		return 'standard';
	}

	if ( $request_path === $home_path . 'apple-touch-icon-precomposed.png' ) {
		return 'precomposed';
	}

	return '';
}

/**
 * Serve generated touch icons at the conventional root filenames.
 *
 * Missing files normally reach WordPress through its existing front-controller
 * rewrite, so no rewrite rule or permalink flush is required.
 *
 * @return void
 */
function fanspaysite_maybe_serve_touch_icon() {
	$type = fanspaysite_get_requested_touch_icon_type();
	if ( ! $type ) {
		return;
	}

	$path = fanspaysite_get_touch_icon_path();
	if ( ! $path ) {
		return;
	}

	$file_mtime = filemtime( $path );
	$file_size  = filesize( $path );
	$etag       = '"' . md5( (string) $file_mtime . ':' . (string) $file_size ) . '"';

	if ( ! empty( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) {
		$if_none_match = sanitize_text_field( wp_unslash( $_SERVER['HTTP_IF_NONE_MATCH'] ) );
		if ( hash_equals( $etag, $if_none_match ) ) {
			status_header( 304 );
			exit;
		}
	}

	$request_method = isset( $_SERVER['REQUEST_METHOD'] ) ? sanitize_key( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) : 'get';
	$file_contents  = null;

	// The generated file is a bounded 180x180 PNG, so reading it once is safe.
	if ( 'head' !== $request_method ) {
		$file_contents = file_get_contents( $path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Reads only the theme's small generated PNG cache file.
		if ( false === $file_contents ) {
			status_header( 500 );
			exit;
		}

		$file_size = strlen( $file_contents );
	}

	status_header( 200 );
	header( 'Content-Type: image/png' );
	header( 'Content-Length: ' . (string) $file_size );
	header( 'Cache-Control: public, max-age=86400' );
	header( 'ETag: ' . $etag );
	header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $file_mtime ) . ' GMT' );
	header( 'X-Content-Type-Options: nosniff' );

	if ( 'head' !== $request_method ) {
		echo $file_contents; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Binary PNG data cannot be escaped.
	}

	exit;
}
add_action( 'parse_request', 'fanspaysite_maybe_serve_touch_icon', 0 );
