<?php
/**
 * Update Core Tool.
 *
 * Allows the agent to update WordPress core to the latest version. Uses
 * Core_Upgrader class for filesystem operations and version management.
 *
 * @package   Agenistrator
 * @since     1.0.0
 * @author    Alex Ruban <alex@maximum.guru>
 * @author    Maximum Software Inc <contact@maximum.software>
 * @license   GPL-3.0-only
 * @link      https://maximum.software/
 *
 * SPDX-FileCopyrightText: 2025-2026 Alex Ruban <alex@maximum.guru>
 * SPDX-FileCopyrightText: 2025-2026 Maximum Software Inc <contact@maximum.software>
 * SPDX-License-Identifier: GPL-3.0-only
 */

namespace Agenistrator;

// Direct access prevention
if ( ! defined( 'ABSPATH' ) ) {
	return;
}

/**
 * Update_Core_Tool class.
 */
class Update_Core_Tool extends Tool {

	/**
	 * Get the tool ID.
	 *
	 * @return string The tool ID.
	 * @since     1.0.0
	 */
	public function get_id() {
		return 'update_core';
	}

	/**
	 * Get the tool name.
	 *
	 * @return string The tool name.
	 * @since     1.0.0
	 */
	public function get_name() {
		return __( 'Update WordPress Core', 'agenistrator' );
	}

	/**
	 * Get the tool description.
	 *
	 * @return string The tool description.
	 * @since     1.0.0
	 */
	public function get_description() {
		return 'Update WordPress core to the latest version.';
	}

	/**
	 * Get usage instructions for the LLM.
	 *
	 * @return string Instructions for using this tool.
	 * @since     1.0.0
	 */
	public function get_instructions() {
		return 'Use `list_available_updates` tool first to check if an update is available. This is a major operation - ensure you have a backup before proceeding.';
	}

	/**
	 * Get the parameters schema for this tool.
	 *
	 * @return array Parameters schema in JSON Schema format.
	 * @since     1.0.0
	 */
	public function get_parameters() {
		return array(
			'type'       => 'object',
			'properties' => array(
				'version' => array(
					'type'        => 'string',
					'description' => 'Optional: specific version to update to. If not provided, updates to the latest available version.',
				),
			),
			'required'   => array(),
		);
	}

	/**
	 * Check if the current user can execute this tool.
	 *
	 * @return bool True if the current user has permission.
	 * @since     1.0.0
	 */
	public function current_user_can_execute() {
		return current_user_can( 'update_core' );
	}

	/**
	 * Check if this tool is read-only.
	 *
	 * @return bool True if the tool only reads data.
	 * @since     1.0.0
	 */
	public function is_read_only() {
		return false;
	}

	/**
	 * Execute the tool with the given arguments.
	 *
	 * @param array $args The tool arguments.
	 *
	 * @return array The tool execution result.
	 * @since     1.0.0
	 */
	protected function execute( $args ) {
		// Check if file modifications are disabled
		if ( ! wp_is_file_mod_allowed( 'capability_update_core' ) ) {
			return $this->error_response( 'File modifications are disabled' );
		}

		require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
		require_once ABSPATH . 'wp-admin/includes/update.php';
		require_once ABSPATH . 'wp-admin/includes/admin.php';

		// Force check for updates
		wp_version_check();

		$update_core = get_site_transient( 'update_core' );

		if ( empty( $update_core->updates ) ) {
			return $this->success_response(
				'WordPress is already up to date',
				array(
					'current_version' => get_bloginfo( 'version' ),
					'updated'         => false,
				)
			);
		}

		// Find the appropriate update
		$target_update     = null;
		$requested_version = isset( $args['version'] ) ? sanitize_text_field( $args['version'] ) : null;

		foreach ( $update_core->updates as $update ) {
			// Skip if this is the current version
			if ( 'upgrade' !== $update->response ) {
				continue;
			}

			// If specific version requested, match it
			if ( null !== $requested_version ) {
				if ( $update->version === $requested_version ) {
					$target_update = $update;
					break;
				}
			} else {
				// Take the first upgrade available (latest)
				$target_update = $update;
				break;
			}
		}

		if ( ! $target_update ) {
			if ( $requested_version ) {
				return $this->error_response(
					String_Utils::replace_tags(
						__( 'Requested version {version} is not available for update', 'agenistrator' ),
						array( 'version' => $requested_version )
					)
				);
			}
			return $this->success_response(
				'WordPress is already up to date',
				array(
					'current_version' => get_bloginfo( 'version' ),
					'updated'         => false,
				)
			);
		}

		$old_version = get_bloginfo( 'version' );

		// Check PHP and MySQL requirements
		if ( isset( $target_update->php_version ) && version_compare( PHP_VERSION, $target_update->php_version, '<' ) ) {
			return $this->error_response(
				String_Utils::replace_tags(
					__( 'WordPress {wp_version} requires PHP {php_version} or higher. Current: {current_php}', 'agenistrator' ),
					array(
						'wp_version'  => $target_update->version,
						'php_version' => $target_update->php_version,
						'current_php' => PHP_VERSION,
					)
				)
			);
		}

		if ( isset( $target_update->mysql_version ) ) {
			global $wpdb;
			$mysql_version = $wpdb->db_version();
			if ( version_compare( $mysql_version, $target_update->mysql_version, '<' ) ) {
				return $this->error_response(
					String_Utils::replace_tags(
						__( 'WordPress {wp_version} requires MySQL {mysql_version} or higher. Current: {current_mysql}', 'agenistrator' ),
						array(
							'wp_version'    => $target_update->version,
							'mysql_version' => $target_update->mysql_version,
							'current_mysql' => $mysql_version,
						)
					)
				);
			}
		}

		// Perform the core update
		$upgrader = new \Core_Upgrader( new \WP_Ajax_Upgrader_Skin() );
		$result   = $upgrader->upgrade( $target_update );

		if ( is_wp_error( $result ) ) {
			return $this->error_response(
				String_Utils::replace_tags(
					__( 'Core update failed: {error}', 'agenistrator' ),
					array( 'error' => $result->get_error_message() )
				)
			);
		}

		$new_version = $target_update->version;

		// Trigger database upgrade via separate HTTP request (same approach WordPress uses internally).
		// The old PHP code is still in memory, so we must make a new request to load fresh code.
		$db_upgrade_url    = admin_url( 'upgrade.php?step=upgrade_db' );
		$db_upgrade_result = wp_remote_post(
			$db_upgrade_url,
			array(
				'timeout'    => 60,
				'user-agent' => 'Agenistrator/' . AGENISTRATOR_VERSION,
			)
		);
		$database_upgraded = ! is_wp_error( $db_upgrade_result );

		return $this->success_response(
			String_Utils::replace_tags(
				__( 'WordPress updated successfully from {old} to {new}', 'agenistrator' ),
				array(
					'old' => $old_version,
					'new' => $new_version,
				)
			),
			array(
				'old_version'       => $old_version,
				'new_version'       => $new_version,
				'updated'           => true,
				'database_upgraded' => $database_upgraded,
			)
		);
	}
}
