<?php
/**
 * Ability: wp-agent/create-menu
 *
 * Legt ein neues WordPress-Navigationsmenü an. Ein nav_menu ist technisch eine
 * Taxonomie (Terms in der Taxonomie 'nav_menu'), deshalb landet das Ergebnis von
 * wp_create_nav_menu() als term_id in menu_id. WordPress selbst verhindert über
 * wp_update_nav_menu_object() bereits doppelte Menünamen (Fehlercode
 * 'menu_exists'); dieser Fall wird hier als 400 gemeldet, nicht als 500.
 *
 * @package WPAgentCompanion
 */

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

/**
 * Permission callback: der Aufrufer muss Theme-Optionen bearbeiten dürfen.
 *
 * Gemeinsame Capability für die gesamte Phase-E-Menü-Ability-Gruppe (create-menu,
 * add-menu-item, list-menus, assign-menu-location, delete-menu). Sie lebt bewusst
 * HIER und nicht in includes/helpers.php, weil helpers.php eine geteilte Datei
 * ist, die in dieser Phase nicht angefasst werden darf (das übernimmt die
 * Integrationsphase). Die Funktion wird nur einmal definiert; die anderen vier
 * Menü-Ability-Dateien referenzieren sie per String, ohne sie erneut zu
 * deklarieren. Voraussetzung: create-menu.php muss zusammen mit den anderen vier
 * Dateien geladen werden (oder die Funktion wird bei der Integration nach
 * helpers.php verschoben).
 *
 * Wichtig für den Bot-Betrieb: edit_theme_options ist in WordPress' Kern-Rollen
 * ausschließlich der Administrator-Rolle zugewiesen, der Editor-Rolle NICHT
 * (siehe wp-admin/includes/schema.php, populate_roles_300()). Der sonst überall
 * geltende Grundsatz "Bot-User ist Editor, nie Admin" gilt für die Menü-Gruppe
 * also nicht: Menüverwaltung ist in WordPress selbst Admin-Territorium (genau wie
 * write-theme-file, das ebenfalls eine Theme-Capability voraussetzt). Ein
 * Editor-Bot bekommt hier von JEDER Ability dieser Gruppe ein 403.
 *
 * @param mixed $input Unused ability input.
 * @return bool
 */
function wpagent_perm_edit_theme_options( $input = null ): bool {
	return current_user_can( 'edit_theme_options' );
}

function wpagent_ability_create_menu(): array {
	return array(
		'label'               => __( 'Menü erstellen', 'wp-agent-companion' ),
		'description'         => __( 'Legt ein neues Navigationsmenü mit dem angegebenen Namen an und verifiziert per Re-Read. Ein doppelter Menüname wird als Eingabefehler (400) gemeldet.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'       => 'object',
			'properties' => array(
				'name' => array(
					'type'        => 'string',
					'description' => __( 'Name des neuen Menüs. Muss innerhalb der Site eindeutig sein.', 'wp-agent-companion' ),
				),
			),
			'required'   => array( 'name' ),
		),
		'output_schema'       => array(
			'type'       => 'object',
			'properties' => array(
				'menu_id'  => array( 'type' => 'integer' ),
				'name'     => array( 'type' => 'string' ),
				'verified' => array( 'type' => 'boolean' ),
			),
		),
		'execute_callback'    => 'wpagent_exec_create_menu',
		'permission_callback' => 'wpagent_perm_edit_theme_options',
		'meta'                => array(
			'show_in_rest' => true,
			'annotations'  => array(
				'readonly'    => false,
				'destructive' => false,
				// wp_create_nav_menu() weist einen doppelten Namen serverseitig
				// mit dem Fehlercode 'menu_exists' ab: ein Retry mit identischem
				// Input legt also NIE ein zweites Menü an, sondern schlägt beim
				// zweiten Versuch kontrolliert fehl. Kein zusätzlicher
				// Umwelteffekt bei Wiederholung, deshalb idempotent.
				'idempotent'  => true,
			),
		),
	);
}

/**
 * @param mixed $input
 * @return array|WP_Error
 */
function wpagent_exec_create_menu( $input ) {
	$input = is_array( $input ) ? $input : array();
	$name  = trim( (string) ( $input['name'] ?? '' ) );

	if ( '' === $name ) {
		return new WP_Error( 'wpagent_missing_name', __( 'name fehlt.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}

	$result = wp_create_nav_menu( $name );
	if ( is_wp_error( $result ) ) {
		// wp_create_nav_menu() liefert bei Namenskonflikten den Fehlercode
		// 'menu_exists' OHNE eigene 'status'-Angabe; ohne dieses Re-Wrapping
		// würde die Abilities-API mangels 'status' auf 500 zurückfallen, obwohl
		// es sich um einen klaren Eingabefehler handelt.
		return new WP_Error( 'wpagent_menu_create_failed', $result->get_error_message(), array( 'status' => 400 ) );
	}

	$menu_id = (int) $result;
	$menu    = wp_get_nav_menu_object( $menu_id );
	$verified = ( $menu instanceof WP_Term && $name === $menu->name );

	return array(
		'menu_id'  => $menu_id,
		'name'     => $menu instanceof WP_Term ? $menu->name : $name,
		'verified' => $verified,
	);
}
