<?php

/**
 * Download webfonts locally with improved performance and compatibility.
 *
 * @package neatnote/font-loader
 * @license https://opensource.org/licenses/MIT
 */

/**
 * WebFont Loader Class
 *
 * This class handles downloading, caching, and serving webfonts locally
 * for improved performance, privacy, and to reduce third-party dependencies.
 *
 * @package NeatNote
 * @since 1.0.0
 */

if (! class_exists('NeatNote_WebFont_Loader')) {

	/**
	 * NeatNote WebFont Loader Class
	 */
	class NeatNote_WebFont_Loader
	{

		/**
		 * Font format (default: 'woff2')
		 *
		 * @var string
		 */
		protected $font_format = 'woff2';

		/**
		 * Remote URL for the font CSS file
		 *
		 * @var string
		 */
		protected $remote_url;

		/**
		 * Local path for the cached stylesheet
		 *
		 * @var string
		 */
		protected $local_stylesheet_path;

		/**
		 * Holds remote CSS content
		 *
		 * @var string
		 */
		protected $remote_styles;

		/**
		 * Generated CSS content
		 *
		 * @var string
		 */
		protected $css;

		/**
		 * Constructor method
		 *
		 * Initializes the class with the remote font URL and format.
		 * Registers a cleanup action for deleting cached fonts.
		 *
		 * @param string $url    Remote URL of the font stylesheet.
		 * @param string $format Font format type (e.g., 'woff2', 'woff').
		 */
		public function __construct($url = '', $format = 'woff2')
		{
			$this->remote_url = esc_url_raw($url);
			$this->font_format = sanitize_text_field($format);

			// Register cleanup event to remove unused font files
			add_action('neatnote_delete_fonts_folder', [$this, 'delete_fonts_folder']);
		}

		/**
		 * Retrieves webfont styles or creates a local stylesheet if none exists.
		 *
		 * @return string CSS content for webfonts.
		 */
		public function get_styles()
		{
			// Check if the local stylesheet already exists
			$local_stylesheet_contents = $this->get_local_stylesheet_contents();
			if ($local_stylesheet_contents) {
				return $local_stylesheet_contents;
			}

			// Return early if no remote styles are available
			if (empty($this->remote_styles)) {
				return '';
			}

			// Generate local file paths from remote URLs
			$files = $this->get_local_files_from_css();

			// Replace remote URLs with local file paths
			foreach ($files as $remote => $local) {
				$files[$remote] = str_replace(
					$this->get_base_path(),
					$this->get_base_url(),
					$local
				);
			}

			// Update the CSS with replaced URLs
			$this->css = str_replace(
				array_keys($files),
				array_values($files),
				$this->remote_styles
			);

			// Write the CSS to a local file for caching
			$this->write_stylesheet();

			return $this->css;
		}

		/**
		 * Writes the generated CSS to a local file for improved performance.
		 *
		 * @return string|false Path to the saved stylesheet or false on failure.
		 */
		protected function write_stylesheet()
		{
			$file_path = $this->get_local_stylesheet_path();
			$filesystem = $this->get_filesystem();

			// Create the file if it doesn't exist
			if (! file_exists($file_path) && ! $filesystem->touch($file_path)) {
				return false;
			}

			// Write the CSS content into the file
			if (! $filesystem->put_contents($file_path, $this->css)) {
				return false;
			}

			return $file_path;
		}

		/**
		 * Deletes the stored fonts folder for cleanup purposes.
		 *
		 * @return bool True on success, false on failure.
		 */
		public function delete_fonts_folder()
		{
			return $this->get_filesystem()->delete($this->get_fonts_folder(), true);
		}

		/**
		 * Returns WordPress filesystem instance.
		 *
		 * Ensures WordPress filesystem is properly loaded and available.
		 *
		 * @return WP_Filesystem_Base
		 */
		protected function get_filesystem()
		{
			global $wp_filesystem;

			// Load WordPress filesystem functions if not already available
			if (! $wp_filesystem) {
				if (! function_exists('WP_Filesystem')) {
					require_once ABSPATH . 'wp-admin/includes/file.php';
				}
				WP_Filesystem();
			}

			return $wp_filesystem;
		}

		/**
		 * Retrieves the contents of the locally stored stylesheet.
		 *
		 * @return string CSS content or an empty string if not found.
		 */
		protected function get_local_stylesheet_contents()
		{
			$local_path = $this->get_local_stylesheet_path();
			return file_exists($local_path) ? file_get_contents($local_path) : '';
		}

		/**
		 * Extracts font file URLs from CSS content.
		 *
		 * @return array List of remote URLs mapped to local file paths.
		 */
		protected function get_local_files_from_css()
		{
			return [];
		}

		/**
		 * Retrieves the local fonts folder path.
		 *
		 * @return string Path to the local fonts folder.
		 */
		protected function get_base_path()
		{
			return WP_CONTENT_DIR . '/fonts';
		}

		/**
		 * Retrieves the URL path for locally stored fonts.
		 *
		 * @return string URL for the fonts folder.
		 */
		protected function get_base_url()
		{
			return content_url('/fonts');
		}

		/**
		 * Retrieves the full path to the fonts folder.
		 *
		 * @return string Path to the local fonts folder.
		 */
		protected function get_fonts_folder()
		{
			return $this->get_base_path();
		}

		/**
		 * Retrieves the path to the local stylesheet file.
		 *
		 * @return string Path to the generated local stylesheet.
		 */
		protected function get_local_stylesheet_path()
		{
			if (! $this->local_stylesheet_path) {
				$this->local_stylesheet_path = $this->get_fonts_folder() . '/' . md5($this->remote_url) . '.css';
			}
			return $this->local_stylesheet_path;
		}
	}
}

/**
 * Helper function to retrieve webfont styles.
 *
 * @param string $url    Remote URL of the font stylesheet.
 * @param string $format Font format type (e.g., 'woff2', 'woff').
 * @return string CSS content for webfonts.
 */
if (! function_exists('neatnote_get_webfont_styles')) {
	function neatnote_get_webfont_styles($url, $format = 'woff2')
	{
		$font = new NeatNote_WebFont_Loader($url, $format);
		return $font->get_styles();
	}
}

/**
 * Helper function to retrieve the local webfont URL.
 *
 * @param string $url    Remote URL of the font stylesheet.
 * @param string $format Font format type (e.g., 'woff2', 'woff').
 * @return string URL for the locally cached webfont stylesheet.
 */
if (! function_exists('neatnote_get_webfont_url')) {
	function neatnote_get_webfont_url($url, $format = 'woff2')
	{
		$font = new NeatNote_WebFont_Loader($url, $format);
		return $font->get_styles();
	}
}
