<?php
/**
 * Ability: wp-agent/create-reusable-block
 *
 * Legt einen wiederverwendbaren Block (Post-Type wp_block) aus Markdown an.
 * Der post_type ist fest auf
 * wp_block verdrahtet, deshalb kommt hier bewusst NICHT wpagent_validate_post_type()
 * zum Einsatz: wp_block wird im WordPress-Kern mit 'public' => false registriert
 * (siehe wp-includes/post.php), und dieser generische Whitelist-Check würde jeden
 * Aufruf fälschlich mit "Post-Type nicht öffentlich" ablehnen.
 *
 * Zwei WordPress-Kern-Fallstricke, die diese Ability gezielt umschifft:
 *
 * 1. Erstell-Capability: Der WordPress-Kern mappt create_posts für wp_block NICHT
 *    auf edit_posts, sondern explizit auf die echte Capability publish_posts
 *    (Kern-Kommentar dort: "You need to be able to publish posts, in order to
 *    create blocks."). wpagent_post_type_create_cap( 'wp_block' ) löst das
 *    korrekt auf. Ein Mitwirkender (Contributor) mit edit_posts, aber ohne
 *    publish_posts, darf also KEINEN wiederverwendbaren Block anlegen, obwohl er
 *    eigene Beiträge bearbeiten kann.
 *
 * 2. post_status ist deshalb bewusst fest auf 'publish' verdrahtet und KEIN
 *    Eingabefeld: core/block referenziert einen wiederverwendbaren Block über
 *    dessen ID, und render_block_core_block() im Kern liefert für normale
 *    Besucher nur dann Inhalt, wenn der referenzierte Block den Status
 *    "publish" hat. Ein als draft angelegter Block würde auf jeder Seite, die
 *    ihn einbindet, still leer bleiben, ganz ohne Fehlermeldung. Aus demselben
 *    Grund wird hier AUCH NICHT wpagent_check_post_status_cap() aufgerufen: die
 *    darin genutzte publish-Capability für einen Post-Type wird über dessen
 *    NICHT überschriebenen Standard-Wert publish_posts -> "publish_blocks"
 *    aufgelöst, eine synthetische Capability, die im Kern an keine Rolle
 *    vergeben wird und JEDEN Aufruf ablehnen würde, selbst durch Administratoren.
 *    Die bereits oben durchgeführte create_posts-Prüfung deckt die
 *    Veröffentlichungs-Berechtigung hier vollständig ab.
 *
 * @package WPAgentCompanion
 */

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

function wpagent_ability_create_reusable_block(): array {
	return array(
		'label'               => __( 'Wiederverwendbaren Block erstellen', 'wp-agent-companion' ),
		'description'         => __( 'Legt einen wiederverwendbaren Block (wp_block) aus Markdown an. Der Server erzeugt daraus erlaubte Core-Blöcke. Wird immer veröffentlicht angelegt, damit core/block ihn sofort einbinden kann. Meldet block_count/freeform_count und verifiziert Titel und Inhalt per Re-Read.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'                 => 'object',
			'properties'           => array(
				'title'            => array(
					'type'        => 'string', 'minLength' => 1, 'maxLength' => 200,
					'description' => __( 'Name des wiederverwendbaren Blocks.', 'wp-agent-companion' ),
				),
				'content_markdown' => array(
					'type'        => 'string', 'minLength' => 1, 'maxLength' => 100000,
					'description' => __( 'Inhalt in Markdown, wird serverseitig über WPAgent_Markdown_To_Blocks zu erlaubten Gutenberg-Core-Blöcken konvertiert.', 'wp-agent-companion' ),
				),
			),
			'required'   => array( 'title', 'content_markdown' ),
			'additionalProperties' => false,
		),
		'output_schema'       => array(
			'type'                 => 'object',
			'properties'           => array(
				'block_id'       => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 2147483647 ),
				'status'         => array( 'type' => 'string', 'maxLength' => 20 ),
				'written'        => array(
					'type'                 => 'object',
					'properties'           => array( 'title' => array( 'type' => 'boolean' ), 'content' => array( 'type' => 'boolean' ) ),
					'required'             => array( 'title', 'content' ),
					'additionalProperties' => false,
				),
				'verified'       => array( 'type' => 'boolean' ),
				'block_count'    => array( 'type' => 'integer', 'minimum' => 0, 'maximum' => 100 ),
				'freeform_count' => array( 'type' => 'integer', 'minimum' => 0, 'maximum' => 100 ),
				'block_types'    => array(
					'type'  => 'array', 'maxItems' => 100,
					'items' => array( 'type' => 'string', 'maxLength' => 100 ),
				),
				'has_freeform'   => array( 'type' => 'boolean' ),
			),
			'required'             => array( 'block_id', 'status', 'written', 'verified', 'block_count', 'freeform_count', 'block_types', 'has_freeform' ),
			'additionalProperties' => false,
		),
		'execute_callback'    => 'wpagent_exec_create_reusable_block',
		'permission_callback' => 'wpagent_perm_edit_posts',
		'meta'                => array(
			'show_in_rest' => true,
			'annotations'  => array(
				'readonly'    => false,
				'destructive' => false,
				// Jeder Aufruf legt per wp_insert_post() einen neuen wp_block an.
				// Es gibt keinen post_id-/slug-Schlüssel, der einen Retry auf
				// denselben Datensatz abbildet.
				'idempotent'  => false,
			),
		),
	);
}

