<?php
/**
 * CacheLoop – Nginx Cache Rules
 *
 * Generates Nginx configuration snippets for browser caching and fastcgi caching.
 *
 * @package CacheLoop
 */

// Security: Prevent direct file access.
defined( 'ABSPATH' ) || exit;

/**
 * Class CACHELOOP_Nginx_Cache
 *
 * Generates Nginx configuration snippets for CacheLoop.
 */
class CACHELOOP_Nginx_Cache {

	/**
	 * Generates Nginx browser cache rules.
	 *
	 * @param array $settings Plugin settings.
	 * @return string Nginx configuration snippet.
	 */
	public static function get_browser_cache_rules( $settings = array() ) {
		$gzip    = isset( $settings['gzip'] ) && $settings['gzip'];
		$browser = isset( $settings['browser_cache'] ) && $settings['browser_cache'];

		$rules  = "# CacheLoop Nginx Browser Cache Rules\n";
		$rules .= '# Generated on ' . gmdate( 'Y-m-d H:i:s' ) . " UTC\n\n";

		// Gzip compression.
		if ( $gzip ) {
			$rules .= "# Gzip Compression\n";
			$rules .= "gzip on;\n";
			$rules .= "gzip_types text/plain text/css application/javascript application/json image/svg+xml;\n";
			$rules .= "gzip_vary on;\n";
			$rules .= "gzip_min_length 256;\n\n";
		}

		// Browser cache for static assets. Deliberately no `location /` block
		// here: this snippet is meant to be pasted into an *existing* Nginx
		// server block for a WordPress site, which already has its own
		// `location /` routing permalinks through index.php
		// (try_files $uri $uri/ /index.php?$args;). A second, plugin-generated
		// `location /` — especially one that falls back to index.html instead
		// of index.php — both duplicates that routing and, being a second
		// `location /` in the same server block, makes Nginx refuse to load
		// the config at all ("duplicate location \"/\""). Static-asset
		// caching is the one thing this plugin can safely add without risking
		// a collision with whatever the user's server block already does.
		// One `add_header Cache-Control` line, not `expires` + `add_header`:
		// `expires 30d` auto-generates its own `Cache-Control: max-age=...`,
		// and `add_header` *adds* a header rather than replacing one already
		// set by another directive — combining the two produces two separate
		// Cache-Control lines in the response instead of one. Dropping
		// `expires` and writing the full value (public + max-age + immutable)
		// through `add_header` alone gives a single, complete header with no
		// ambiguity about which value wins. No separate `Expires` header
		// either, but that's fine: `Cache-Control: max-age` has taken
		// precedence over `Expires` since HTTP/1.1, and every client that
		// still only understands `Expires` predates this plugin's supported
		// range by decades.
		if ( $browser ) {
			$rules .= "# Browser Cache for Static Assets\n";
			$rules .= "location ~* \\.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {\n";
			$rules .= "    add_header Cache-Control \"public, max-age=2592000, immutable\";\n";
			$rules .= "}\n";
		}

		return $rules;
	}

	/**
	 * Outputs the Nginx rules as a downloadable file.
	 *
	 * @param array $settings Plugin settings.
	 * @return void
	 */
	public static function download_rules( $settings = array() ) {
		$rules = self::get_browser_cache_rules( $settings );

		header( 'Content-Type: text/plain' );
		header( 'Content-Disposition: attachment; filename="cacheloop-nginx.conf"' );
		header( 'Content-Length: ' . strlen( $rules ) );
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- streamed as a downloadable .conf file, not HTML.
		echo $rules;
		exit;
	}
}
