<?php
/** Update one verified Ocean Extra module switch. */

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

function wpagent_ability_update_oceanwp_extra_module(): array {
	return array(
		'label'               => __( 'Ocean-Extra-Modul aktualisieren', 'wp-agent-companion' ),
		'description'         => __( 'Ändert genau einen geprüften Ocean-Extra-Modulschalter mit Konfliktschutz und Read-back. Sicherheitsrelevante Module kann der Agent nur deaktivieren.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'                 => 'object',
			'properties'           => array(
				'module'        => array( 'type' => 'string', 'enum' => array_keys( wpagent_ocean_extra_module_catalog() ) ),
				'enabled'       => array( 'type' => 'boolean' ),
				'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			),
			'required'             => array( 'module', 'enabled', 'expected_hash' ),
			'additionalProperties' => false,
		),
		'output_schema'       => wpagent_ocean_extra_modules_output_schema( true ),
		'execute_callback'    => 'wpagent_exec_update_oceanwp_extra_module',
		'permission_callback' => 'wpagent_perm_manage_options',
		'meta'                => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => true ) ),
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_update_oceanwp_extra_module( $input ) {
	$ready = wpagent_ocean_extra_modules_require_runtime();
	if ( is_wp_error( $ready ) ) {
		return $ready;
	}
	$input   = is_array( $input ) ? $input : array();
	$catalog = wpagent_ocean_extra_module_catalog();
	$module  = is_string( $input['module'] ?? null ) ? $input['module'] : '';
	$enabled = $input['enabled'] ?? null;
	if ( ! isset( $catalog[ $module ] ) || ! is_bool( $enabled ) ) {
		return new WP_Error( 'wpagent_ocean_extra_module_invalid', __( 'Das Ocean-Extra-Modul oder sein Zielzustand ist ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( $enabled && 'disable_only' === $catalog[ $module ]['policy'] ) {
		return new WP_Error( 'wpagent_ocean_extra_module_enable_denied', __( 'Dieses sicherheitsrelevante Ocean-Extra-Modul darf der Agent nur deaktivieren.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$lock = wpagent_ocean_extra_modules_acquire_lock();
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$ready = wpagent_ocean_extra_modules_require_runtime();
		if ( is_wp_error( $ready ) || ! current_user_can( 'manage_options' ) ) {
			return is_wp_error( $ready ) ? $ready : new WP_Error( 'wpagent_ocean_extra_modules_permission_changed', __( 'Die Berechtigung zum Verwalten der Ocean-Extra-Module ist nicht mehr vorhanden.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		$before = wpagent_ocean_extra_modules_snapshot();
		if ( is_wp_error( $before ) ) {
			return $before;
		}
		$before_hash  = wpagent_ocean_extra_modules_state_hash( $before );
		$expected_hash = strtolower( (string) ( $input['expected_hash'] ?? '' ) );
		if ( ! preg_match( '/^[a-f0-9]{64}$/', $expected_hash ) || ! hash_equals( $before_hash, $expected_hash ) ) {
			return new WP_Error( 'wpagent_ocean_extra_modules_conflict', __( 'Die Ocean-Extra-Module haben sich seit dem Lesen geändert. Lies sie neu und wiederhole den Vorgang.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $before_hash ) );
		}
		$definition = $catalog[ $module ];
		$option     = $definition['option'];
		$desired    = $enabled ? $definition['enabled'] : $definition['disabled'];
		$expected   = $before;
		$expected['options'][ $option ] = array( 'exists' => true, 'value' => $desired );
		$write_started = false;
		if ( $before['options'][ $option ]['exists'] && $before['options'][ $option ]['value'] === $desired ) {
			$fresh = $before;
		} else {
			if ( ! wpagent_ocean_extra_modules_refresh_lock( $lock ) ) {
				return new WP_Error( 'wpagent_ocean_extra_modules_lock_lost', __( 'Die Ocean-Extra-Moduländerung hat ihre exklusive Sperre verloren.', 'wp-agent-companion' ), array( 'status' => 409 ) );
			}
			if ( ! current_user_can( 'manage_options' ) ) {
				return new WP_Error( 'wpagent_ocean_extra_modules_permission_changed', __( 'Die Berechtigung zum Verwalten der Ocean-Extra-Module ist nicht mehr vorhanden.', 'wp-agent-companion' ), array( 'status' => 403 ) );
			}
			try {
				$write_started = true;
				update_option( $option, $desired );
			} catch ( Throwable $error ) {
				return wpagent_ocean_extra_modules_recovery_required();
			}
			if ( ! wpagent_ocean_extra_modules_refresh_lock( $lock ) ) {
				return wpagent_ocean_extra_modules_recovery_required();
			}
			wpagent_companion_forget_option_cache( $option );
			$fresh = wpagent_ocean_extra_modules_snapshot();
			if ( is_wp_error( $fresh ) || ! hash_equals( wpagent_ocean_extra_modules_state_hash( $expected ), wpagent_ocean_extra_modules_state_hash( $fresh ) ) ) {
				return wpagent_ocean_extra_modules_recovery_required();
			}
			if ( ! wpagent_ocean_extra_modules_refresh_lock( $lock ) ) {
				return wpagent_ocean_extra_modules_recovery_required();
			}
		}
		if ( ! wpagent_ocean_extra_modules_refresh_lock( $lock ) ) {
			return $write_started
				? wpagent_ocean_extra_modules_recovery_required()
				: new WP_Error( 'wpagent_ocean_extra_modules_lock_lost', __( 'Die Ocean-Extra-Moduländerung hat ihre exklusive Sperre verloren.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		if ( ! current_user_can( 'manage_options' ) ) {
			return $write_started
				? wpagent_ocean_extra_modules_recovery_required()
				: new WP_Error( 'wpagent_ocean_extra_modules_permission_changed', __( 'Die Berechtigung zum Verwalten der Ocean-Extra-Module ist nicht mehr vorhanden.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		return array(
			'modules'                    => wpagent_ocean_extra_modules_normalize( $fresh ),
			'state_hash'                 => wpagent_ocean_extra_modules_state_hash( $fresh ),
			'verified'                   => true,
			'effective_after_new_request' => true,
		);
	} finally {
		wpagent_ocean_extra_modules_release_lock( $lock );
	}
}
