<?php

namespace CustomAdminCss;

use WP_PowerSuite\Core\AbstractModule;
use WP_PowerSuite\Core\Contracts\DataLocationsInterface;

class Module extends AbstractModule implements DataLocationsInterface {

	private const MODULE_ID = 'custom-admin-css';
	private const MODULE_VERSION = '1.2.0';

	private ?array $settings_cache = null;

	public function getId(): string {
		return self::MODULE_ID;
	}

	public function getName(): string {
		return __( 'Custom Admin CSS', 'wp-powersuite' );
	}

	public function getVersion(): string {
		return self::MODULE_VERSION;
	}

	public function getDescription(): string {
		return __( 'Style the WordPress admin with custom CSS—quick visual tweaks without touching theme files.', 'wp-powersuite' );
	}

	public function getContext(): string|array {
		return [ 'admin' ];
	}

	protected function registerHooks(): void {
		if ( ! is_admin() ) {
			return;
		}

		add_action( 'admin_print_footer_scripts', [ $this, 'injectCss' ] );
	}

	public function injectCss(): void {
		$css = $this->getSettings()['custom_css'] ?? '';
		$css = is_string( $css ) ? trim( $css ) : '';

		if ( $css === '' ) {
			return;
		}

		$css = $this->sanitizeCssForOutput( $css );
		if ( $css === '' ) {
			return;
		}

		echo '<style id="wpps-custom-admin-css" type="text/css">', "\n";
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSS already passed through sanitizeCssForOutput().
		echo $css;
		echo "\n", '</style>', "\n";
	}

	/**
	 * Strip XSS vectors from stored CSS before output.
	 */
	public function sanitizeCssForOutput( string $css ): string {
		$css = wp_strip_all_tags( $css );
		$css = preg_replace( '#</style>|</script>|<script[^>]*>#i', '', $css );
		$css = preg_replace( '/javascript\s*:/i', '', $css );
		$css = preg_replace( '/expression\s*\(/i', '', $css );
		$css = preg_replace( '/behavior\s*:/i', '', $css );
		$css = preg_replace( '/url\s*\(\s*["\']?\s*data\s*:/i', 'url(invalid:', $css );

		return trim( $css );
	}

	/**
	 * {@inheritdoc}
	 */
	public function getDataLocations(): array {
		return [
			'option_store_keys' => [ self::MODULE_ID ],
		];
	}

	private function getSettings(): array {
		if ( $this->settings_cache !== null ) {
			return $this->settings_cache;
		}

		$settings = $this->moduleSettings()->all( [] );
		$settings = is_array( $settings ) ? $settings : [];
		$defaults = $this->getDefaultSettings();
		$this->settings_cache = array_merge( $defaults, $settings );

		return $this->settings_cache;
	}

	public function getDefaultSettings(): array {
		return [ 'custom_css' => '' ];
	}
}
