<?php
/**
 * Ability: wp-agent/update-product
 *
 * Partielles Update eines WooCommerce-Produkts ausschließlich über das
 * WC_Product-Objekt (wc_get_product() + offizielle Setter + save()), nie über
 * wp_update_post()/update_post_meta() direkt.
 *
 * KRITISCH (empirisch verifiziert, nicht die verbreitete HPOS-Behauptung):
 * HPOS (High-Performance Order Storage) betrifft ausschließlich Bestellungen,
 * nicht Produkte. Der reale Fallstrick bei Produkten ist ein anderer: Ein
 * roher update_post_meta( $id, '_regular_price', ... ) ändert zwar die
 * Postmeta-Zeile, aber weder WooCommerce' Objekt-Cache (wc_get_product() kann
 * innerhalb desselben Requests den alten, gecachten Wert zurückgeben) noch die
 * Lookup-Tabelle wp_wc_product_meta_lookup, die den Shop-Frontend für
 * Preis-Sortierung und -Filterung nutzt. Das Ergebnis: der Preis "stimmt" in
 * der DB, aber Sortierung/Filterung im Shop bleiben auf dem alten Stand, ohne
 * jede Fehlermeldung. Nur $product->save() aktualisiert Objekt-Cache und
 * Lookup-Tabelle konsistent mit.
 *
 * Zweiter Fallstrick: WC_Product::set_sku() wirft bei einer doppelt
 * vergebenen SKU SOFORT (nicht erst bei save()) eine WC_Data_Exception, die
 * unabgefangen zu einem PHP-Fatal-Error (HTTP 500) statt zu einer sauberen
 * Fehlermeldung führt. Eine eigene Vorab-Prüfung über
 * wc_get_product_id_by_sku() liefert die verständliche 400-Meldung; das
 * try/catch um den gesamten Schreib-Block fängt zusätzlich jede andere
 * WC-eigene Validierungs-Exception ab, die (noch) nicht vorab geprüft wird.
 *
 * @package WPAgentCompanion
 */

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

function wpagent_ability_update_product(): array {
	$properties = wpagent_wc_product_input_properties( true );
	unset( $properties['type'] );
	return array(
		'label'               => __( 'Produkt aktualisieren', 'wp-agent-companion' ),
		'description'         => __( 'Aktualisiert Produktdaten einschließlich Preise, Lager, Medien, Versand, Abmessungen, Taxonomien und Attribute ausschließlich über das WC_Product-Objekt und verifiziert das Ergebnis.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'       => 'object',
			'properties' => $properties,
			'required'   => array( 'product_id' ),
		),
		'output_schema'       => array(
			'type'       => 'object',
			'properties' => array(
				'product_id' => array( 'type' => 'integer' ),
				'type'       => array( 'type' => 'string' ),
				'written'    => array( 'type' => 'object' ),
				'verified'   => array( 'type' => 'boolean' ),
			),
		),
		'execute_callback'    => 'wpagent_exec_update_product',
		'permission_callback' => 'wpagent_perm_edit_posts',
		'meta'                => array(
			'show_in_rest' => true,
			'annotations'  => array(
				'readonly'    => false,
				'destructive' => false,
				'idempotent'  => true,
			),
		),
	);
}

/**
 * @param mixed $input
 * @return array|WP_Error
 */
function wpagent_exec_update_product( $input ) {
	$input      = is_array( $input ) ? $input : array();
	$product_id = (int) ( $input['product_id'] ?? 0 );
	$product    = wpagent_get_editable_product( $product_id );
	if ( is_wp_error( $product ) ) {
		return $product;
	}
	$changed = array();
	try {
		if ( array_key_exists( 'name', $input ) ) {
			$name = trim( (string) $input['name'] );
			if ( '' === $name ) {
				return new WP_Error( 'wpagent_bad_product_value', __( 'Der Produktname darf nicht leer sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			$product->set_name( $name );
			$changed[] = 'name';
		}
		if ( array_key_exists( 'status', $input ) ) {
			$status_cap = wpagent_check_post_status_cap( 'product', (string) $input['status'] );
			if ( is_wp_error( $status_cap ) ) return $status_cap;
			$product->set_status( (string) $input['status'] );
			$changed[] = 'status';
		}
		$applied = wpagent_wc_apply_product_fields( $product, $input );
		if ( is_wp_error( $applied ) ) return $applied;
		$changed = array_values( array_unique( array_merge( $changed, $applied ) ) );
		if ( array() === $changed ) return new WP_Error( 'wpagent_no_fields', __( 'Kein zu aktualisierendes Feld übergeben.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		$expected = wpagent_wc_capture_product_fields( $product, $changed );
		$product->save();
	} catch ( WC_Data_Exception $e ) {
		// set_sku()/save() können bei WooCommerce-eigenen Validierungsfehlern
		// synchron eine WC_Data_Exception werfen (empirisch verifiziert: ohne
		// dieses catch führt bereits ein simpler Doppel-SKU-Aufruf zu einem
		// unabgefangenen PHP-Fatal-Error/HTTP 500 statt einer sauberen 400).
		return new WP_Error( 'wpagent_wc_invalid', $e->getMessage(), array( 'status' => 400 ) );
	}

	$fresh = wc_get_product( $product_id );
	if ( ! $fresh instanceof WC_Product ) {
		return new WP_Error( 'wpagent_wc_readback_failed', __( 'Das aktualisierte Produkt konnte nicht erneut gelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	$verification = wpagent_wc_verify_product_fields( $fresh, $expected );

	return array(
		'product_id' => $product_id,
		'type'       => $fresh->get_type(),
		'written'    => $verification['written'],
		'verified'   => $verification['verified'],
	);
}
