<?php
/**
 * Ability: wp-agent/update-term
 *
 * Partielles Update eines bestehenden Terms: nur die übergebenen Felder
 * werden geändert. Analog zu wp-agent/update-post prüft die Ability jedes
 * geänderte Feld per Re-Read über get_term() und meldet pro Feld
 * verified:true/false.
 *
 * parent ist nur bei hierarchischen Taxonomien erlaubt (is_taxonomy_hierarchical()),
 * und ein Term darf nicht sein eigener Eltern-Term sein (analog zur
 * post_parent-Prüfung in wp-agent/update-post). Beide Fälle werden explizit
 * mit einer klaren Fehlermeldung abgelehnt statt WordPress' eigenes,
 * stilleres Verhalten zu übernehmen.
 *
 * @package WPAgentCompanion
 */

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

function wpagent_ability_update_term(): array {
	return array(
		'label'               => __( 'Term aktualisieren', 'wp-agent-companion' ),
		'description'         => __( 'Aktualisiert einzelne Felder eines bestehenden Terms (Name, Slug, Eltern-Term, Beschreibung). Nur übergebene Felder werden geändert; jedes geänderte Feld wird per Re-Read verifiziert.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'       => 'object',
			'properties' => array(
				'term_id'     => array( 'type' => 'integer' ),
				'taxonomy'    => array(
					'type'        => 'string',
					'description' => __( 'Muss eine registrierte Taxonomie sein (z. B. category, post_tag).', 'wp-agent-companion' ),
				),
				'name'        => array( 'type' => 'string' ),
				'slug'        => array( 'type' => 'string' ),
				'parent'      => array(
					'type'        => 'integer',
					'description' => __( 'Nur bei hierarchischen Taxonomien erlaubt (z. B. category).', 'wp-agent-companion' ),
				),
				'description' => array( 'type' => 'string' ),
			),
			'required'   => array( 'term_id', 'taxonomy' ),
		),
		'output_schema'       => array(
			'type'       => 'object',
			'properties' => array(
				'term_id'  => array( 'type' => 'integer' ),
				'taxonomy' => array( 'type' => 'string' ),
				'written'  => array( 'type' => 'object' ),
				'verified' => array( 'type' => 'boolean' ),
			),
		),
		'execute_callback'    => 'wpagent_exec_update_term',
		'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_term( $input ) {
	$input    = is_array( $input ) ? $input : array();
	$term_id  = (int) ( $input['term_id'] ?? 0 );
	$taxonomy = (string) ( $input['taxonomy'] ?? '' );

	if ( '' === $taxonomy || ! taxonomy_exists( $taxonomy ) ) {
		return new WP_Error( 'wpagent_bad_taxonomy', sprintf( __( 'Unbekannte Taxonomie "%s".', 'wp-agent-companion' ), $taxonomy ), array( 'status' => 400 ) );
	}
	if ( 'product_shipping_class' === $taxonomy ) {
		return new WP_Error(
			'wpagent_wc_shipping_class_requires_specialized_update',
			__( 'WooCommerce-Versandklassen müssen über die spezielle Versandklassen-Ability aktualisiert werden. Sie erzwingt Konfliktschutz und Read-back-Verifikation und verweist unklare Zustände ohne weitere Mutation zur manuellen Prüfung.', 'wp-agent-companion' ),
			array( 'status' => 409 )
		);
	}

	$term = get_term( $term_id, $taxonomy );
	if ( ! $term || is_wp_error( $term ) ) {
		return new WP_Error( 'wpagent_no_term', __( 'Term nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}

	// Feingranulare Capability der konkreten Taxonomie (get_taxonomy()->cap),
	// fail-closed analog zu wpagent_post_type_cap() in helpers.php.
	$tax_object = get_taxonomy( $taxonomy );
	$edit_cap   = ( $tax_object && isset( $tax_object->cap->edit_terms ) && '' !== (string) $tax_object->cap->edit_terms )
		? (string) $tax_object->cap->edit_terms
		: 'do_not_allow';
	if ( ! current_user_can( $edit_cap ) ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung, Terme in dieser Taxonomie zu bearbeiten.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}

	$hierarchical = is_taxonomy_hierarchical( $taxonomy );
	$args         = array();
	$expect       = array();

	if ( array_key_exists( 'name', $input ) ) {
		$name = trim( (string) $input['name'] );
		if ( '' === $name ) {
			return new WP_Error( 'wpagent_missing_name', __( 'name darf nicht leer sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$args['name']   = $name;
		$expect['name'] = $name;
	}

	if ( array_key_exists( 'slug', $input ) && '' !== trim( (string) $input['slug'] ) ) {
		$args['slug']   = sanitize_title( (string) $input['slug'] );
		$expect['slug'] = $args['slug'];
	}

	if ( array_key_exists( 'parent', $input ) ) {
		$parent = (int) $input['parent'];
		if ( ! $hierarchical && $parent > 0 ) {
			return new WP_Error(
				'wpagent_not_hierarchical',
				sprintf( __( 'Taxonomie "%s" ist nicht hierarchisch; parent ist nicht erlaubt.', 'wp-agent-companion' ), $taxonomy ),
				array( 'status' => 400 )
			);
		}
		if ( $parent === $term_id ) {
			return new WP_Error( 'wpagent_bad_parent', __( 'Ein Term kann nicht sein eigener Eltern-Term sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		if ( $parent > 0 && ! get_term( $parent, $taxonomy ) ) {
			return new WP_Error( 'wpagent_bad_parent', __( 'Eltern-Term nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$args['parent']   = $parent;
		$expect['parent'] = $parent;
	}

	if ( array_key_exists( 'description', $input ) ) {
		$args['description']   = (string) $input['description'];
		$expect['description'] = $args['description'];
	}

	if ( array() === $expect ) {
		return new WP_Error( 'wpagent_no_fields', __( 'Kein zu aktualisierendes Feld übergeben.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}

	$res = wp_update_term( $term_id, $taxonomy, $args );
	if ( is_wp_error( $res ) ) {
		return $res;
	}

	$fresh = get_term( $term_id, $taxonomy );
	if ( ! $fresh || is_wp_error( $fresh ) ) {
		return new WP_Error( 'wpagent_verify_failed', __( 'Term wurde aktualisiert, konnte aber nicht zurückgelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}

	$written  = array();
	$verified = true;
	foreach ( $expect as $field => $value ) {
		$actual = match ( $field ) {
			'name'        => $fresh->name,
			'slug'        => $fresh->slug,
			'parent'      => (int) $fresh->parent,
			'description' => $fresh->description,
			default       => null,
		};
		$ok                = ( (string) $actual === (string) $value );
		$written[ $field ] = $ok;
		if ( ! $ok ) {
			$verified = false;
		}
	}

	return array(
		'term_id'  => $term_id,
		'taxonomy' => $taxonomy,
		'written'  => $written,
		'verified' => $verified,
	);
}
