<?php
/** Wiederverwendbare, site-spezifische Agent-Skills. */

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

function wpagent_skill_schema(): array {
	return array( 'type' => 'object', 'properties' => array(
		'id' => array( 'type' => 'string', 'maxLength' => 64 ), 'title' => array( 'type' => 'string', 'maxLength' => 150 ), 'description' => array( 'type' => 'string', 'maxLength' => 1000 ),
		'instructions' => array( 'type' => 'string', 'maxLength' => 20000 ), 'enable_agentic' => array( 'type' => 'boolean' ),
		'enable_prompt' => array( 'type' => 'boolean' ), 'updated_at' => array( 'type' => 'string', 'maxLength' => 100 ),
	), 'additionalProperties' => false );
}

function wpagent_skill_summary_schema(): array {
	return array( 'type' => 'object', 'properties' => array(
		'id' => array( 'type' => 'string', 'maxLength' => 64 ), 'title' => array( 'type' => 'string', 'maxLength' => 150 ), 'description' => array( 'type' => 'string', 'maxLength' => 1000 ),
		'enable_agentic' => array( 'type' => 'boolean' ), 'enable_prompt' => array( 'type' => 'boolean' ), 'updated_at' => array( 'type' => 'string', 'maxLength' => 100 ),
	), 'additionalProperties' => false );
}

