<?php

namespace CustomBodyClass;

use WP_PowerSuite\Core\AbstractModule;

class Module extends AbstractModule {

	private const MODULE_ID      = 'custom-body-class';
	private const MODULE_VERSION = '1.0.3';

	public const MAX_CLASSES       = 40;
	public const MAX_INPUT_LENGTH  = 1024;

	/** @var array{classes: string}|null */
	private ?array $settings_cache = null;

	/** @var list<string>|null */
	private ?array $parsed_classes_cache = null;

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

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

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

	public function getDescription(): string {
		return __( 'Adds custom CSS classes to the front-end body for easy styling and layout flags—no template edits.', 'wp-powersuite' );
	}

	public function getContext(): string|array {
		return 'frontend';
	}

	protected function registerHooks(): void {
		if ( $this->getParsedClasses() === [] ) {
			return;
		}

		add_filter( 'body_class', [ $this, 'addBodyClasses' ] );
	}

	public function addBodyClasses( array $classes ): array {
		$extra = $this->getParsedClasses();

		return $extra === [] ? $classes : array_merge( $classes, $extra );
	}

	/**
	 * @return list<string>
	 */
	public static function parseClasses( string $raw ): array {
		$raw = trim( str_replace( ',', ' ', $raw ) );
		if ( $raw === '' ) {
			return [];
		}

		if ( function_exists( 'mb_substr' ) ) {
			$raw = mb_substr( $raw, 0, self::MAX_INPUT_LENGTH );
		} else {
			$raw = substr( $raw, 0, self::MAX_INPUT_LENGTH );
		}

		$parts = preg_split( '/\s+/', $raw, -1, PREG_SPLIT_NO_EMPTY );
		$out   = [];

		foreach ( is_array( $parts ) ? $parts : [] as $part ) {
			$class = sanitize_html_class( trim( (string) $part ) );
			if ( $class !== '' && ! in_array( $class, $out, true ) ) {
				$out[] = $class;
			}
			if ( count( $out ) >= self::MAX_CLASSES ) {
				break;
			}
		}

		return $out;
	}

	public static function normalizeClassesString( mixed $raw ): string {
		if ( ! is_string( $raw ) ) {
			return '';
		}

		$parsed = self::parseClasses( $raw );

		return $parsed === [] ? '' : implode( ' ', $parsed );
	}

	/**
	 * @return list<string>
	 */
	private function getParsedClasses(): array {
		if ( $this->parsed_classes_cache !== null ) {
			return $this->parsed_classes_cache;
		}

		$raw = trim( (string) ( $this->getSettings()['classes'] ?? '' ) );
		$this->parsed_classes_cache = $raw === '' ? [] : self::parseClasses( $raw );

		return $this->parsed_classes_cache;
	}

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

		$raw = $this->moduleSettings()->all( [] );
		$this->settings_cache = [
			'classes' => self::normalizeClassesString( is_array( $raw ) ? ( $raw['classes'] ?? '' ) : '' ),
		];

		return $this->settings_cache;
	}
}
