<?php
/**
 * Server-side enforcement for authenticated order-status changes.
 *
 * @package WOSR
 */

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

class WOSR_Enforcement {

	public function __construct() {
		add_filter( 'woocommerce_rest_pre_insert_shop_order_object', array( $this, 'validate_rest_status_transition' ), 10, 3 );
		add_action( 'wp_ajax_woocommerce_mark_order_status', array( $this, 'validate_ajax_status_transition' ), 0 );
		add_action( 'admin_init', array( $this, 'validate_bulk_status_transition' ), 5 );
		add_action( 'woocommerce_before_order_object_save', array( $this, 'protect_order_status' ), 5, 2 );
		add_filter( 'wp_insert_post_data', array( $this, 'protect_legacy_status_save' ), 10, 2 );
	}

	public function validate_rest_status_transition( $order, $request, $creating ) {
		$target = $request->get_param( 'status' );
		if ( $creating || ! $target || ! $order instanceof WC_Order ) {
			return $order;
		}
		$current = wc_get_order( $order->get_id() );
		if ( ! $current || WOSR_Permissions::status_transition_is_allowed( $current, $target, wp_get_current_user() ) ) {
			return $order;
		}
		return new WP_Error( 'wosr_status_forbidden', __( 'You are not allowed to move this order to the requested status.', 'order-role-manager-for-woocommerce' ), array( 'status' => 403 ) );
	}

	public function validate_ajax_status_transition() {
		$order_id = isset( $_REQUEST['order_id'] ) ? absint( $_REQUEST['order_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- WooCommerce verifies the action nonce in its callback.
		$target   = isset( $_REQUEST['status'] ) ? sanitize_key( wp_unslash( $_REQUEST['status'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- WooCommerce verifies the action nonce in its callback.
		$order    = $order_id ? wc_get_order( $order_id ) : false;
		if ( $order && $target && ! WOSR_Permissions::status_transition_is_allowed( $order, $target, wp_get_current_user() ) ) {
			wp_send_json_error( array( 'message' => __( 'You are not allowed to move this order to the requested status.', 'order-role-manager-for-woocommerce' ) ), 403 );
		}
	}

	public function validate_bulk_status_transition() {
		$action = isset( $_REQUEST['action'] ) ? sanitize_key( wp_unslash( $_REQUEST['action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only inspection before core processes the request.
		if ( ! $action || '-1' === $action ) {
			$action = isset( $_REQUEST['action2'] ) ? sanitize_key( wp_unslash( $_REQUEST['action2'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only inspection before core processes the request.
		}
		$target = WOSR_Permissions::get_bulk_target_status( $action );
		if ( ! $target ) {
			return;
		}

		$order_ids = array();
		if ( isset( $_REQUEST['id'] ) && is_array( $_REQUEST['id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$order_ids = wp_unslash( $_REQUEST['id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		} elseif ( isset( $_REQUEST['post'] ) && is_array( $_REQUEST['post'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$order_ids = wp_unslash( $_REQUEST['post'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		}
		$order_ids = array_filter( array_map( 'absint', $order_ids ) );
		if ( empty( $order_ids ) ) {
			return;
		}

		$blocked = array();
		$user    = wp_get_current_user();
		foreach ( $order_ids as $order_id ) {
			$order = wc_get_order( $order_id );
			if ( $order && ! WOSR_Permissions::status_transition_is_allowed( $order, $target, $user ) ) {
				$blocked[] = $order_id;
			}
		}
		if ( $blocked ) {
			$this->deny( sprintf( __( 'You are not allowed to update the status of these orders: %s', 'order-role-manager-for-woocommerce' ), implode( ', ', array_map( 'absint', $blocked ) ) ) );
		}
	}

	public function protect_order_status( $order, $data_store ) {
		unset( $data_store );
		$is_rest = defined( 'REST_REQUEST' ) && REST_REQUEST;
		if ( ! $order instanceof WC_Order || ! $order->get_id() || ! is_user_logged_in() || ( ! is_admin() && ! $is_rest ) ) {
			return;
		}
		$changes = $order->get_changes();
		if ( ! array_key_exists( 'status', $changes ) ) {
			return;
		}
		$current = wc_get_order( $order->get_id() );
		if ( $current && ! WOSR_Permissions::status_transition_is_allowed( $current, $changes['status'], wp_get_current_user() ) ) {
			$order->set_status( $current->get_status() );
		}
	}

	public function protect_legacy_status_save( $data, $postarr ) {
		$order_id = isset( $postarr['ID'] ) ? absint( $postarr['ID'] ) : 0;
		$is_rest  = defined( 'REST_REQUEST' ) && REST_REQUEST;
		if ( ! $order_id || 'shop_order' !== ( $data['post_type'] ?? '' ) || empty( $data['post_status'] ) || ! is_user_logged_in() || ( ! is_admin() && ! $is_rest ) ) {
			return $data;
		}
		$order = wc_get_order( $order_id );
		if ( $order && $data['post_status'] !== 'wc-' . $order->get_status() && ! WOSR_Permissions::status_transition_is_allowed( $order, $data['post_status'], wp_get_current_user() ) ) {
			$data['post_status'] = 'wc-' . $order->get_status();
		}
		return $data;
	}

	private function deny( $message ) {
		wp_die( esc_html( $message ), esc_html__( 'Permission Denied', 'order-role-manager-for-woocommerce' ), array( 'response' => 403, 'back_link' => true ) );
	}
}

new WOSR_Enforcement();
