<?php
/** Strict validation and transformations for OceanWP design settings. */

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

/** @return string|WP_Error */
function wpagent_oceanwp_validate_color( $value, bool $allow_empty = false ) {
	if ( ! is_string( $value ) || strlen( $value ) > 64 || wp_check_invalid_utf8( $value ) !== $value ) {
		return new WP_Error( 'wpagent_oceanwp_invalid_color', __( 'Ungültiger OceanWP-Farbwert.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$value = trim( $value );
	if ( '' === $value ) {
		return $allow_empty ? '' : new WP_Error( 'wpagent_oceanwp_invalid_color', __( 'Ungültiger OceanWP-Farbwert.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( preg_match( '/^#(?:[a-f0-9]{3}|[a-f0-9]{4}|[a-f0-9]{6}|[a-f0-9]{8})$/i', $value ) ) {
		return strtolower( $value );
	}
	if ( ! preg_match( '/^(rgb|rgba)\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(0(?:\.\d+)?|1(?:\.0+)?|\.\d+))?\s*\)$/i', $value, $matches ) ) {
		return new WP_Error( 'wpagent_oceanwp_invalid_color', __( 'Ungültiger OceanWP-Farbwert.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$red   = (int) $matches[2];
	$green = (int) $matches[3];
	$blue  = (int) $matches[4];
	if ( $red > 255 || $green > 255 || $blue > 255 || ( 'rgba' === strtolower( $matches[1] ) && ! isset( $matches[5] ) ) || ( 'rgb' === strtolower( $matches[1] ) && isset( $matches[5] ) && '' !== $matches[5] ) ) {
		return new WP_Error( 'wpagent_oceanwp_invalid_color', __( 'Ungültiger OceanWP-Farbwert.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( 'rgb' === strtolower( $matches[1] ) ) {
		return sprintf( 'rgb(%d, %d, %d)', $red, $green, $blue );
	}
	$alpha = (float) $matches[5];
	if ( $alpha < 0 || $alpha > 1 ) {
		return new WP_Error( 'wpagent_oceanwp_invalid_color', __( 'Ungültiger OceanWP-Farbwert.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$alpha_string = rtrim( rtrim( number_format( $alpha, 4, '.', '' ), '0' ), '.' );
	return sprintf( 'rgba(%d, %d, %d, %s)', $red, $green, $blue, $alpha_string );
}

/** @return string|WP_Error */
function wpagent_oceanwp_validate_font_family( $value ) {
	if ( ! is_string( $value ) || strlen( $value ) > 100 || wp_check_invalid_utf8( $value ) !== $value || sanitize_text_field( $value ) !== $value || ! preg_match( '/^[\p{L}\p{N}][\p{L}\p{N} .,\'"_+\-]{0,99}$/u', $value ) ) {
		return new WP_Error( 'wpagent_oceanwp_invalid_font', __( 'Ungültige OceanWP-Schriftfamilie.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return $value;
}

/** @param string[] $allowed @return array<string,string>|WP_Error */
function wpagent_oceanwp_read_responsive_enum( array $device_values, string $key, array $allowed ) {
	$result = array();
	foreach ( $device_values as $device => $values ) {
		if ( ! array_key_exists( $key, $values ) || '' === $values[ $key ] ) {
			continue;
		}
		$value = $values[ $key ];
		if ( ! is_string( $value ) || ! in_array( $value, $allowed, true ) ) {
			return wpagent_oceanwp_invalid_provider_state();
		}
		$result[ $device ] = $value;
	}
	return $result;
}

/** @param string[] $units @return array<string,int|float|string>|WP_Error */
function wpagent_oceanwp_read_responsive_number( array $device_values, string $key, string $unit_key, float $minimum, float $maximum, array $units, $default, string $default_unit ) {
	$result = array();
	foreach ( $device_values as $device => $values ) {
		$value = $values[ $key ] ?? ( 'desktop' === $device ? $default : null );
		if ( null === $value || '' === $value ) {
			continue;
		}
		$number = is_numeric( $value ) ? (float) $value : NAN;
		if ( ! is_finite( $number ) || $number < $minimum || $number > $maximum ) {
			return wpagent_oceanwp_invalid_provider_state();
		}
		$result[ $device ] = floor( $number ) === $number ? (int) $number : $number;
	}
	if ( ! $result ) {
		return array();
	}
	$unit = $device_values['desktop'][ $unit_key ] ?? $default_unit;
	if ( ! is_string( $unit ) || ! in_array( $unit, $units, true ) ) {
		return wpagent_oceanwp_invalid_provider_state();
	}
	$result['unit'] = $unit;
	return $result;
}

/** @return array<int,array<string,mixed>>|WP_Error */
function wpagent_oceanwp_read_typography( array $mods ) {
	$result = array();
	foreach ( array( 'body', 'headings' ) as $target ) {
		$device_values = array();
		foreach ( array( 'desktop' => '', 'tablet' => '_tablet', 'mobile' => '_mobile' ) as $device => $suffix ) {
			$key   = $target . $suffix . '_typography';
			$value = wpagent_oceanwp_mod( $mods, $key, array() );
			if ( ! is_array( $value ) || count( $value ) > 50 ) {
				return wpagent_oceanwp_invalid_provider_state();
			}
			$device_values[ $device ] = $value;
		}
		$row  = array( 'target' => $target );
		$base = $device_values['desktop'];
		if ( array_key_exists( 'font-family', $base ) && '' !== $base['font-family'] ) {
			$family = wpagent_oceanwp_validate_font_family( $base['font-family'] );
			if ( is_wp_error( $family ) ) {
				return wpagent_oceanwp_invalid_provider_state();
			}
			$row['font_family'] = $family;
		}
		if ( array_key_exists( 'color', $base ) && '' !== $base['color'] ) {
			$color = wpagent_oceanwp_validate_color( $base['color'], false );
			if ( is_wp_error( $color ) ) {
				return wpagent_oceanwp_invalid_provider_state();
			}
			$row['color'] = $color;
		}
		$weight = wpagent_oceanwp_read_responsive_enum( $device_values, 'font-weight', array( 'normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900' ) );
		$transform = wpagent_oceanwp_read_responsive_enum( $device_values, 'text-transform', array( 'none', 'capitalize', 'uppercase', 'lowercase' ) );
		$font_size = wpagent_oceanwp_read_responsive_number( $device_values, 'font-size', 'font-size-unit', 1, 400, array( 'px', 'em', 'rem', 'vw' ), 'body' === $target ? 14 : null, 'px' );
		$letter_spacing = wpagent_oceanwp_read_responsive_number( $device_values, 'letter-spacing', 'letter-spacing-unit', -10, 20, array( 'px', 'em', 'rem' ), null, 'px' );
		$line_height = wpagent_oceanwp_read_responsive_number( $device_values, 'line-height', 'line-height-unit', 0.5, 5, array( '', 'px', 'em', 'rem' ), 'body' === $target ? 1.8 : 1.4, '' );
		foreach ( array( 'font_weight' => $weight, 'font_size' => $font_size, 'letter_spacing' => $letter_spacing, 'line_height' => $line_height, 'text_transform' => $transform ) as $key => $value ) {
			if ( is_wp_error( $value ) ) {
				return $value;
			}
			if ( $value ) {
				$row[ $key ] = $value;
			}
		}
		if ( array_key_exists( 'text-decoration', $base ) && '' !== $base['text-decoration'] ) {
			$decoration = $base['text-decoration'];
			if ( ! is_string( $decoration ) || ! in_array( $decoration, array( 'none', 'underline', 'overline', 'line-through' ), true ) ) {
				return wpagent_oceanwp_invalid_provider_state();
			}
			$row['text_decoration'] = $decoration;
		}
		$result[] = $row;
	}
	return $result;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_oceanwp_validate_settings( string $section, $settings ) {
	$schemas = wpagent_oceanwp_section_schemas();
	if ( ! isset( $schemas[ $section ] ) ) {
		return new WP_Error( 'wpagent_oceanwp_unknown_section', __( 'Unbekannter OceanWP-Designbereich.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( ! is_array( $settings ) || ! $settings ) {
		return new WP_Error( 'wpagent_oceanwp_no_changes', __( 'Gib mindestens eine zu ändernde OceanWP-Einstellung an.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$valid = rest_validate_value_from_schema( $settings, $schemas[ $section ], 'settings' );
	if ( is_wp_error( $valid ) ) {
		return new WP_Error( 'wpagent_oceanwp_invalid_settings', __( 'Die OceanWP-Einstellungen sind ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$normalized = $settings;
	if ( in_array( $section, array( 'colors', 'buttons' ), true ) ) {
		foreach ( $normalized as $key => $value ) {
			$color = wpagent_oceanwp_validate_color( $value, false );
			if ( is_wp_error( $color ) ) {
				return $color;
			}
			$normalized[ $key ] = $color;
		}
	}
	if ( 'typography' === $section ) {
		if ( isset( $normalized['font_family'] ) ) {
			$family = wpagent_oceanwp_validate_font_family( $normalized['font_family'] );
			if ( is_wp_error( $family ) ) {
				return $family;
			}
			$normalized['font_family'] = $family;
		}
		if ( isset( $normalized['color'] ) ) {
			$color = wpagent_oceanwp_validate_color( $normalized['color'], false );
			if ( is_wp_error( $color ) ) {
				return $color;
			}
			$normalized['color'] = $color;
		}
	}
	return $normalized;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_oceanwp_apply_settings( string $section, array $mods, array $settings ) {
	$maps = array(
		'layout' => array(
			'site_layout' => 'ocean_main_layout_style', 'container_width' => 'ocean_main_container_width',
			'container_width_unit' => 'ocean_main_container_width_unit', 'page_layout' => 'ocean_page_single_layout',
			'blog_archive_layout' => 'ocean_blog_archives_layout', 'blog_single_layout' => 'ocean_blog_single_layout',
		),
		'colors' => array(
			'primary' => 'ocean_primary_color', 'primary_hover' => 'ocean_hover_primary_color',
			'links' => 'ocean_links_color', 'links_hover' => 'ocean_links_color_hover',
		),
		'buttons' => array(
			'background' => 'ocean_theme_button_bg', 'background_hover' => 'ocean_theme_button_hover_bg',
			'text' => 'ocean_theme_button_color', 'text_hover' => 'ocean_theme_button_hover_color',
		),
	);
	if ( isset( $maps[ $section ] ) ) {
		foreach ( $maps[ $section ] as $public => $provider ) {
			if ( array_key_exists( $public, $settings ) ) {
				$mods[ $provider ] = $settings[ $public ];
			}
		}
		if ( 'colors' === $section ) {
			foreach ( array( 'body_text' => 'body_typography', 'headings' => 'headings_typography' ) as $public => $provider ) {
				if ( array_key_exists( $public, $settings ) ) {
					$current          = isset( $mods[ $provider ] ) && is_array( $mods[ $provider ] ) ? $mods[ $provider ] : array();
					$current['color'] = $settings[ $public ];
					$mods[ $provider ] = $current;
				}
			}
		}
		return $mods;
	}
	if ( 'header' === $section ) {
		$mods['ocean_header_style'] = $settings['style'];
		return $mods;
	}
	if ( 'typography' === $section ) {
		return wpagent_oceanwp_apply_typography( $mods, $settings );
	}
	return new WP_Error( 'wpagent_oceanwp_unknown_section', __( 'Unbekannter OceanWP-Designbereich.', 'wp-agent-companion' ), array( 'status' => 400 ) );
}

/** @return array<string,mixed> */
function wpagent_oceanwp_apply_typography( array $mods, array $settings ): array {
	$target = $settings['target'];
	$keys   = array( 'desktop' => $target . '_typography', 'tablet' => $target . '_tablet_typography', 'mobile' => $target . '_mobile_typography' );
	foreach ( $keys as $device => $option_key ) {
		$current = isset( $mods[ $option_key ] ) && is_array( $mods[ $option_key ] ) ? $mods[ $option_key ] : array();
		$changed = false;
		if ( 'desktop' === $device ) {
			foreach ( array( 'font_family' => 'font-family', 'color' => 'color', 'text_decoration' => 'text-decoration' ) as $public => $provider ) {
				if ( array_key_exists( $public, $settings ) ) {
					$current[ $provider ] = $settings[ $public ];
					$changed = true;
				}
			}
		}
		foreach ( array( 'font_weight' => 'font-weight', 'text_transform' => 'text-transform' ) as $public => $provider ) {
			if ( isset( $settings[ $public ][ $device ] ) ) {
				$current[ $provider ] = $settings[ $public ][ $device ];
				$changed = true;
			}
		}
		foreach ( array( 'font_size' => 'font-size', 'letter_spacing' => 'letter-spacing', 'line_height' => 'line-height' ) as $public => $provider ) {
			if ( isset( $settings[ $public ][ $device ] ) ) {
				$current[ $provider ] = $settings[ $public ][ $device ];
				$changed = true;
			}
			if ( 'desktop' === $device && array_key_exists( 'unit', $settings[ $public ] ?? array() ) ) {
				$current[ $provider . '-unit' ] = $settings[ $public ]['unit'];
				$changed = true;
			}
		}
		if ( $changed || array_key_exists( $option_key, $mods ) ) {
			$mods[ $option_key ] = $current;
		}
	}
	return $mods;
}
