<?php

declare(strict_types=1);

namespace SiteFort\Modules\Tools;

// If this file is called directly, abort.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Database helpers shared by high-risk security tools.
 */
final class ToolDatabase {

	/**
	 * Escape a validated table identifier for direct interpolation.
	 */
	public static function table_identifier( string $table_name ): string {
		if ( $table_name === '' || strlen( $table_name ) > 64 || ! preg_match( '/^[A-Za-z0-9_]+$/', $table_name ) ) {
			throw new \InvalidArgumentException( 'Invalid table identifier.' );
		}

		return '`' . $table_name . '`';
	}

	/**
	 * Ensure all tables that participate in a transaction support rollback semantics.
	 *
	 * @param string[] $tables         Table names to verify.
	 * @param string   $operation_name Human-readable operation name for errors.
	 * @return true|\WP_Error
	 */
	public static function assert_transactional_tables( array $tables, string $operation_name ) {
		global $wpdb;

		$non_transactional = [];
		$operation_name    = trim( $operation_name ) !== '' ? trim( $operation_name ) : 'operation';

		foreach ( array_values( array_unique( array_filter( $tables, 'is_string' ) ) ) as $table ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Operational preflight.
			$status = $wpdb->get_row(
				$wpdb->prepare( 'SHOW TABLE STATUS WHERE Name = %s', $table ),
				ARRAY_A
			);

			if ( ! is_array( $status ) ) {
				return new \WP_Error(
					'db_error',
					'Unable to verify database table engines before the ' . $operation_name . '.'
				);
			}

			$engine = strtolower( (string) ( $status['Engine'] ?? '' ) );
			if ( ! self::is_transactional_engine( $engine ) ) {
				$non_transactional[] = $table . ( '' !== $engine ? ' (' . $engine . ')' : '' );
			}
		}

		if ( ! empty( $non_transactional ) ) {
			return new \WP_Error(
				'non_transactional_tables',
				'The ' . $operation_name . ' requires transactional database tables. Non-transactional tables: ' . implode( ', ', $non_transactional ) . '.'
			);
		}

		return true;
	}

	private static function is_transactional_engine( string $engine ): bool {
		return in_array( $engine, [ 'innodb', 'xtradb', 'ndbcluster', 'rocksdb' ], true );
	}
}
