<?php
/** Shared validation and transaction helpers for native block documents. */

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

function wpagent_native_block_namespace( string $name ): string {
	$separator = strpos( $name, '/' );
	return false === $separator ? '' : substr( $name, 0, $separator );
}

function wpagent_native_block_sensitive_key( string $key ): bool {
	return 1 === preg_match( '/(?:secret|password|passwd|token|api[_-]?key|private[_-]?key|credential|authorization|cookie|callback|(?:^|[_-])(?:file|path)(?:$|[_-])|^(?:file|path)[A-Z_-])/i', $key );
}

function wpagent_native_block_string_length( string $value ): int {
	return function_exists( 'mb_strlen' ) ? (int) mb_strlen( $value, 'UTF-8' ) : strlen( $value );
}

function wpagent_native_block_local_path_value( string $value ): bool {
	foreach ( array( 'ABSPATH', 'WP_CONTENT_DIR', 'WP_PLUGIN_DIR', 'WPMU_PLUGIN_DIR' ) as $constant ) {
		$root = defined( $constant ) ? (string) constant( $constant ) : '';
		if ( '' !== $root && str_contains( $value, $root ) ) {
			return true;
		}
	}
	return 1 === preg_match( '#(?:^|\s)(?:[A-Za-z]:[\\\\/]|\\\\\\\\|/(?:Users|home|private|var)/)|file://#', $value );
}

/** @return string|null */
function wpagent_native_block_public_string( string $value, int $maximum = 4096 ) {
	$value = substr( $value, 0, $maximum );
	return wpagent_native_block_local_path_value( $value ) ? null : $value;
}

/** @param mixed $value @return mixed */
function wpagent_native_block_public_schema_value( $value, int $depth = 0 ) {
	if ( $depth > 12 ) {
		return null;
	}
	if ( is_array( $value ) ) {
		$out = array();
		foreach ( $value as $key => $child ) {
			if ( is_string( $key ) && wpagent_native_block_sensitive_key( $key ) ) {
				continue;
			}
			$sanitized = wpagent_native_block_public_schema_value( $child, $depth + 1 );
			if ( null !== $sanitized || null === $child ) {
				$out[ $key ] = $sanitized;
			}
		}
		return $out;
	}
	if ( is_string( $value ) ) {
		return wpagent_native_block_public_string( $value );
	}
	return is_int( $value ) || is_float( $value ) || is_bool( $value ) || null === $value ? $value : null;
}

/** @return array<string,mixed> */
function wpagent_native_block_public_attributes( WP_Block_Type $type ): array {
	$attributes = array();
	foreach ( $type->get_attributes() as $name => $schema ) {
		if ( wpagent_native_block_sensitive_key( (string) $name ) || ! is_array( $schema ) ) {
			continue;
		}
		$attributes[ $name ] = wpagent_native_block_public_schema_value( $schema );
	}
	return $attributes;
}

/** @param mixed $values @return array<int,string> */
function wpagent_native_block_public_block_names( $values ): array {
	$names = array();
	foreach ( (array) $values as $name ) {
		if ( ! is_string( $name ) || strlen( $name ) > 200 || ! preg_match( '/^[a-z0-9-]+\/[a-z0-9-]+$/', $name ) ) {
			continue;
		}
		$names[] = $name;
	}
	return array_values( array_unique( $names ) );
}

/** @return array<string,mixed> */
function wpagent_native_block_type_summary( WP_Block_Type $type ): array {
	return array(
		'name'            => $type->name,
		'namespace'       => wpagent_native_block_namespace( $type->name ),
		'title'           => wpagent_native_block_public_string( wp_strip_all_tags( (string) $type->title ), 1024 ) ?? '',
		'category'        => sanitize_key( (string) $type->category ),
		'api_version'     => (int) $type->api_version,
		'dynamic'         => is_callable( $type->render_callback ),
		'attribute_count' => count( $type->get_attributes() ),
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_native_block_document_state( int $post_id ) {
	$post = get_post( $post_id );
	if ( ! $post instanceof WP_Post ) {
		return new WP_Error( 'wpagent_native_block_not_found', __( 'Beitrag nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	if ( ! current_user_can( 'edit_post', $post_id ) ) {
		return new WP_Error( 'wpagent_native_block_forbidden', __( 'Keine Berechtigung für diesen Beitrag.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	$detection = wpagent_exec_detect_builder( array( 'post_id' => $post_id ) );
	if ( is_wp_error( $detection ) ) {
		return $detection;
	}
	$report = array( 'block_count' => 0, 'freeform_count' => 0, 'block_types' => array() );
	wpagent_native_block_report_walk( parse_blocks( $post->post_content ), $report );
	$report['block_types'] = array_values( array_unique( $report['block_types'] ) );
	sort( $report['block_types'], SORT_STRING );
	$hash = hash(
		'sha256',
		wp_json_encode(
			array(
				'blog_id'   => (int) get_current_blog_id(),
				'id'        => $post_id,
				'post_type' => $post->post_type,
				'content'   => $post->post_content,
			),
			JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
		)
	);
	return array(
		'post_id'        => $post_id,
		'post_type'      => $post->post_type,
		'status'         => $post->post_status,
		'modified'       => $post->post_modified,
		'content'        => $post->post_content,
		'block_count'    => $report['block_count'],
		'freeform_count' => $report['freeform_count'],
		'block_types'    => $report['block_types'],
		'primary'        => (string) $detection['primary'],
		'hash'           => $hash,
	);
}

/** @param array<int,array<string,mixed>> $blocks @param array<string,mixed> $report */
function wpagent_native_block_report_walk( array $blocks, array &$report ): void {
	foreach ( $blocks as $block ) {
		$name = $block['blockName'] ?? null;
		if ( null === $name ) {
			if ( '' !== trim( (string) ( $block['innerHTML'] ?? '' ) ) ) {
				++$report['block_count'];
				++$report['freeform_count'];
				$report['block_types'][] = 'core/freeform';
			}
			continue;
		}
		++$report['block_count'];
		$report['block_types'][] = (string) $name;
		if ( ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) ) {
			wpagent_native_block_report_walk( $block['innerBlocks'], $report );
		}
	}
}

/** @param array<int,array<string,mixed>> $blocks */
function wpagent_native_block_has_patchable_spectra_block( array $blocks ): bool {
	$registry = function_exists( 'wpagent_spectra_block_registry' ) ? wpagent_spectra_block_registry() : array();
	if ( is_wp_error( $registry ) ) {
		return false;
	}
	foreach ( $blocks as $block ) {
		$name = is_string( $block['blockName'] ?? null ) ? $block['blockName'] : '';
		$slug = str_starts_with( $name, 'uagb/' ) ? substr( $name, 5 ) : '';
		$type = '' !== $slug ? WP_Block_Type_Registry::get_instance()->get_registered( $name ) : null;
		if ( isset( $registry[ $slug ] ) && $type instanceof WP_Block_Type && is_callable( $type->render_callback ) ) {
			foreach ( $type->get_attributes() as $attribute => $schema ) {
					if ( is_array( $schema ) && function_exists( 'wpagent_native_block_patchable_attribute_name' ) && wpagent_native_block_patchable_attribute_name( (string) $attribute )
						&& function_exists( 'wpagent_native_block_patchable_attribute_schema' ) && wpagent_native_block_patchable_attribute_schema( $schema ) ) {
					return true;
				}
			}
		}
		if ( ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) && wpagent_native_block_has_patchable_spectra_block( $block['innerBlocks'] ) ) {
			return true;
		}
	}
	return false;
}