/**
 * @param mixed $input
 * @return array|WP_Error
 */
function wpagent_exec_create_reusable_block( $input ) {
	$input = is_array( $input ) ? $input : array();
	$title = wpagent_core_mutator_bounded_text( $input['title'] ?? null, 200 );

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

	// Grobe Schranke oben ist edit_posts; hier zusätzlich die für wp_block
	// tatsächlich zuständige Erstell-Capability prüfen (publish_posts, siehe
	// Datei-Kommentar oben), nicht einfach edit_posts erneut.
	if ( ! current_user_can( wpagent_post_type_create_cap( 'wp_block' ) ) ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung, wiederverwendbare Blöcke zu erstellen.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}

	if ( array_key_exists( 'content', $input ) ) {
		return new WP_Error( 'wpagent_raw_block_markup_not_allowed', __( 'Rohes Block-Markup und HTML sind nicht erlaubt. Verwende content_markdown.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}

	if ( ! array_key_exists( 'content_markdown', $input ) ) {
		return new WP_Error( 'wpagent_missing_content', __( 'content_markdown ist erforderlich.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$content_markdown = wpagent_core_mutator_bounded_text( $input['content_markdown'], 100000 );
	if ( is_wp_error( $content_markdown ) ) {
		return new WP_Error( 'wpagent_missing_content', __( 'content_markdown ist erforderlich und darf höchstens 100.000 Byte lang sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}

	$converter = new WPAgent_Markdown_To_Blocks();
	$content   = $converter->convert( $content_markdown );

	$report    = wpagent_block_report( $content );
	if ( $report['block_count'] > 100 || $report['freeform_count'] > 100 || count( $report['block_types'] ) > 100 ) {
		return new WP_Error( 'wpagent_reusable_block_output_limit', __( 'Der wiederverwendbare Block überschreitet die sichere Block- oder Typgrenze.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	foreach ( $report['block_types'] as $block_type ) {
		if ( is_wp_error( wpagent_core_schema_output_text( $block_type, 100, 'block_types' ) ) ) {
			return new WP_Error( 'wpagent_reusable_block_output_limit', __( 'Ein Blocktyp überschreitet die veröffentlichte Ausgabegrenze.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
	}
	$validated = wpagent_validate_generated_core_blocks( $content );
	if ( is_wp_error( $validated ) ) {
		return $validated;
	}

	$postarr = array(
		'post_title'   => $title,
		'post_content' => $content,
		'post_status'  => 'publish',
		'post_type'    => 'wp_block',
	);

	$res = wp_insert_post( $postarr, true );
	if ( is_wp_error( $res ) ) {
		return $res;
	}
	$block_id = (int) $res;
	if ( $block_id < 1 ) {
		return new WP_Error( 'wpagent_reusable_block_create_failed', __( 'Der wiederverwendbare Block wurde nicht angelegt.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	do_action( 'wpagent_reusable_block_after_insert', $block_id );

	$fresh = get_post( $block_id );

	$written = array(
		'title'   => ( $fresh instanceof WP_Post && (string) $fresh->post_title === $title ),
		'content' => ( $fresh instanceof WP_Post && (string) $fresh->post_content === $content ),
	);
	if ( ! $fresh instanceof WP_Post || ! current_user_can( 'edit_post', $block_id ) || in_array( false, $written, true ) ) {
		return wpagent_reusable_block_recovery_required( $block_id, __( 'Der wiederverwendbare Block wurde angelegt, konnte aber nicht vollständig verifiziert werden. Er bleibt zur manuellen Prüfung erhalten.', 'wp-agent-companion' ) );
	}
	$output_status = wpagent_core_schema_output_text( $fresh->post_status, 20, 'status' );
	if ( is_wp_error( $output_status ) ) {
		return wpagent_reusable_block_recovery_required( $block_id, __( 'Der wiederverwendbare Block überschreitet eine veröffentlichte Ausgabegrenze. Er bleibt zur manuellen Prüfung erhalten.', 'wp-agent-companion' ) );
	}

	return array(
		'block_id'       => $block_id,
		'status'         => $output_status,
		'written'        => $written,
		'verified'       => true,
		'block_count'    => $report['block_count'],
		'freeform_count' => $report['freeform_count'],
		'block_types'    => $report['block_types'],
		'has_freeform'   => $report['freeform_count'] > 0,
	);
}
