<?php
/**
 * Shared product-card visual settings helpers.
 *
 * @package Affilun\Presentation\Card
 */

declare(strict_types=1);

namespace Affilun\Presentation\Card;

use Affilun\Application\Settings\PluginSettings;
use Affilun\Application\Settings\ProviderCredentials;
use Affilun\Application\Settings\RenderingDefaults;

/**
 * Maps saved rendering and provider settings to canonical card CSS.
 */
final class ProductCardVisualSettings {

	/**
	 * Compose visual modifier classes from the saved rendering defaults.
	 *
	 * @param RenderingDefaults $rendering Current rendering defaults.
	 * @param list<string>      $additional Additional card classes.
	 */
	public static function rootClasses( RenderingDefaults $rendering, array $additional = array() ): string {
		$classes = $additional;

		if ( $rendering->defaultDesignPreset() !== 'default' ) {
			$classes[] = 'affilun-design-' . $rendering->defaultDesignPreset();
		}
		$classes[] = 'affilun-color-scheme-' . $rendering->defaultColorScheme();
		if ( $rendering->defaultButtonLayout() !== 'wrap' ) {
			$classes[] = 'affilun-buttons-' . $rendering->defaultButtonLayout();
		}
		if ( $rendering->defaultButtonShape() !== 'rounded' ) {
			$classes[] = 'affilun-button-shape-' . $rendering->defaultButtonShape();
		}
		if ( $rendering->defaultButtonTone() !== 'brand' ) {
			$classes[] = 'affilun-button-tone-' . $rendering->defaultButtonTone();
		}

		return implode( ' ', array_values( array_filter( $classes ) ) );
	}

	/**
	 * Build provider button color variables from persisted settings.
	 *
	 * @param PluginSettings    $settings     Current settings.
	 * @param list<string>|null $providerKeys Optional provider filter.
	 */
	public static function providerButtonColorStyle(
		PluginSettings $settings,
		?array $providerKeys = null
	): string {
		$style = '';
		foreach ( $settings->providerCredentials() as $providerKey => $credentials ) {
			if ( $providerKeys !== null && ! in_array( $providerKey, $providerKeys, true ) ) {
				continue;
			}
			$style .= self::providerButtonColorDeclaration(
				$providerKey,
				(string) $credentials->secret( 'button_color' ),
				(string) $credentials->secret( 'button_text_color' )
			);
		}
		return $style;
	}

	/**
	 * Build one provider's normalized button color variables.
	 *
	 * @param string $providerKey Provider key.
	 * @param string $color       Configured background color.
	 * @param string $textColor   Configured text-color preference.
	 */
	public static function providerButtonColorDeclaration(
		string $providerKey,
		string $color,
		string $textColor
	): string {
		$background = ProviderCredentials::normalizeButtonColor( $providerKey, $color );
		$foreground = ProviderCredentials::resolveButtonTextColor( $background, $textColor );
		$token      = self::providerCssToken( $providerKey );

		return '--affilun-color-' . $token . ':' . $background . ';'
			. '--affilun-color-' . $token . '-text:' . $foreground . ';';
	}

	/**
	 * Add CSS declarations to the first canonical card root.
	 *
	 * @param string $html  Rendered card HTML.
	 * @param string $style CSS declarations.
	 */
	public static function appendCardRootStyle( string $html, string $style ): string {
		if ( $style === '' ) {
			return $html;
		}

		$result = preg_replace_callback(
			'/<([a-z][a-z0-9-]*)\b([^>]*\bclass=("|\')[^"\']*\baffilun-card\b[^"\']*\3[^>]*)>/i',
			static function ( array $matches ) use ( $style ): string {
				$tag   = (string) $matches[1];
				$attrs = (string) $matches[2];
				if ( preg_match( '/\sstyle=("|\')([^"\']*)\1/i', $attrs, $styleMatch ) === 1 ) {
					$quote        = (string) $styleMatch[1];
					$currentStyle = rtrim( self::stripProviderButtonColorStyles( (string) $styleMatch[2] ) );
					$mergedStyle  = $currentStyle === '' ? $style : rtrim( $currentStyle, ';' ) . ';' . $style;
					$styleAttr    = ' style=' . $quote . self::escapeAttribute( $mergedStyle ) . $quote;
					$attrs        = preg_replace( '/\sstyle=("|\')[^"\']*\1/i', $styleAttr, $attrs, 1 );
					$attrs        = is_string( $attrs ) ? $attrs : (string) $matches[2];
					return '<' . $tag . $attrs . '>';
				}

				return '<' . $tag . $attrs . ' style="' . self::escapeAttribute( $style ) . '">';
			},
			$html,
			1
		);

		return is_string( $result ) ? $result : $html;
	}

	/**
	 * Return the CSS custom-property token for a provider.
	 *
	 * @param string $providerKey Provider key.
	 */
	public static function providerCssToken( string $providerKey ): string {
		return $providerKey === 'yahoo_shopping'
			? 'yahoo'
			: str_replace( '_', '-', $providerKey );
	}

	/**
	 * Remove previously injected provider color declarations.
	 *
	 * @param string $style Inline CSS declarations.
	 */
	private static function stripProviderButtonColorStyles( string $style ): string {
		$cleaned = preg_replace(
			'/--affilun-color-(?:amazon|rakuten|yahoo|mercari)(?:-text)?:[^;]*;?/',
			'',
			$style
		);
		return trim( is_string( $cleaned ) ? $cleaned : $style );
	}

	/**
	 * Escape an HTML attribute value.
	 *
	 * @param string $value Raw attribute value.
	 */
	private static function escapeAttribute( string $value ): string {
		return htmlspecialchars( $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' );
	}
}
