<?php
/** Shared discovery and merge helpers for native WordPress style variations. */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

define( 'WPAGENT_GLOBAL_STYLE_VARIATIONS_MAX_ITEMS', 200 );

/**
 * Keeps only keys matching a Site Editor property group, preserving their path.
 * This mirrors WordPress' filterObjectByProperties() helper.
 *
 * @param mixed    $value      Value to filter.
 * @param string[] $properties Property names to retain.
 * @return mixed
 */
function wpagent_gs_variation_filter_properties( $value, array $properties ) {
	if ( ! is_array( $value ) ) {
		return null;
	}
	$filtered = array();
	foreach ( $value as $key => $child ) {
		if ( is_string( $key ) && in_array( $key, $properties, true ) ) {
			$filtered[ $key ] = $child;
			continue;
		}
		if ( is_array( $child ) ) {
			$nested = wpagent_gs_variation_filter_properties( $child, $properties );
			if ( is_array( $nested ) && array() !== $nested ) {
				$filtered[ $key ] = $nested;
			}
		}
	}
	return $filtered;
}

/** @param string[] $properties */
function wpagent_gs_variation_matches_properties( array $variation, array $properties ): bool {
	$filtered = wpagent_gs_variation_filter_properties( $variation, $properties );
	$settings = isset( $variation['settings'] ) && is_array( $variation['settings'] ) ? $variation['settings'] : array();
	$styles   = isset( $variation['styles'] ) && is_array( $variation['styles'] ) ? $variation['styles'] : array();
	return ( $filtered['settings'] ?? array() ) == $settings && ( $filtered['styles'] ?? array() ) == $styles;
}

function wpagent_gs_variation_scope( array $variation ): string {
	if ( wpagent_gs_variation_matches_properties( $variation, array( 'color' ) ) ) {
		return 'color';
	}
	if ( wpagent_gs_variation_matches_properties( $variation, array( 'typography', 'spacing' ) ) ) {
		return 'typography';
	}
	return 'full';
}

