<?php
/** Bounded ACPT Lite 2.0.11 WooCommerce product-data configuration support. */

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

define( 'WPAGENT_ACPT_PRODUCT_DATA_MAX_GROUPS', 50 );
define( 'WPAGENT_ACPT_PRODUCT_DATA_MAX_FIELDS', 20 );
define( 'WPAGENT_ACPT_PRODUCT_DATA_MAX_OPTIONS', 20 );
define( 'WPAGENT_ACPT_PRODUCT_DATA_MAX_SNAPSHOT_BYTES', 131072 );
define( 'WPAGENT_ACPT_PRODUCT_DATA_MAX_CONTENT_BYTES', 65536 );
define( 'WPAGENT_ACPT_PRODUCT_DATA_LOCK_TTL', 300 );

/** @return array<string,string>|WP_Error */
function wpagent_acpt_product_data_provider() {
	global $wpdb;
	$engine = defined( 'DB_ENGINE' ) ? strtolower( (string) DB_ENGINE ) : ( false !== stripos( get_class( $wpdb ), 'sqlite' ) ? 'sqlite' : 'mysql' );
	if ( 'sqlite' === $engine || ! isset( $wpdb->dbh ) || ! $wpdb->dbh instanceof mysqli ) {
		return new WP_Error( 'wpagent_acpt_product_data_database', __( 'ACPT Lite Product Data wird nur auf MySQL oder MariaDB unterstützt.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$provider = array(
		'version'       => defined( 'ACPT_LITE_PLUGIN_VERSION' ) ? (string) ACPT_LITE_PLUGIN_VERSION : '',
		'woo_version'   => defined( 'WC_VERSION' ) ? (string) WC_VERSION : '',
		'repository'    => 'ACPT_Lite\\Core\\Repository\\WooCommerceProductDataRepository',
		'model'         => 'ACPT_Lite\\Core\\Models\\WooCommerce\\WooCommerceProductDataModel',
		'field_model'   => 'ACPT_Lite\\Core\\Models\\WooCommerce\\WooCommerceProductDataFieldModel',
		'option_model'  => 'ACPT_Lite\\Core\\Models\\WooCommerce\\WooCommerceProductDataFieldOptionModel',
		'generator'     => 'ACPT_Lite\\Core\\Generators\\Meta\\WooCommerceProductDataGenerator',
		'database'      => 'ACPT_Lite\\Includes\\ACPT_Lite_DB',
		'woo_runtime'   => 'ACPT_Lite\\Integrations\\WooCommerce\\ACPT_Lite_WooCommerce',
	);
	if ( '2.0.11' !== $provider['version'] || '10.9.4' !== $provider['woo_version'] || ! function_exists( 'is_plugin_active' ) || ! is_plugin_active( 'acpt-lite/acpt-lite.php' ) || ! is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
		return new WP_Error( 'wpagent_acpt_product_data_missing', __( 'Dieser sichere Product-Data-Pfad erfordert genau ACPT Lite 2.0.11 und WooCommerce 10.9.4.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	foreach ( array( 'repository', 'model', 'field_model', 'option_model', 'generator', 'database', 'woo_runtime' ) as $class ) {
		if ( ! class_exists( $provider[ $class ] ) ) return new WP_Error( 'wpagent_acpt_product_data_api', __( 'Die erforderliche native ACPT-Lite-Product-Data-API ist nicht verfügbar.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	foreach ( array( 'get', 'exists', 'save' ) as $method ) {
		if ( ! is_callable( array( $provider['repository'], $method ) ) ) return new WP_Error( 'wpagent_acpt_product_data_api', __( 'Die erforderliche native ACPT-Lite-Product-Data-API ist nicht verfügbar.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( ! is_callable( array( $provider['database'], 'flushCache' ) ) || ! is_callable( array( $provider['woo_runtime'], 'active' ) ) || ! $provider['woo_runtime']::active() ) {
		return new WP_Error( 'wpagent_acpt_product_data_api', __( 'Die native ACPT-Lite-WooCommerce-Product-Data-Integration ist nicht aktiv.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	return $provider;
}

function wpagent_acpt_product_data_can_manage(): bool {
	return current_user_can( 'manage_options' ) && current_user_can( 'manage_woocommerce' );
}

function wpagent_perm_acpt_product_data( $input = null ): bool {
	unset( $input );
	return wpagent_acpt_product_data_can_manage();
}

/** @return true|WP_Error */
function wpagent_acpt_product_data_require_capability() {
	if ( ! wpagent_acpt_product_data_can_manage() ) return new WP_Error( 'wpagent_acpt_product_data_forbidden', __( 'Du darfst ACPT-Lite-WooCommerce-Product-Data nicht verwalten.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	return true;
}

function wpagent_acpt_product_data_uuid( $value ): bool {
	return is_string( $value ) && 1 === preg_match( '/^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/Di', $value );
}

function wpagent_acpt_product_data_bytes( string $value ): int {
	return strlen( $value );
}

function wpagent_acpt_product_data_canonicalize( $value ) {
	if ( ! is_array( $value ) ) return $value;
	foreach ( $value as $key => $item ) $value[ $key ] = wpagent_acpt_product_data_canonicalize( $item );
	ksort( $value, SORT_STRING );
	return $value;
}

function wpagent_acpt_product_data_hash( array $raw ): string {
	$payload = array( 'blog_id' => get_current_blog_id(), 'state' => wpagent_acpt_product_data_canonicalize( $raw ) );
	return hash( 'sha256', (string) wp_json_encode( $payload ) );
}

/** @return array<string,string>|WP_Error */
function wpagent_acpt_product_data_tables( array $provider ) {
	try {
		$database = $provider['database'];
		$tables = array(
			'group'   => $database::prefixedTableName( $database::TABLE_WOOCOMMERCE_PRODUCT_DATA ),
			'field'   => $database::prefixedTableName( $database::TABLE_WOOCOMMERCE_PRODUCT_DATA_FIELD ),
			'option'  => $database::prefixedTableName( $database::TABLE_WOOCOMMERCE_PRODUCT_DATA_OPTION ),
		);
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_acpt_product_data_tables', __( 'Die nativen ACPT-Lite-Product-Data-Tabellen konnten nicht sicher aufgelöst werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	foreach ( $tables as $table ) if ( ! is_string( $table ) || ! preg_match( '/^[A-Za-z0-9_]+$/D', $table ) ) return new WP_Error( 'wpagent_acpt_product_data_tables', __( 'Die nativen ACPT-Lite-Product-Data-Tabellen sind nicht kanonisch.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	return $tables;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_acpt_product_data_raw( string $id, array $provider ) {
	global $wpdb;
	$tables = wpagent_acpt_product_data_tables( $provider );
	if ( is_wp_error( $tables ) ) return $tables;
	$wpdb->last_error = '';
	$group = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM `{$tables['group']}` WHERE id = %s LIMIT 1", $id ), ARRAY_A );
	if ( '' !== $wpdb->last_error ) return new WP_Error( 'wpagent_acpt_product_data_tables', __( 'Die ACPT-Lite-Product-Data-Gruppe konnte nicht sicher gelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	if ( ! is_array( $group ) ) return new WP_Error( 'wpagent_acpt_product_data_not_found', __( 'Die ACPT-Lite-Product-Data-Gruppe wurde nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	$wpdb->last_error = '';
	$fields = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `{$tables['field']}` WHERE product_data_id = %s ORDER BY sort ASC, id ASC LIMIT 21", $id ), ARRAY_A );
	$field_error = $wpdb->last_error;
	$wpdb->last_error = '';
	$options = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `{$tables['option']}` WHERE product_data_id = %s ORDER BY sort ASC, id ASC LIMIT 401", $id ), ARRAY_A );
	$option_error = $wpdb->last_error;
	if ( '' !== $field_error || '' !== $option_error || ! is_array( $fields ) || ! is_array( $options ) || count( $fields ) > WPAGENT_ACPT_PRODUCT_DATA_MAX_FIELDS || count( $options ) > WPAGENT_ACPT_PRODUCT_DATA_MAX_FIELDS * WPAGENT_ACPT_PRODUCT_DATA_MAX_OPTIONS ) {
		return new WP_Error( 'wpagent_acpt_product_data_limit', __( 'Der vollständige ACPT-Lite-Product-Data-Zustand überschreitet die sichere Grenze.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$raw = array( 'group' => $group, 'fields' => $fields, 'options' => $options );
	$encoded = wp_json_encode( $raw );
	if ( ! is_string( $encoded ) || wpagent_acpt_product_data_bytes( $encoded ) > WPAGENT_ACPT_PRODUCT_DATA_MAX_SNAPSHOT_BYTES ) return new WP_Error( 'wpagent_acpt_product_data_limit', __( 'Der vollständige ACPT-Lite-Product-Data-Zustand ist zu groß.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	return $raw;
}

/** @return string|WP_Error */
function wpagent_acpt_product_data_safe_text( $value, string $label, int $max, bool $allow_empty = true ) {
	if ( ! is_string( $value ) || wpagent_acpt_product_data_bytes( $value ) > $max || sanitize_text_field( $value ) !== $value || ( ! $allow_empty && '' === $value ) ) {
		return new WP_Error( 'wpagent_acpt_product_data_invalid', sprintf( __( '%s ist nicht sicher oder überschreitet die erlaubte Länge.', 'wp-agent-companion' ), $label ), array( 'status' => 400 ) );
	}
	return $value;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_acpt_product_data_public( array $raw ) {
	$group = $raw['group'] ?? null;
	$fields = $raw['fields'] ?? null;
	$options = $raw['options'] ?? null;
	if ( ! is_array( $group ) || ! is_array( $fields ) || ! is_array( $options ) || ! wpagent_acpt_product_data_uuid( $group['id'] ?? null ) || ! isset( $group['product_data_name'], $group['icon'], $group['visibility'], $group['content'], $group['show_in_ui'] ) ) return new WP_Error( 'wpagent_acpt_product_data_unsupported', __( 'Die ACPT-Lite-Product-Data-Gruppe liegt außerhalb des sicheren Vertrags.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	$name = wpagent_acpt_product_data_safe_text( $group['product_data_name'], 'Gruppenname', 100, false );
	$content = $group['content'];
	if ( is_wp_error( $name ) || ! is_string( $content ) || wpagent_acpt_product_data_bytes( $content ) > WPAGENT_ACPT_PRODUCT_DATA_MAX_CONTENT_BYTES || ! in_array( (string) $group['show_in_ui'], array( '0', '1' ), true ) ) return new WP_Error( 'wpagent_acpt_product_data_unsupported', __( 'Die ACPT-Lite-Product-Data-Gruppe liegt außerhalb des sicheren Vertrags.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	$icon = json_decode( (string) $group['icon'], true );
	$visibility = json_decode( (string) $group['visibility'], true );
	$visibility_values = array( 'show_if_simple', 'show_if_variable', 'show_if_grouped', 'show_if_external', 'hide_if_virtual', 'hide_if_external' );
	$visibility_strings = is_array( $visibility ) && count( $visibility ) === count( array_filter( $visibility, 'is_string' ) );
	if ( JSON_ERROR_NONE !== json_last_error() || ! is_array( $icon ) || ! is_array( $visibility ) || array_values( $visibility ) !== $visibility || count( $visibility ) > 6 || ! $visibility_strings || count( $visibility ) !== count( array_unique( $visibility ) ) || array_diff( $visibility, $visibility_values ) || wp_json_encode( $icon ) !== $group['icon'] || wp_json_encode( $visibility ) !== $group['visibility'] || count( $fields ) < 1 ) return new WP_Error( 'wpagent_acpt_product_data_unsupported', __( 'Die ACPT-Lite-Product-Data-Gruppe liegt außerhalb des sicheren Vertrags.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	$options_by_field = array();
	foreach ( $options as $option ) {
		if ( ! is_array( $option ) || ! wpagent_acpt_product_data_uuid( $option['id'] ?? null ) || ! wpagent_acpt_product_data_uuid( $option['product_data_field_id'] ?? null ) || ( $option['product_data_id'] ?? null ) !== $group['id'] ) return new WP_Error( 'wpagent_acpt_product_data_unsupported', __( 'Die ACPT-Lite-Product-Data-Gruppe liegt außerhalb des sicheren Vertrags.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		$label = wpagent_acpt_product_data_safe_text( $option['option_label'] ?? null, 'Optionsbeschriftung', 100, false );
		$value = wpagent_acpt_product_data_safe_text( $option['option_value'] ?? null, 'Optionswert', 100, false );
		if ( is_wp_error( $label ) || is_wp_error( $value ) || ! is_numeric( $option['sort'] ?? null ) ) return new WP_Error( 'wpagent_acpt_product_data_unsupported', __( 'Die ACPT-Lite-Product-Data-Gruppe liegt außerhalb des sicheren Vertrags.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		$options_by_field[ $option['product_data_field_id'] ][] = array( 'id' => $option['id'], 'label' => $label, 'value' => $value, 'sort' => (int) $option['sort'] );
	}
	$public_fields = array();
	$field_ids = array();
	foreach ( $fields as $field ) {
		if ( ! is_array( $field ) || ! wpagent_acpt_product_data_uuid( $field['id'] ?? null ) || ( $field['product_data_id'] ?? null ) !== $group['id'] || ! in_array( $field['field_type'] ?? null, array( 'Text', 'Number', 'Select' ), true ) || ! in_array( (string) ( $field['required'] ?? '' ), array( '0', '1' ), true ) || ! is_numeric( $field['sort'] ?? null ) ) return new WP_Error( 'wpagent_acpt_product_data_unsupported', __( 'Die ACPT-Lite-Product-Data-Gruppe liegt außerhalb des sicheren Vertrags.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		$field_name = wpagent_acpt_product_data_safe_text( $field['field_name'] ?? null, 'Feldname', 100, false );
		$default = wpagent_acpt_product_data_safe_text( $field['field_default_value'] ?? null, 'Standardwert', 200 );
		$description = wpagent_acpt_product_data_safe_text( $field['field_description'] ?? null, 'Beschreibung', 500 );
		$field_options = $options_by_field[ $field['id'] ] ?? array();
		$invalid_select = 'Select' === $field['field_type'] && ( count( $field_options ) < 1 || count( $field_options ) !== count( array_unique( array_column( $field_options, 'value' ) ) ) );
		$invalid_number_default = 'Number' === $field['field_type'] && ( '' !== $default && ( ! preg_match( '/^-?(?:\d+|\d*\.\d+)$/D', $default ) || ! is_finite( (float) $default ) ) );
		$invalid_select_default = 'Select' === $field['field_type'] && '' !== $default && ! in_array( $default, array_column( $field_options, 'value' ), true );
		if ( is_wp_error( $field_name ) || is_wp_error( $default ) || is_wp_error( $description ) || count( $field_options ) > WPAGENT_ACPT_PRODUCT_DATA_MAX_OPTIONS || $invalid_select || $invalid_number_default || $invalid_select_default ) return new WP_Error( 'wpagent_acpt_product_data_unsupported', __( 'Die ACPT-Lite-Product-Data-Gruppe liegt außerhalb des sicheren Vertrags.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		$field_ids[] = $field['id'];
		$public_fields[] = array( 'id' => $field['id'], 'name' => $field_name, 'type' => $field['field_type'], 'default_value' => $default, 'description' => $description, 'required' => '1' === (string) $field['required'], 'sort' => (int) $field['sort'], 'options' => $field_options );
	}
	foreach ( array_keys( $options_by_field ) as $field_id ) if ( ! in_array( $field_id, $field_ids, true ) ) return new WP_Error( 'wpagent_acpt_product_data_unsupported', __( 'Die ACPT-Lite-Product-Data-Gruppe liegt außerhalb des sicheren Vertrags.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	return array( 'id' => $group['id'], 'name' => $name, 'show_in_ui' => '1' === (string) $group['show_in_ui'], 'visibility' => $visibility, 'fields' => $public_fields );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_acpt_product_data_state( string $id, array $provider ) {
	$raw = wpagent_acpt_product_data_raw( $id, $provider );
	if ( is_wp_error( $raw ) ) return $raw;
	$public = wpagent_acpt_product_data_public( $raw );
	if ( is_wp_error( $public ) ) return $public;
	try {
		$models = $provider['repository']::get( array( 'id' => $id ) );
		$model = is_array( $models ) && 1 === count( $models ) ? $models[0] : null;
		$model_field_ids = array_map( static fn( $field ): string => $field->getId(), $model ? $model->getFields() : array() );
		$public_field_ids = array_column( $public['fields'], 'id' );
		sort( $model_field_ids, SORT_STRING );
		sort( $public_field_ids, SORT_STRING );
		if ( ! $model || ! is_a( $model, $provider['model'] ) || $model->getId() !== $id || $model->getName() !== $public['name'] || $model->isShowInUI() !== $public['show_in_ui'] || $model_field_ids !== $public_field_ids ) throw new UnexpectedValueException( 'Native ACPT product data mismatch.' );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_acpt_product_data_api', __( 'Der native ACPT-Lite-Product-Data-Readback ist nicht vollständig.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	return array( 'raw' => $raw, 'public' => $public, 'state_hash' => wpagent_acpt_product_data_hash( $raw ), 'model' => $model );
}

function wpagent_acpt_product_data_lock_name( string $id ): string {
	return 'wp_agent_acpt_product_data_lock_' . $id;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_acpt_product_data_recovery_error( string $message, ?array $state = null ) {
	$data = array( 'status' => 409, 'recovery_required' => true );
	if ( is_array( $state ) ) $data['current'] = array_merge( $state['public'], array( 'state_hash' => $state['state_hash'] ) );
	return new WP_Error( 'wpagent_acpt_product_data_recovery_required', $message, $data );
}
