<?php
/**
 * Ability: wp-agent/get-term
 *
 * Read-only. Liest einen einzelnen Term (Name, Slug, Beschreibung, Eltern-Term,
 * Anzahl zugeordneter Objekte) aus einer Taxonomie.
 *
 * Die Capability-Anforderung ist bewusst die schwächste des Standard-Sets
 * (manage_terms/edit_terms/delete_terms/assign_terms): assign_terms, weil
 * schon das Lesen eines Terms voraussetzt, dass der Aufrufer Terme dieser
 * Taxonomie überhaupt zuordnen darf; das ist die minimale sinnvolle Schranke
 * für einen reinen Lesezugriff.
 *
 * @package WPAgentCompanion
 */

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

function wpagent_ability_get_term(): array {
	return array(
		'label'               => __( 'Term lesen', 'wp-agent-companion' ),
		'description'         => __( 'Liest einen einzelnen Term mit kanonischem state_hash für konfliktgeschützte Folgeänderungen.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'       => 'object',
			'properties' => array(
				'term_id'  => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 2147483647 ),
				'taxonomy' => array(
					'type'        => 'string', 'minLength' => 1, 'maxLength' => 32, 'pattern' => '^[a-z0-9_-]{1,32}$',
					'description' => __( 'Muss eine registrierte Taxonomie sein (z. B. category, post_tag).', 'wp-agent-companion' ),
				),
			),
			'required'   => array( 'term_id', 'taxonomy' ),
			'maxProperties' => 2,
			'additionalProperties' => false,
		),
		'output_schema'       => array(
			'type'       => 'object',
			'properties' => array(
				'id'          => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 2147483647 ),
				'taxonomy'    => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 32, 'pattern' => '^[a-z0-9_-]{1,32}$' ),
				'name'        => array( 'type' => 'string', 'maxLength' => 200 ),
				'slug'        => array( 'type' => 'string', 'maxLength' => 200 ),
				'description' => array( 'type' => 'string', 'maxLength' => 10000 ),
				'parent'      => array( 'type' => 'integer', 'minimum' => 0, 'maximum' => 2147483647 ),
				'count'       => array( 'type' => 'integer', 'minimum' => 0, 'maximum' => 2147483647 ),
				'state_hash'  => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			),
			'required' => array( 'id', 'taxonomy', 'name', 'slug', 'description', 'parent', 'count', 'state_hash' ),
			'maxProperties' => 8,
			'additionalProperties' => false,
		),
		'execute_callback'    => 'wpagent_exec_get_term',
		'permission_callback' => 'wpagent_perm_edit_posts',
		'meta'                => array(
			'show_in_rest' => true,
			'annotations'  => array(
				'readonly'    => true,
				'destructive' => false,
				'idempotent'  => true,
			),
		),
	);
}

/** @return int|WP_Error */
function wpagent_term_read_output_integer( $value, int $minimum, int $maximum, string $field ) {
	if ( ! is_int( $value ) || $value < $minimum || $value > $maximum ) {
		return new WP_Error(
			'wpagent_core_schema_output_invalid',
			/* translators: %s: provider output field. */
			sprintf( __( 'Die Provider-Ausgabe für %s ist keine zulässige Ganzzahl innerhalb des veröffentlichten Sicherheitsvertrags.', 'wp-agent-companion' ), $field ),
			array( 'status' => 500, 'recovery_required' => false )
		);
	}
	return $value;
}

/**
 * @param mixed $input
 * @return array|WP_Error
 */
function wpagent_exec_get_term( $input ) {
	$input = is_array( $input ) ? $input : array();
	$term_id = wpagent_core_schema_input_integer( $input['term_id'] ?? null, 1, 2147483647, 'term_id' );
	$taxonomy = wpagent_core_mutator_bounded_text( $input['taxonomy'] ?? null, 32 );
	if ( is_wp_error( $term_id ) ) {
		return $term_id;
	}
	if ( is_wp_error( $taxonomy ) || 1 !== preg_match( '/^[a-z0-9_-]{1,32}$/D', $taxonomy ) ) {
		return new WP_Error( 'wpagent_bad_taxonomy', __( 'Taxonomie oder Term-ID ist ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}

	if ( '' === $taxonomy || ! taxonomy_exists( $taxonomy ) ) {
		return new WP_Error( 'wpagent_bad_taxonomy', sprintf( __( 'Unbekannte Taxonomie "%s".', 'wp-agent-companion' ), $taxonomy ), array( 'status' => 400 ) );
	}

	// Check the taxonomy-specific capability before resolving the term. Besides
	// being the authorization boundary for reads, this avoids disclosing whether
	// a term exists in a private taxonomy through a 404 or cache activity.
	$tax_object = get_taxonomy( $taxonomy );
	$read_cap   = ( $tax_object && isset( $tax_object->cap->assign_terms ) && '' !== (string) $tax_object->cap->assign_terms )
		? (string) $tax_object->cap->assign_terms
		: 'do_not_allow';
	if ( ! current_user_can( $read_cap ) ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung für diese Taxonomie.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}

	// The hash includes count. Clear the term cache first, otherwise a
	// concurrent assignment can be returned with a stale count and become a
	// false CAS baseline for update-term or delete-term.
	$term = wpagent_term_snapshot( $term_id, $taxonomy );
	if ( is_wp_error( $term ) ) {
		return $term;
	}

	$result = array(
		'id'          => wpagent_term_read_output_integer( $term->term_id, 1, 2147483647, 'id' ),
		'taxonomy'    => wpagent_core_schema_output_text( $term->taxonomy, 32, 'taxonomy', false ),
		'name'        => wpagent_core_schema_output_text( $term->name, 200, 'name' ),
		'slug'        => wpagent_core_schema_output_text( $term->slug, 200, 'slug' ),
		'description' => wpagent_core_schema_output_text( $term->description, 10000, 'description' ),
		'parent'      => wpagent_term_read_output_integer( $term->parent, 0, 2147483647, 'parent' ),
		'count'       => wpagent_term_read_output_integer( $term->count, 0, 2147483647, 'count' ),
		'state_hash'  => wpagent_term_state_hash( $term ),
	);
	foreach ( $result as $value ) {
		if ( is_wp_error( $value ) ) {
			return $value;
		}
	}
	return $result;
}
