<?php
/**
 * Cache module — Resource hints (preconnect / dns-prefetch / preload)
 *
 * Two integration points:
 *   1. `wp_resource_hints` filter — declarative WP-native API for preconnect
 *      and dns-prefetch. Cleanest path; cooperates with other plugins.
 *   2. `wp_head` direct echo — for `<link rel="preload" as="font">` (no
 *      WP-native API for font preloads yet).
 *
 * @package BlaminhorEssentials
 */

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

class Blaminhor_Essentials_Cache_Resource_Hints {

	/** @var Blaminhor_Essentials_Module_Cache */
	private $parent;

	public function __construct( Blaminhor_Essentials_Module_Cache $parent ) {
		$this->parent = $parent;
	}

	public function register_hooks() {
		add_filter( 'wp_resource_hints', array( $this, 'add_resource_hints' ), 10, 2 );
		add_action( 'wp_head', array( $this, 'output_font_preloads' ), 1 );
	}

	/**
	 * Append user-declared preconnect / dns-prefetch entries to WordPress's
	 * own resource_hints output.
	 *
	 * @param array  $urls          Existing hint URLs (or arrays).
	 * @param string $relation_type 'preconnect'|'dns-prefetch'|'prefetch'|'prerender'|'preload'.
	 * @return array
	 */
	public function add_resource_hints( $urls, $relation_type ) {
		// Bypass for admins / logged-in users — let WordPress emit only its
		// native resource hints so the request matches what an as-is debug
		// session expects.
		if ( $this->parent->should_skip_runtime_optimizations() ) {
			return $urls;
		}
		// Bail if our setting is empty for this type.
		$key = '';
		if ( 'preconnect' === $relation_type ) {
			$key = 'preconnect_domains';
		} elseif ( 'dns-prefetch' === $relation_type ) {
			$key = 'dns_prefetch_domains';
		}
		if ( '' === $key ) {
			return $urls;
		}

		$raw = (string) $this->parent->get_setting( $key, '' );
		foreach ( preg_split( '/[\r\n]+/', $raw ) as $line ) {
			$line = trim( $line );
			if ( '' === $line || 0 === strpos( $line, '#' ) ) {
				continue;
			}
			// Auto-prefix bare domains with the right scheme for preconnect.
			if ( 'preconnect' === $relation_type && false === strpos( $line, '://' ) ) {
				$line = 'https://' . $line;
			}
			$urls[] = $line;
		}

		// Cap at 6 to avoid waste / diminishing returns.
		if ( 'preconnect' === $relation_type && count( $urls ) > 6 ) {
			$urls = array_slice( $urls, 0, 6 );
		}

		return $urls;
	}

	/**
	 * Echo `<link rel="preload" as="font">` tags for user-declared fonts.
	 */
	public function output_font_preloads() {
		// Bypass: an admin browsing the front-end must see the page exactly as
		// WordPress emits it, without our extra preload hints.
		if ( $this->parent->should_skip_runtime_optimizations() ) {
			return;
		}
		$raw = (string) $this->parent->get_setting( 'preload_fonts', '' );
		foreach ( preg_split( '/[\r\n]+/', $raw ) as $line ) {
			$line = trim( $line );
			if ( '' === $line || 0 === strpos( $line, '#' ) ) {
				continue;
			}
			$type = $this->guess_font_type( $line );
			$crossorigin = ' crossorigin'; // Required for preloaded fonts.
			printf(
				'<link rel="preload" as="font" href="%s" type="%s"%s>' . "\n",
				esc_url( $line ),
				esc_attr( $type ),
				esc_attr( $crossorigin )
			);
		}
	}

	/**
	 * @param string $url
	 * @return string MIME type matching the URL extension.
	 */
	private function guess_font_type( $url ) {
		$ext = strtolower( pathinfo( wp_parse_url( $url, PHP_URL_PATH ), PATHINFO_EXTENSION ) );
		switch ( $ext ) {
			case 'woff2': return 'font/woff2';
			case 'woff':  return 'font/woff';
			case 'ttf':   return 'font/ttf';
			case 'otf':   return 'font/otf';
			default:      return 'font/woff2';
		}
	}
}