function wpagent_ability_list_skills(): array {
	$definition = wpagent_skill_ability_definition( __( 'Gespeicherte Skills auflisten', 'wp-agent-companion' ), 'wpagent_exec_list_skills', 'wpagent_perm_edit_posts', true, array(), array( 'items' => array( 'type' => 'array', 'items' => wpagent_skill_summary_schema(), 'maxItems' => 100 ), 'total' => array( 'type' => 'integer', 'maximum' => 100 ), 'state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) ) );
	$definition['meta']['mcp'] = array(
		'uri'         => 'wpagently://site/skills',
		'annotations' => array( 'audience' => array( 'assistant' ) ),
	);
	$definition['input_schema']['default'] = array();
	return $definition;
}
function wpagent_ability_get_skill(): array {
	return wpagent_skill_ability_definition( __( 'Gespeicherten Skill lesen', 'wp-agent-companion' ), 'wpagent_exec_get_skill', 'wpagent_perm_edit_posts', true, array( 'id' => array( 'type' => 'string', 'maxLength' => 64 ) ), array( 'skill' => wpagent_skill_schema(), 'state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) ), array( 'id' ) );
}
function wpagent_ability_upsert_skill(): array {
	return wpagent_skill_ability_definition( __( 'Skill speichern', 'wp-agent-companion' ), 'wpagent_exec_upsert_skill', 'wpagent_perm_manage_options', false, array( 'id' => array( 'type' => 'string', 'maxLength' => 64 ), 'title' => array( 'type' => 'string', 'maxLength' => 150 ), 'description' => array( 'type' => 'string', 'maxLength' => 1000 ), 'instructions' => array( 'type' => 'string', 'maxLength' => 20000 ), 'enable_agentic' => array( 'type' => 'boolean' ), 'enable_prompt' => array( 'type' => 'boolean' ), 'expected_state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) ), array( 'skill' => wpagent_skill_schema(), 'verified' => array( 'type' => 'boolean' ), 'state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) ), array( 'id', 'title', 'instructions', 'expected_state_hash' ) );
}
function wpagent_ability_delete_skill(): array {
	return wpagent_skill_ability_definition( __( 'Skill löschen', 'wp-agent-companion' ), 'wpagent_exec_delete_skill', 'wpagent_perm_manage_options', false, array( 'id' => array( 'type' => 'string', 'maxLength' => 64 ), 'expected_state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) ), array( 'id' => array( 'type' => 'string', 'maxLength' => 64 ), 'deleted' => array( 'type' => 'boolean' ), 'state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) ), array( 'id', 'expected_state_hash' ), true );
}

/**
 * Liefert die Namen aller Site-Skills, die als native MCP-Prompts angeboten
 * werden. Die Ability bleibt getrennt vom gleichnamigen Skill-Tool, damit der
 * Adapter sie nicht versehentlich zusätzlich unter tools/list exponiert.
 *
 * @return string[]
 */
function wpagent_companion_site_skill_prompt_ability_names(): array {
	$names = array();
	foreach ( wpagent_normalized_skills() as $skill ) {
		if ( ! $skill['enable_prompt'] ) {
			continue;
		}
		$names[] = 'wp-agent/site-skill-' . $skill['id'];
	}
	return $names;
}

/** @return array<string,mixed> */
function wpagent_companion_site_skill_prompt_definition( string $id ): array {
	$skills = wpagent_normalized_skills();
	$skill  = $skills[ $id ] ?? array();
	$description = (string) ( $skill['description'] ?? '' );
	if ( '' === $description ) {
		$description = sprintf(
			/* translators: %s: site skill title. */
			__( 'Site-spezifische Arbeitsanweisung: %s', 'wp-agent-companion' ),
			(string) ( $skill['title'] ?? $id )
		);
	}

	return array(
		'label'               => (string) ( $skill['title'] ?? $id ),
		'description'         => $description,
		'category'            => 'wp-agent',
		'input_schema'        => array( 'type' => 'object', 'properties' => array(), 'default' => array() ),
		'output_schema'       => array(
			'type'       => 'object',
			'properties' => array(
				'text'        => array( 'type' => 'string' ),
				'description' => array( 'type' => 'string' ),
			),
			'required'   => array( 'text', 'description' ),
		),
		'execute_callback'    => static fn( $input = array() ) => wpagent_exec_site_skill_prompt( array( 'id' => $id ) ),
		'permission_callback' => 'wpagent_perm_edit_posts',
		'meta'                => array(
			'mcp'         => array( 'public' => true, 'type' => 'prompt' ),
			'annotations' => array( 'readonly' => true, 'destructive' => false, 'idempotent' => true ),
		),
	);
}

/** @return array{text:string,description:string}|WP_Error */
function wpagent_exec_site_skill_prompt( $input ) {
	$id = wpagent_state_id( is_array( $input ) ? ( $input['id'] ?? '' ) : '' );
	if ( is_wp_error( $id ) ) {
		return $id;
	}
	$skill = wpagent_normalized_skills()[ $id ] ?? null;
	if ( null === $skill ) {
		return new WP_Error( 'wpagent_skill_not_found', __( 'Skill nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	if ( ! $skill['enable_prompt'] ) {
		return new WP_Error( 'wpagent_skill_prompt_disabled', __( 'Dieser Skill ist für direkte Prompts deaktiviert.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	return array( 'text' => $skill['instructions'], 'description' => $skill['description'] );
}

function wpagent_companion_register_site_skill_prompts(): void {
	foreach ( wpagent_companion_site_skill_prompt_ability_names() as $name ) {
		$id = substr( $name, strlen( 'wp-agent/site-skill-' ) );
		wpagent_companion_register_hardened_ability( $name, wpagent_companion_site_skill_prompt_definition( $id ) );
	}
}

function wpagent_skill_ability_definition( string $label, string $callback, string $permission, bool $readonly, array $input, array $output, array $required = array(), bool $destructive = false ): array {
	$input_schema = array( 'type' => 'object', 'properties' => $input, 'additionalProperties' => false );
	if ( $required ) {
		$input_schema['required'] = $required;
	}
	return array(
		'label' => $label, 'description' => __( 'Verwaltet begrenzte, site-spezifische Arbeitsanweisungen für Agent-Läufe.', 'wp-agent-companion' ), 'category' => 'wp-agent',
		'input_schema' => $input_schema, 'output_schema' => array( 'type' => 'object', 'properties' => $output, 'additionalProperties' => false ),
		'execute_callback' => $callback, 'permission_callback' => $permission,
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => $readonly, 'destructive' => $destructive, 'idempotent' => $readonly ) ),
	);
}

/** @return array<string,mixed>|null */
function wpagent_normalize_stored_skill( $value ): ?array {
	if ( ! is_array( $value ) ) {
		return null;
	}
	$id = wpagent_state_id( $value['id'] ?? '' );
	if ( is_wp_error( $id ) ) {
		return null;
	}
	$normalized = array( 'id' => $id );
	foreach ( array( 'title' => 150, 'description' => 1000, 'instructions' => 20000 ) as $field => $limit ) {
		$normalized[ $field ] = wpagent_state_text( $value[ $field ] ?? '', $limit, $field );
		if ( is_wp_error( $normalized[ $field ] ) ) {
			return null;
		}
	}
	$normalized['enable_agentic'] = ! array_key_exists( 'enable_agentic', $value ) || true === $value['enable_agentic'];
	$normalized['enable_prompt']  = ! array_key_exists( 'enable_prompt', $value ) || true === $value['enable_prompt'];
	$normalized['updated_at'] = wpagent_state_text( $value['updated_at'] ?? '', 100, 'updated_at' );
	if ( is_wp_error( $normalized['updated_at'] ) ) {
		return null;
	}
	return '' !== $normalized['title'] && '' !== $normalized['instructions'] ? $normalized : null;
}

/** @return array<string,array<string,mixed>> */
function wpagent_normalized_skills( ?array $stored = null ): array {
	$normalized = array();
	$stored = null === $stored ? wpagent_state_array_option( WPAGENT_COMPANION_OPT_SKILLS ) : $stored;
	foreach ( $stored as $value ) {
		$skill = wpagent_normalize_stored_skill( $value );
		if ( null !== $skill ) {
			$normalized[ $skill['id'] ] = $skill;
		}
	}
	return $normalized;
}

function wpagent_exec_list_skills( $input = array() ): array {
	$skills = array_values( wpagent_normalized_skills() );
	usort( $skills, static fn( array $a, array $b ): int => strcasecmp( $a['title'], $b['title'] ) );
	$items = array_map(
		static function ( array $skill ): array {
			unset( $skill['instructions'] );
			return $skill;
		},
		$skills
	);
	$hash = wpagent_state_hash_for_options( array( WPAGENT_COMPANION_OPT_SKILLS ) );
	return is_wp_error( $hash ) ? $hash : array( 'items' => $items, 'total' => count( $items ), 'state_hash' => $hash );
}

/** @return array|WP_Error */
function wpagent_exec_get_skill( $input ) {
	$id = wpagent_state_id( is_array( $input ) ? ( $input['id'] ?? '' ) : '' );
	if ( is_wp_error( $id ) ) {
		return $id;
	}
	$skills = wpagent_normalized_skills();
	if ( ! isset( $skills[ $id ] ) ) {
		return new WP_Error( 'wpagent_skill_not_found', __( 'Skill nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	$hash = wpagent_state_hash_for_options( array( WPAGENT_COMPANION_OPT_SKILLS ) );
	return is_wp_error( $hash ) ? $hash : array( 'skill' => $skills[ $id ], 'state_hash' => $hash );
}

/** @return array|WP_Error */
function wpagent_exec_upsert_skill( $input ) {
	$input = is_array( $input ) ? $input : array();
	$id    = wpagent_state_id( $input['id'] ?? '' );
	if ( is_wp_error( $id ) ) {
		return $id;
	}
	$values = array();
	foreach ( array( 'title' => 150, 'description' => 1000, 'instructions' => 20000 ) as $field => $limit ) {
		$values[ $field ] = wpagent_state_text( $input[ $field ] ?? '', $limit, $field );
		if ( is_wp_error( $values[ $field ] ) ) {
			return $values[ $field ];
		}
	}
	foreach ( array( 'enable_agentic', 'enable_prompt' ) as $field ) {
		if ( array_key_exists( $field, $input ) && ! is_bool( $input[ $field ] ) ) {
			return new WP_Error( 'wpagent_skill_bad_flag', __( 'Skill-Schalter müssen boolesche Werte sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$values[ $field ] = ! array_key_exists( $field, $input ) || true === $input[ $field ];
	}
	if ( '' === $values['title'] || '' === $values['instructions'] ) {
		return new WP_Error( 'wpagent_skill_missing_content', __( 'title und instructions dürfen nicht leer sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return wpagent_state_with_scoped_lock( 'skills', static function ( string $token ) use ( $input, $id, $values ) {
		$snapshot = wpagent_state_option_snapshot( WPAGENT_COMPANION_OPT_SKILLS );
		if ( ! $snapshot['readable'] ) {
			return new WP_Error( 'wpagent_skill_persist_failed', __( 'Skill konnte nicht verifiziert gespeichert werden.', 'wp-agent-companion' ), array( 'status' => 500, 'recovery_required' => true ) );
		}
		$required = wpagent_state_require_expected_hash( $input, wpagent_state_snapshot_hash( array( WPAGENT_COMPANION_OPT_SKILLS => $snapshot ) ) );
		if ( is_wp_error( $required ) ) { return $required; }
		$skills = wpagent_normalized_skills( is_array( $snapshot['value'] ) ? $snapshot['value'] : array() );
		if ( ! isset( $skills[ $id ] ) && count( $skills ) >= 100 ) {
			return new WP_Error( 'wpagent_skill_limit', __( 'Es können höchstens 100 Skills gespeichert werden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$skill = array_merge( array( 'id' => $id ), $values, array( 'updated_at' => wpagent_state_now() ) );
		$skills[ $id ] = $skill;
		$persisted = wpagent_state_commit_options( array( WPAGENT_COMPANION_OPT_SKILLS => $skills ), array( WPAGENT_COMPANION_OPT_SKILLS => $snapshot ), 'skills', $token, 'wpagent_skill_persist_failed', __( 'Skill konnte nicht verifiziert gespeichert werden.', 'wp-agent-companion' ) );
		if ( is_wp_error( $persisted ) ) { return $persisted; }
		$hash = wpagent_state_hash_for_options( array( WPAGENT_COMPANION_OPT_SKILLS ) );
		return is_wp_error( $hash ) ? $hash : array( 'skill' => $skill, 'verified' => true, 'state_hash' => $hash );
	}, 'wpagent_skill_persist_failed', __( 'Skill konnte nicht verifiziert gespeichert werden.', 'wp-agent-companion' ) );
}

/** @return array|WP_Error */
function wpagent_exec_delete_skill( $input ) {
	$input = is_array( $input ) ? $input : array();
	$id = wpagent_state_id( $input['id'] ?? '' );
	if ( is_wp_error( $id ) ) {
		return $id;
	}
	return wpagent_state_with_scoped_lock( 'skills', static function ( string $token ) use ( $input, $id ) {
		$snapshot = wpagent_state_option_snapshot( WPAGENT_COMPANION_OPT_SKILLS );
		if ( ! $snapshot['readable'] ) {
			return new WP_Error( 'wpagent_skill_persist_failed', __( 'Skill konnte nicht verifiziert gelöscht werden.', 'wp-agent-companion' ), array( 'status' => 500, 'recovery_required' => true ) );
		}
		$required = wpagent_state_require_expected_hash( $input, wpagent_state_snapshot_hash( array( WPAGENT_COMPANION_OPT_SKILLS => $snapshot ) ) );
		if ( is_wp_error( $required ) ) { return $required; }
		$skills  = wpagent_normalized_skills( is_array( $snapshot['value'] ) ? $snapshot['value'] : array() );
		$deleted = isset( $skills[ $id ] );
		unset( $skills[ $id ] );
		$persisted = wpagent_state_commit_options( array( WPAGENT_COMPANION_OPT_SKILLS => $skills ), array( WPAGENT_COMPANION_OPT_SKILLS => $snapshot ), 'skills', $token, 'wpagent_skill_persist_failed', __( 'Skill konnte nicht verifiziert gelöscht werden.', 'wp-agent-companion' ) );
		if ( is_wp_error( $persisted ) ) { return $persisted; }
		$hash = wpagent_state_hash_for_options( array( WPAGENT_COMPANION_OPT_SKILLS ) );
		return is_wp_error( $hash ) ? $hash : array( 'id' => $id, 'deleted' => $deleted, 'state_hash' => $hash );
	}, 'wpagent_skill_persist_failed', __( 'Skill konnte nicht verifiziert gelöscht werden.', 'wp-agent-companion' ) );
}