/** @return array<string,mixed>|WP_Error */
function wpagent_gs_variation_record( array $variation, string $theme, int $index, ?string $scope_override = null ) {
	$encoded = wp_json_encode( $variation, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
	if ( false === $encoded ) {
		return new WP_Error( 'wpagent_gs_variation_encode', __( 'Eine Stilvariante konnte nicht sicher gelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	$bytes = strlen( $encoded );
	if ( $bytes > WPAGENT_GLOBAL_STYLES_MAX_BYTES ) {
		return new WP_Error( 'wpagent_gs_variation_too_large', __( 'Eine Stilvariante ist größer als 512 KiB und wird deshalb nicht über den Agenten verarbeitet.', 'wp-agent-companion' ), array( 'status' => 413 ) );
	}
	$settings = isset( $variation['settings'] ) && is_array( $variation['settings'] ) ? $variation['settings'] : array();
	$styles   = isset( $variation['styles'] ) && is_array( $variation['styles'] ) ? $variation['styles'] : array();
	$scope    = in_array( $scope_override, array( 'full', 'color', 'typography' ), true )
		? $scope_override
		: wpagent_gs_variation_scope( $variation );
	$title = isset( $variation['title'] ) && is_scalar( $variation['title'] )
		? trim( wp_strip_all_tags( (string) $variation['title'] ) )
		: '';
	if ( '' === $title ) {
		/* translators: %d: one-based style variation number. */
		$title = sprintf( __( 'Stilvariante %d', 'wp-agent-companion' ), $index + 1 );
	}
	$description = isset( $variation['description'] ) && is_scalar( $variation['description'] )
		? trim( wp_strip_all_tags( (string) $variation['description'] ) )
		: '';
	$id = hash( 'sha256', "wpagently-style-variation-v1\0" . $theme . "\0" . $scope . "\0" . $index . "\0" . $encoded );

	return array(
		'variation_id'     => $id,
		'title'            => $title,
		'description'      => $description,
		'scope'            => $scope,
		'bytes'            => $bytes,
		'settings_sections' => array_values( array_map( 'strval', array_keys( $settings ) ) ),
		'style_sections'   => array_values( array_map( 'strval', array_keys( $styles ) ) ),
		'has_custom_css'   => isset( $styles['css'] ) || wpagent_gs_variation_has_block_css( $styles ),
		'variation'        => $variation,
	);
}

function wpagent_gs_variation_has_block_css( array $styles ): bool {
	if ( ! isset( $styles['blocks'] ) || ! is_array( $styles['blocks'] ) ) {
		return false;
	}
	foreach ( $styles['blocks'] as $block ) {
		if ( is_array( $block ) && isset( $block['css'] ) ) {
			return true;
		}
	}
	return false;
}

/** @return array<int,array<string,mixed>>|WP_Error */
function wpagent_gs_variation_catalog() {
	if ( ! class_exists( 'WP_Theme_JSON_Resolver' ) || ! method_exists( 'WP_Theme_JSON_Resolver', 'get_style_variations' ) ) {
		return new WP_Error( 'wpagent_gs_variations_unsupported', __( 'Diese WordPress-Version unterstützt native Stilvarianten nicht.', 'wp-agent-companion' ), array( 'status' => 501 ) );
	}
	$theme      = (string) get_stylesheet();
	$variations = WP_Theme_JSON_Resolver::get_style_variations();
	if ( ! is_array( $variations ) ) {
		return new WP_Error( 'wpagent_gs_variations_invalid', __( 'WordPress hat keine gültige Liste der Stilvarianten geliefert.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	if ( count( $variations ) > WPAGENT_GLOBAL_STYLE_VARIATIONS_MAX_ITEMS ) {
		return new WP_Error( 'wpagent_gs_variations_too_many', __( 'Das aktive Theme stellt mehr als 200 Stilvarianten bereit. Die Liste wird aus Sicherheitsgründen nicht verarbeitet.', 'wp-agent-companion' ), array( 'status' => 413 ) );
	}

	$catalog = array();
	$default = wpagent_gs_variation_record(
		array(
			'title'    => __( 'Standard', 'wp-agent-companion' ),
			'settings' => array(),
			'styles'   => array(),
		),
		$theme,
		-1,
		'full'
	);
	if ( is_wp_error( $default ) ) {
		return $default;
	}
	$catalog[] = $default;
	foreach ( array_values( $variations ) as $index => $variation ) {
		if ( ! is_array( $variation ) ) {
			return new WP_Error( 'wpagent_gs_variations_invalid', __( 'WordPress hat eine ungültige Stilvariante geliefert.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		$record = wpagent_gs_variation_record( $variation, $theme, $index );
		if ( is_wp_error( $record ) ) {
			return $record;
		}
		$catalog[] = $record;
	}
	return $catalog;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_gs_find_variation( $variation_id ) {
	$id = is_string( $variation_id ) ? strtolower( $variation_id ) : '';
	if ( ! preg_match( '/^[a-f0-9]{64}$/', $id ) ) {
		return new WP_Error( 'wpagent_gs_variation_id', __( 'variation_id muss eine vollständige Stilvarianten-ID sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$catalog = wpagent_gs_variation_catalog();
	if ( is_wp_error( $catalog ) ) {
		return $catalog;
	}
	foreach ( $catalog as $record ) {
		if ( hash_equals( (string) $record['variation_id'], $id ) ) {
			return $record;
		}
	}
	return new WP_Error( 'wpagent_gs_variation_not_found', __( 'Die Stilvariante gehört nicht zum aktuell aktiven Theme oder ist nicht mehr vorhanden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
}

/** Recursively removes Site Editor property groups from the user config. */
function wpagent_gs_variation_remove_properties( array $value, array $properties ): array {
	foreach ( array_keys( $value ) as $key ) {
		if ( is_string( $key ) && in_array( $key, $properties, true ) ) {
			unset( $value[ $key ] );
			continue;
		}
		if ( is_array( $value[ $key ] ) ) {
			$value[ $key ] = wpagent_gs_variation_remove_properties( $value[ $key ], $properties );
		}
	}
	return $value;
}

/** Deep-merges plain objects while replacing preset arrays, matching WordPress. */
function wpagent_gs_variation_merge( array $base, array $overlay ): array {
	foreach ( $overlay as $key => $value ) {
		if (
			'backgroundImage' !== $key && is_array( $value ) && ! array_is_list( $value ) &&
			isset( $base[ $key ] ) && is_array( $base[ $key ] ) && ! array_is_list( $base[ $key ] )
		) {
			$base[ $key ] = wpagent_gs_variation_merge( $base[ $key ], $value );
		} else {
			$base[ $key ] = $value;
		}
	}
	return $base;
}

/** @return string|WP_Error */
function wpagent_gs_variation_css( $value, string $context ) {
	if ( null === $value || '' === $value ) {
		return '';
	}
	if ( ! is_string( $value ) ) {
		/* translators: %s: CSS storage location. */
		return new WP_Error( 'wpagent_gs_variation_css_invalid', sprintf( __( 'Der vorhandene CSS-Wert unter %s ist kein Text und kann nicht sicher erhalten werden.', 'wp-agent-companion' ), $context ), array( 'status' => 500 ) );
	}
	return $value;
}

function wpagent_gs_variation_combine_css( string $theme_css, string $user_css ): string {
	if ( '' === $theme_css ) {
		return $user_css;
	}
	if ( '' === $user_css ) {
		return $theme_css;
	}
	if ( $theme_css === $user_css || str_starts_with( $user_css, $theme_css . ' ' ) ) {
		return $user_css;
	}
	return $theme_css . ' ' . $user_css;
}
