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

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

/** @return int|float */
function wpagent_kadence_normalize_number( $value ) {
	$number = (float) $value;
	return floor( $number ) === $number ? (int) $number : $number;
}

/** @return string|WP_Error */
function wpagent_kadence_validate_color( $value, bool $allow_palette, bool $allow_empty ) {
	if ( ! is_string( $value ) || strlen( $value ) > 64 || wp_check_invalid_utf8( $value ) !== $value ) {
		return new WP_Error( 'wpagent_kadence_invalid_color', __( 'Ungültiger Kadence-Farbwert.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$value = trim( $value );
	if ( '' === $value ) {
		return $allow_empty ? '' : new WP_Error( 'wpagent_kadence_invalid_color', __( 'Ungültiger Kadence-Farbwert.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( $allow_palette && ( 'transparent' === $value || preg_match( '/^palette(?:[1-9]|1[0-5])$/', $value ) ) ) {
		return $value;
	}
	if ( preg_match( '/^#(?:[a-f0-9]{3}|[a-f0-9]{4}|[a-f0-9]{6}|[a-f0-9]{8})$/i', $value ) ) {
		return $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_kadence_invalid_color', __( 'Ungültiger Kadence-Farbwert.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$red   = (int) $matches[2];
	$green = (int) $matches[3];
	$blue  = (int) $matches[4];
	$is_rgba = 'rgba' === strtolower( $matches[1] );
	if ( $red > 255 || $green > 255 || $blue > 255 || ( $is_rgba && ! isset( $matches[5] ) ) || ( ! $is_rgba && isset( $matches[5] ) && '' !== $matches[5] ) ) {
		return new WP_Error( 'wpagent_kadence_invalid_color', __( 'Ungültiger Kadence-Farbwert.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( ! $is_rgba ) {
		return sprintf( 'rgb(%d, %d, %d)', $red, $green, $blue );
	}
	$alpha = (float) $matches[5];
	if ( $alpha < 0 || $alpha > 1 ) {
		return new WP_Error( 'wpagent_kadence_invalid_color', __( 'Ungültiger Kadence-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_kadence_validate_font_family( $value ) {
	if ( ! is_string( $value ) || strlen( $value ) > 200 || wp_check_invalid_utf8( $value ) !== $value || sanitize_text_field( $value ) !== $value || ! preg_match( '/^-?[\p{L}\p{N}][\p{L}\p{N} .,\'"_+\-]{0,198}$/u', $value ) ) {
		return new WP_Error( 'wpagent_kadence_invalid_font', __( 'Ungültige Kadence-Schriftfamilie.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return $value;
}

/** @param string[] $units @return array<string,int|float|string>|WP_Error */
function wpagent_kadence_read_responsive_number( $values, $unit, float $minimum, float $maximum, array $units ) {
	if ( ! is_array( $values ) || ! is_string( $unit ) || ! in_array( $unit, $units, true ) ) {
		return wpagent_kadence_invalid_provider_state();
	}
	$result = array();
	foreach ( array( 'desktop', 'tablet', 'mobile' ) as $device ) {
		if ( ! array_key_exists( $device, $values ) || '' === $values[ $device ] ) {
			continue;
		}
		$value = $values[ $device ];
		if ( ! is_numeric( $value ) || ! is_finite( (float) $value ) || (float) $value < $minimum || (float) $value > $maximum ) {
			return wpagent_kadence_invalid_provider_state();
		}
		$result[ $device ] = wpagent_kadence_normalize_number( $value );
	}
	if ( $result ) {
		$result['unit'] = $unit;
	}
	return $result;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_kadence_validate_settings( string $section, $settings ) {
	$schemas = wpagent_kadence_section_schemas();
	if ( ! isset( $schemas[ $section ] ) ) {
		return new WP_Error( 'wpagent_kadence_unknown_section', __( 'Unbekannter Kadence-Designbereich.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( ! is_array( $settings ) || ! $settings ) {
		return new WP_Error( 'wpagent_kadence_no_changes', __( 'Gib mindestens eine zu ändernde Kadence-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_kadence_invalid_settings', __( 'Die Kadence-Einstellungen sind ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$normalized = $settings;
	if ( 'palette' === $section && isset( $normalized['colors'] ) ) {
		foreach ( $normalized['colors'] as $key => $value ) {
			$color = wpagent_kadence_validate_color( $value, false, false );
			if ( is_wp_error( $color ) ) {
				return $color;
			}
			$normalized['colors'][ $key ] = $color;
		}
	}
	if ( 'colors' === $section ) {
		foreach ( $normalized as $key => $value ) {
			$color = wpagent_kadence_validate_color( $value, true, true );
			if ( is_wp_error( $color ) ) {
				return $color;
			}
			$normalized[ $key ] = $color;
		}
	}
	if ( 'typography' === $section ) {
		if ( isset( $normalized['font_family'] ) ) {
			$family = wpagent_kadence_validate_font_family( $normalized['font_family'] );
			if ( is_wp_error( $family ) ) {
				return $family;
			}
			$normalized['font_family'] = $family;
		}
		if ( isset( $normalized['color'] ) ) {
			$color = wpagent_kadence_validate_color( $normalized['color'], true, true );
			if ( is_wp_error( $color ) ) {
				return $color;
			}
			$normalized['color'] = $color;
		}
	}
	if ( 'buttons' === $section ) {
		foreach ( array( 'text', 'text_hover', 'background', 'background_hover' ) as $key ) {
			if ( ! array_key_exists( $key, $normalized ) ) {
				continue;
			}
			$color = wpagent_kadence_validate_color( $normalized[ $key ], true, true );
			if ( is_wp_error( $color ) ) {
				return $color;
			}
			$normalized[ $key ] = $color;
		}
		if ( isset( $normalized['border_radius']['unit'], $normalized['border_radius']['units'] ) ) {
			return new WP_Error( 'wpagent_kadence_conflicting_units', __( 'Gib für den Kadence-Buttonradius entweder eine gemeinsame Einheit oder responsive Einheiten an.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
	}
	if ( 'header' === $section ) {
		$target    = $normalized['target'];
		$component = $normalized['component'];
		$placement = $normalized['placement'];
		if ( ! in_array( $component, wpagent_kadence_header_components( $target ), true ) ) {
			return new WP_Error( 'wpagent_kadence_invalid_header_component', __( 'Die Kadence-Header-Komponente ist für dieses Ziel nicht freigegeben.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$placements = array();
		foreach ( wpagent_kadence_header_zones( $target ) as $zones ) {
			$placements = array_merge( $placements, $zones );
		}
		if ( null !== $placement && ! in_array( $placement, $placements, true ) ) {
			return new WP_Error( 'wpagent_kadence_invalid_header_placement', __( 'Die Kadence-Header-Position ist für dieses Ziel nicht freigegeben.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		if ( null === $placement && array_key_exists( 'position', $normalized ) ) {
			return new WP_Error( 'wpagent_kadence_invalid_header_position', __( 'Beim Entfernen einer Kadence-Header-Komponente darf keine Position angegeben werden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
	}
	return $normalized;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_kadence_apply_settings( string $section, array $snapshot, array $changes ) {
	$settings = $snapshot['settings']['value'];
	$palette  = $snapshot['palette']['decoded'];
	if ( 'layout' === $section ) {
		foreach ( array( 'content_width' => 'content_width', 'narrow_width' => 'content_narrow_width' ) as $public => $provider ) {
			if ( ! array_key_exists( $public, $changes ) && ! array_key_exists( $public . '_unit', $changes ) ) {
				continue;
			}
			$current = wpagent_kadence_setting( $settings, $provider );
			if ( ! is_array( $current ) ) {
				return wpagent_kadence_invalid_provider_state();
			}
			if ( array_key_exists( $public, $changes ) ) {
				$current['size'] = $changes[ $public ];
			}
			if ( array_key_exists( $public . '_unit', $changes ) ) {
				$current['unit'] = $changes[ $public . '_unit' ];
			}
			$settings[ $provider ] = $current;
		}
	} elseif ( 'palette' === $section ) {
		$active = $changes['active'] ?? $palette['active'];
		$palette['active'] = $active;
		if ( isset( $changes['colors'] ) ) {
			if ( ! isset( $palette[ $active ] ) || ! is_array( $palette[ $active ] ) ) {
				return wpagent_kadence_invalid_provider_state();
			}
			foreach ( $changes['colors'] as $slug => $color ) {
				$index = (int) substr( $slug, 7 ) - 1;
				if ( ! isset( $palette[ $active ][ $index ] ) || $slug !== ( $palette[ $active ][ $index ]['slug'] ?? null ) ) {
					return wpagent_kadence_invalid_provider_state();
				}
				$palette[ $active ][ $index ]['color'] = $color;
			}
		}
	} elseif ( 'colors' === $section ) {
		foreach ( array( 'site_background' => 'site_background', 'content_background' => 'content_background' ) as $public => $provider ) {
			if ( ! array_key_exists( $public, $changes ) ) {
				continue;
			}
			$current = wpagent_kadence_setting( $settings, $provider );
			if ( ! is_array( $current ) ) {
				return wpagent_kadence_invalid_provider_state();
			}
			$current['desktop']['color'] = $changes[ $public ];
			$settings[ $provider ] = $current;
		}
		if ( array_key_exists( 'link', $changes ) || array_key_exists( 'link_hover', $changes ) ) {
			$current = wpagent_kadence_setting( $settings, 'link_color' );
			if ( ! is_array( $current ) ) {
				return wpagent_kadence_invalid_provider_state();
			}
			if ( array_key_exists( 'link', $changes ) ) {
				$current['highlight'] = $changes['link'];
			}
			if ( array_key_exists( 'link_hover', $changes ) ) {
				$current['highlight-alt'] = $changes['link_hover'];
			}
			$settings['link_color'] = $current;
		}
	} elseif ( 'typography' === $section ) {
		$provider = 'body' === $changes['target'] ? 'base_font' : $changes['target'] . '_font';
		$current  = wpagent_kadence_setting( $settings, $provider );
		if ( ! is_array( $current ) ) {
			return wpagent_kadence_invalid_provider_state();
		}
		foreach ( array( 'font_family' => 'family', 'google_font' => 'google', 'font_weight' => 'weight', 'color' => 'color' ) as $public => $key ) {
			if ( array_key_exists( $public, $changes ) ) {
				$current[ $key ] = $changes[ $public ];
			}
		}
		if ( array_key_exists( 'font_weight', $changes ) ) {
			$current['variant'] = in_array( $changes['font_weight'], array( 'normal', '400' ), true ) ? 'regular' : $changes['font_weight'];
		}
		foreach ( array( 'font_size' => array( 'size', 'sizeType' ), 'line_height' => array( 'lineHeight', 'lineType' ) ) as $public => $keys ) {
			if ( ! isset( $changes[ $public ] ) ) {
				continue;
			}
			if ( ! isset( $current[ $keys[0] ] ) || ! is_array( $current[ $keys[0] ] ) ) {
				$current[ $keys[0] ] = array();
			}
			foreach ( array( 'desktop', 'tablet', 'mobile' ) as $device ) {
				if ( array_key_exists( $device, $changes[ $public ] ) ) {
					$current[ $keys[0] ][ $device ] = $changes[ $public ][ $device ];
				}
			}
			if ( array_key_exists( 'unit', $changes[ $public ] ) ) {
				$current[ $keys[1] ] = 'line_height' === $public && '' === $changes[ $public ]['unit'] ? '-' : $changes[ $public ]['unit'];
			}
		}
		$settings[ $provider ] = $current;
	} elseif ( 'buttons' === $section ) {
		foreach ( array( 'text' => array( 'buttons_color', 'color' ), 'text_hover' => array( 'buttons_color', 'hover' ), 'background' => array( 'buttons_background', 'color' ), 'background_hover' => array( 'buttons_background', 'hover' ) ) as $public => $keys ) {
			if ( ! array_key_exists( $public, $changes ) ) {
				continue;
			}
			$current = isset( $settings[ $keys[0] ] ) && is_array( $settings[ $keys[0] ] ) ? $settings[ $keys[0] ] : wpagent_kadence_setting( $settings, $keys[0] );
			if ( ! is_array( $current ) ) {
				return wpagent_kadence_invalid_provider_state();
			}
			$current[ $keys[1] ] = $changes[ $public ];
			$settings[ $keys[0] ] = $current;
		}
		if ( isset( $changes['border_radius'] ) ) {
			$current = wpagent_kadence_setting( $settings, 'buttons_border_radius' );
			if ( ! is_array( $current ) ) {
				return wpagent_kadence_invalid_provider_state();
			}
			foreach ( array( 'desktop', 'tablet', 'mobile' ) as $device ) {
				if ( array_key_exists( $device, $changes['border_radius'] ) ) {
					$current['size'][ $device ] = $changes['border_radius'][ $device ];
				}
			}
			if ( array_key_exists( 'unit', $changes['border_radius'] ) ) {
				foreach ( array( 'desktop', 'tablet', 'mobile' ) as $device ) {
					$current['unit'][ $device ] = $changes['border_radius']['unit'];
				}
			}
			foreach ( $changes['border_radius']['units'] ?? array() as $device => $unit ) {
				$current['unit'][ $device ] = $unit;
			}
			$settings['buttons_border_radius'] = $current;
		}
	} elseif ( 'header' === $section ) {
		$target   = $changes['target'];
		$provider = wpagent_kadence_header_provider_value( $target, $settings );
		if ( is_wp_error( $provider ) ) {
			return $provider;
		}
		$zones = wpagent_kadence_header_zones( $target );
		foreach ( $zones as $row => $placements ) {
			foreach ( $placements as $placement ) {
				$provider[ $row ][ $placement ] = array_values(
					array_filter(
						$provider[ $row ][ $placement ],
						static fn( $item ) => $item !== $changes['component']
					)
				);
			}
		}
		if ( null !== $changes['placement'] ) {
			$target_row = '';
			foreach ( $zones as $row => $placements ) {
				if ( in_array( $changes['placement'], $placements, true ) ) {
					$target_row = $row;
					break;
				}
			}
			if ( '' === $target_row ) {
				return new WP_Error( 'wpagent_kadence_invalid_header_placement', __( 'Die Kadence-Header-Position ist für dieses Ziel nicht freigegeben.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			$items    = $provider[ $target_row ][ $changes['placement'] ];
			$position = array_key_exists( 'position', $changes ) ? $changes['position'] : count( $items );
			if ( $position > count( $items ) ) {
				return new WP_Error( 'wpagent_kadence_invalid_header_position', __( 'Die Kadence-Header-Position liegt außerhalb der Zielzone.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			array_splice( $items, $position, 0, array( $changes['component'] ) );
			$provider[ $target_row ][ $changes['placement'] ] = $items;
		}
		$validated_provider = wpagent_kadence_validate_header_provider( $target, $provider );
		if ( is_wp_error( $validated_provider ) ) {
			return $validated_provider;
		}
		$key              = 'desktop' === $target ? 'header_desktop_items' : 'header_mobile_items';
		$settings[ $key ] = $validated_provider;
	} else {
		return new WP_Error( 'wpagent_kadence_unknown_section', __( 'Unbekannter Kadence-Designbereich.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}

	$palette_json = wp_json_encode( $palette, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
	if ( false === $palette_json ) {
		return wpagent_kadence_invalid_provider_state();
	}
	return array(
		'settings' => 'palette' === $section
			? $snapshot['settings']
			: array( 'exists' => true, 'value' => $settings, 'autoload' => $snapshot['settings']['autoload'] ),
		'palette'  => 'palette' === $section
			? array( 'exists' => true, 'value' => $palette_json, 'decoded' => $palette, 'autoload' => $snapshot['palette']['autoload'] )
			: $snapshot['palette'],
	);
}
