<?php
/**
 * Custom Order Statuses module.
 *
 * @package Kramar
 * @since   1.0.0
 */

declare( strict_types=1 );

namespace Kramar\Modules\Orders;

// Prevent direct access.
defined( 'ABSPATH' ) || exit;

/**
 * Custom Order Statuses module.
 *
 * Lets shop owners create custom WooCommerce order statuses with configurable
 * labels, badge colors, and behavior flags. Statuses are stored in a dedicated
 * option (`kramar_custom_order_statuses`) separate from the main settings array
 * so they can be loaded early on `init` and managed via their own UI.
 *
 * @since 1.0.0
 */
final class Custom_Statuses extends \Kramar\Module {

	/**
	 * Option name for storing the list of custom statuses.
	 *
	 * @since 1.0.0
	 */
	private const STATUSES_OPTION = 'kramar_custom_order_statuses';

	/**
	 * POST action for the status management form.
	 *
	 * @since 1.0.0
	 */
	private const FORM_ACTION = 'kramar_manage_status';

	/**
	 * Nonce action for the status management form.
	 *
	 * @since 1.0.0
	 */
	private const NONCE_ACTION = 'kramar_manage_status_nonce';

	/**
	 * Admin sub-page slug.
	 *
	 * @since 1.0.0
	 */
	private const PAGE_SLUG = 'kramar-order-statuses';

	/**
	 * Maximum length of a custom status slug.
	 *
	 * Both order status columns — `wp_wc_orders.status` (HPOS) and
	 * `wp_posts.post_status` (legacy CPT) — are `varchar(20)`, and WooCommerce
	 * stores statuses with the `wc-` prefix. On hosts without
	 * STRICT_TRANS_TABLES a longer value is silently truncated on write, which
	 * leaves the order holding a status nothing has registered — WooCommerce
	 * then falls back to "pending" with no error anywhere.
	 *
	 * @since 1.0.1
	 */
	private const MAX_SLUG_LENGTH = 17;

	/**
	 * Hook suffix returned by add_submenu_page().
	 *
	 * @since 1.0.0
	 */
	private string $page_hook = '';
	private string $redirect_error = '';

	/**
	 * {@inheritDoc}
	 */
	public function get_slug(): string {
		return 'custom-statuses';
	}

	/**
	 * {@inheritDoc}
	 */
	public function get_category(): string {
		return 'orders';
	}

	/**
	 * {@inheritDoc}
	 */
	public function get_name(): string {
		return __( 'Custom Order Statuses', 'kramar' );
	}

	/**
	 * {@inheritDoc}
	 */
	public function get_description(): string {
		return __( 'Create custom WooCommerce order statuses with configurable labels, badge colors, and behavior flags (paid, editable, downloads, email notifications).', 'kramar' );
	}

	/**
	 * {@inheritDoc}
	 *
	 * The module toggle is the only setting stored in the main `kramar_settings`
	 * option. The actual status list lives in `kramar_custom_order_statuses`.
	 */
	public function get_default_settings(): array {
		return [
			'enabled' => false,
		];
	}

	/**
	 * {@inheritDoc}
	 */
	public function sanitize_settings( array $input ): array {
		return [
			'enabled' => ! empty( $input['enabled'] ),
		];
	}

	/**
	 * {@inheritDoc}
	 */
	protected function run(): void {
		// Register all saved statuses with WordPress early on init.
		add_action( 'init', [ $this, 'register_statuses' ], 9 );

		// WooCommerce integration.
		add_filter( 'wc_order_statuses', [ $this, 'add_to_wc_statuses' ] );
		add_filter( 'woocommerce_order_is_paid_statuses', [ $this, 'add_paid_statuses' ] );
		add_filter( 'wc_order_is_editable', [ $this, 'filter_editable' ], 10, 2 );
		add_filter( 'woocommerce_order_is_download_permitted', [ $this, 'filter_downloads' ], 10, 2 );

		// Bulk actions for both CPT and HPOS order screens.
		add_filter( 'bulk_actions-edit-shop_order', [ $this, 'add_bulk_actions' ] );
		add_filter( 'bulk_actions-woocommerce_page_wc-orders', [ $this, 'add_bulk_actions' ] );

		// Badge styling in the admin.
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_badge_styles' ] );

		// Note: status notification emails are NOT sent from this module. The
		// "Sends email" flag creates/enables a custom email in the Email Manager
		// (see sync_custom_email()), and Email Manager's Custom_Email_Triggers
		// delivers it through WC_Email on woocommerce_order_status_changed. This
		// module previously also sent one itself via wp_mail() on the dynamic
		// woocommerce_order_status_{slug} action, which made every custom-status
		// notification go out twice.

		// Admin form handler.
		add_action( 'admin_post_' . self::FORM_ACTION, [ $this, 'handle_status_form' ] );

		// Register the dedicated sub-page.
		add_action( 'admin_menu', [ $this, 'register_admin_page' ] );

		// Enqueue assets only on this page.
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_page_assets' ] );
	}

	// -------------------------------------------------------------------------
	// Admin Page Registration
	// -------------------------------------------------------------------------

	/**
	 * Register the Order Statuses sub-page under the Kramar menu.
	 *
	 * @since 1.0.0
	 */
	public function register_admin_page(): void {
		$this->page_hook = (string) add_submenu_page(
			'kramar',
			__( 'Order Statuses', 'kramar' ),
			__( 'Order Statuses', 'kramar' ),
			'manage_options',
			self::PAGE_SLUG,
			[ $this, 'render_page' ]
		);
	}

	/**
	 * Enqueue admin stylesheet on the Order Statuses page only.
	 *
	 * @since 1.0.0
	 *
	 * @param string $hook_suffix Current page hook suffix.
	 */
	public function enqueue_page_assets( string $hook_suffix ): void {
		if ( $hook_suffix !== $this->page_hook ) {
			return;
		}

		wp_enqueue_style(
			'kramar-admin',
			KRAMAR_URL . 'assets/css/admin.css',
			[],
			KRAMAR_VERSION
		);

		wp_enqueue_script(
			'kramar-custom-statuses-admin',
			KRAMAR_URL . 'assets/js/custom-statuses-admin.js',
			[],
			KRAMAR_VERSION,
			true
		);

		wp_localize_script(
			'kramar-custom-statuses-admin',
			'kramarCustomStatuses',
			[
				'maxSlug' => self::MAX_SLUG_LENGTH,
				'i18n'    => [
					'deleteWithCount' => __( 'Delete this status? {count} order(s) currently use it. The status will be removed from those orders.', 'kramar' ),
					'deleteConfirm'   => __( 'Delete this status?', 'kramar' ),
					'slugTooLong'     => __( 'Too long — {count} characters. Shorten the name, or type a slug of at most {max} characters.', 'kramar' ),
				],
			]
		);
	}

	/**
	 * Enqueue dynamic badge-colour CSS for custom statuses on order screens.
	 *
	 * @since 1.0.0
	 */
	public function enqueue_badge_styles(): void {
		$statuses = $this->get_statuses();
		if ( empty( $statuses ) ) {
			return;
		}

		$screen = get_current_screen();
		if (
			! $screen ||
			( ! in_array( $screen->id, [ 'edit-shop_order', 'shop_order', 'woocommerce_page_wc-orders' ], true ) &&
			! str_contains( $screen->id, 'kramar' ) )
		) {
			return;
		}

		wp_enqueue_style( 'kramar-admin', KRAMAR_URL . 'assets/css/admin.css', [], KRAMAR_VERSION );

		$css = '';
		foreach ( $statuses as $status ) {
			$slug       = sanitize_key( $status['slug'] );
			$bg_color   = sanitize_hex_color( $status['badge_color'] ?? '#777' ) ?? '#777';
			$text_color = sanitize_hex_color( $status['badge_text_color'] ?? '#fff' ) ?? '#fff';

			if ( '' === $slug ) {
				continue;
			}

			$css .= sprintf(
				'.order-status.status-%s { background: %s; color: %s; }',
				esc_attr( $slug ),
				esc_attr( $bg_color ),
				esc_attr( $text_color )
			);
		}

		if ( '' !== $css ) {
			wp_add_inline_style( 'kramar-admin', $css );
		}
	}

	// -------------------------------------------------------------------------
	// Status Registration
	// -------------------------------------------------------------------------

	/**
	 * Register all saved custom statuses with WordPress.
	 *
	 * Hooked at `init` priority 9 so statuses are available before WooCommerce
	 * finalizes its own status list at priority 10.
	 *
	 * @since 1.0.0
	 */
	public function register_statuses(): void {
		foreach ( $this->get_statuses() as $status ) {
			$this->register_one_status( $status );
		}
	}

	/**
	 * Build a nooped-plural array for register_post_status()'s `label_count`
	 * from a runtime status label, mirroring _n_noop()'s return shape without
	 * passing a variable to a gettext function (which the translation parser
	 * cannot extract statically).
	 *
	 * @since 1.0.0
	 *
	 * @param string $label Status label (already sanitized upstream).
	 * @return array<int|string, string|null>
	 */
	private static function make_label_count( string $label ): array {
		$format = $label . ' <span class="count">(%s)</span>';
		return [
			0          => $format,
			1          => $format,
			'singular' => $format,
			'plural'   => $format,
			'context'  => null,
			'domain'   => 'kramar',
		];
	}

	/**
	 * Register a single saved custom status with WordPress.
	 *
	 * @since 1.0.0
	 *
	 * @param array<string, mixed> $status Status definition.
	 */
	private function register_one_status( array $status ): void {
		$slug  = sanitize_key( $status['slug'] );
		$label = sanitize_text_field( $status['label'] );

		if ( '' === $slug || '' === $label ) {
			return;
		}

		// A slug longer than the limit cannot survive a write to the 20-character
		// status column: it is silently truncated, matches nothing registered,
		// and the order falls back to Pending — while the status-change email
		// still goes out, so the shop owner is told the order moved when it did
		// not. Statuses saved before that was validated are simply not
		// registered, which takes them out of the status dropdown and the bulk
		// actions so no further orders can be broken. The Order Statuses screen
		// keeps listing them, flagged, with instructions to recreate them.
		// Deliberately a runtime check rather than an upgrade routine, so it
		// also holds on a site whose upgrade hook never ran.
		if ( strlen( $slug ) > self::MAX_SLUG_LENGTH ) {
			return;
		}

		register_post_status(
			'wc-' . $slug,
			[
				'label'                     => $label,
				'public'                     => true,
				'exclude_from_search'        => false,
				'show_in_admin_all_list'     => true,
				'show_in_admin_status_list'  => true,
				// Built by hand rather than _n_noop() because $label is runtime
				// data (a user-defined status label), not a source literal the
				// translation parser could extract.
				'label_count'                => self::make_label_count( $label ),
			]
		);
	}

	// -------------------------------------------------------------------------
	// WooCommerce Integration Filters
	// -------------------------------------------------------------------------

	/**
	 * Add custom statuses to the WooCommerce order status dropdown.
	 *
	 * @since 1.0.0
	 *
	 * @param array<string, string> $statuses Existing WC statuses (wc-slug => label).
	 * @return array<string, string> Extended statuses.
	 */
	public function add_to_wc_statuses( array $statuses ): array {
		foreach ( $this->get_statuses() as $status ) {
			$slug  = sanitize_key( $status['slug'] );
			$label = sanitize_text_field( $status['label'] );

			// See register_one_status(): an over-length slug can't be stored, so
			// it must not be selectable either.
			if ( strlen( $slug ) > self::MAX_SLUG_LENGTH ) {
				continue;
			}

			if ( '' !== $slug && '' !== $label ) {
				$statuses[ 'wc-' . $slug ] = $label;
			}
		}

		return $statuses;
	}

	/**
	 * Mark custom statuses as "paid" when the flag is set.
	 *
	 * @since 1.0.0
	 *
	 * @param array<int, string> $statuses Existing paid status slugs (without wc- prefix).
	 * @return array<int, string> Extended list.
	 */
	public function add_paid_statuses( array $statuses ): array {
		foreach ( $this->get_statuses() as $status ) {
			if ( ! empty( $status['is_paid'] ) ) {
				$slug = sanitize_key( $status['slug'] );
				if ( '' !== $slug ) {
					$statuses[] = $slug;
				}
			}
		}

		return $statuses;
	}

	/**
	 * Allow editing of orders in custom statuses with the `is_editable` flag.
	 *
	 * @since 1.0.0
	 *
	 * @param bool      $editable Whether the order is currently editable.
	 * @param \WC_Order $order    The order object.
	 * @return bool Modified editability.
	 */
	public function filter_editable( bool $editable, \WC_Order $order ): bool {
		$order_status = $order->get_status(); // Without wc- prefix.

		foreach ( $this->get_statuses() as $status ) {
			if ( sanitize_key( $status['slug'] ) === $order_status && ! empty( $status['is_editable'] ) ) {
				return true;
			}
		}

		return $editable;
	}

	/**
	 * Permit downloads for orders in custom statuses with the `grants_downloads` flag.
	 *
	 * @since 1.0.0
	 *
	 * @param bool      $permitted Whether downloads are currently permitted.
	 * @param \WC_Order $order     The order object.
	 * @return bool Modified permission.
	 */
	public function filter_downloads( bool $permitted, \WC_Order $order ): bool {
		$order_status = $order->get_status(); // Without wc- prefix.

		foreach ( $this->get_statuses() as $status ) {
			if ( sanitize_key( $status['slug'] ) === $order_status && ! empty( $status['grants_downloads'] ) ) {
				return true;
			}
		}

		return $permitted;
	}

	/**
	 * Add bulk actions for each custom status to the orders list screen.
	 *
	 * @since 1.0.0
	 *
	 * @param array<string, string> $actions Existing bulk actions.
	 * @return array<string, string> Extended bulk actions.
	 */
	public function add_bulk_actions( array $actions ): array {
		foreach ( $this->get_statuses() as $status ) {
			$slug  = sanitize_key( $status['slug'] );
			$label = sanitize_text_field( $status['label'] );

			if ( strlen( $slug ) > self::MAX_SLUG_LENGTH ) {
				continue;
			}

			if ( '' !== $slug && '' !== $label ) {
				/* translators: %s: order status label */
				$actions[ 'mark_' . $slug ] = sprintf( __( 'Change status to %s', 'kramar' ), $label );
			}
		}

		return $actions;
	}

	// -------------------------------------------------------------------------
	// Admin Form Handler (PRG pattern)
	// -------------------------------------------------------------------------

	/**
	 * Handle status add/edit/delete form submissions.
	 *
	 * Hooked on `admin_post_kramar_manage_status`. Verifies nonce and capability,
	 * dispatches to add, edit, or delete, then redirects back (PRG).
	 *
	 * @since 1.0.0
	 */
	public function handle_status_form(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have permission to manage order statuses.', 'kramar' ) );
		}

		check_admin_referer( self::NONCE_ACTION );

		$action = sanitize_key( $_POST['kramar_status_action'] ?? '' );

		if ( 'add' === $action ) {
			$this->handle_add_status();
		} elseif ( 'edit' === $action ) {
			$this->handle_edit_status();
		} elseif ( 'delete' === $action ) {
			$this->handle_delete_status();
		}

		$args = [ 'page' => self::PAGE_SLUG ];
		if ( '' !== $this->redirect_error ) {
			$args['error'] = rawurlencode( $this->redirect_error );
		} else {
			$args['status-updated'] = '1';
		}

		wp_safe_redirect( add_query_arg( $args, admin_url( 'admin.php' ) ) );
		exit;
	}

	/**
	 * Add a new custom status from POST data.
	 *
	 * @since 1.0.0
	 */
	private function handle_add_status(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$label = sanitize_text_field( wp_unslash( $_POST['kramar_status_label'] ?? '' ) );

		if ( '' === $label ) {
			return;
		}

		// An explicit slug wins; otherwise derive one from the name. A separate
		// slug matters because plenty of perfectly reasonable names are longer
		// than the 17 characters the database column allows.
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$raw_slug = sanitize_text_field( wp_unslash( $_POST['kramar_status_slug'] ?? '' ) );
		$raw_slug = preg_replace( '/^wc-/', '', trim( $raw_slug ) ) ?? '';
		$slug     = sanitize_key( sanitize_title( '' !== $raw_slug ? $raw_slug : $label ) );

		if ( '' === $slug ) {
			$this->redirect_error = __( 'Please enter a status name that contains at least one letter or number.', 'kramar' );
			return;
		}

		if ( strlen( $slug ) > self::MAX_SLUG_LENGTH ) {
			$this->redirect_error = sprintf(
				/* translators: 1: status slug, 2: maximum slug length in characters */
				__( 'The slug "%1$s" is too long. WooCommerce stores order statuses in a 20-character database column and adds a "wc-" prefix, so a slug can be at most %2$d characters. Shorten the name, or enter a shorter slug of your own.', 'kramar' ),
				$slug,
				self::MAX_SLUG_LENGTH
			);
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$badge_color      = sanitize_hex_color( wp_unslash( $_POST['kramar_status_badge_color'] ?? '#4a90d9' ) ) ?? '#4a90d9';
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$badge_text_color = sanitize_hex_color( wp_unslash( $_POST['kramar_status_badge_text_color'] ?? '#ffffff' ) ) ?? '#ffffff';
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$is_paid          = ! empty( $_POST['kramar_status_is_paid'] );
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$is_editable      = ! empty( $_POST['kramar_status_is_editable'] );
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$grants_downloads = ! empty( $_POST['kramar_status_grants_downloads'] );
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$send_email       = ! empty( $_POST['kramar_status_send_email'] );

		$new_status = [
			'slug'             => $slug,
			'label'            => $label,
			'badge_color'      => $badge_color,
			'badge_text_color' => $badge_text_color,
			'is_paid'          => $is_paid,
			'is_editable'      => $is_editable,
			'grants_downloads' => $grants_downloads,
			'send_email'       => $send_email,
		];

		$statuses = $this->get_statuses();

		// Prevent duplicate slugs.
		foreach ( $statuses as $existing ) {
			if ( sanitize_key( $existing['slug'] ) === $slug ) {
				$this->redirect_error = sprintf(
					/* translators: %s: status slug */
					__( 'A status with slug "%s" already exists.', 'kramar' ),
					$slug
				);
				return;
			}
		}

		// Prevent conflicts with WooCommerce core statuses and with the ones
		// Kramar's own Refund & Returns module registers — a collision there
		// would have two modules owning the same status.
		$reserved = [
			'pending',
			'processing',
			'on-hold',
			'completed',
			'cancelled',
			'refunded',
			'failed',
			'checkout-draft',
			'return-requested',
			'return-approved',
			'return-rejected',
		];
		if ( in_array( $slug, $reserved, true ) ) {
			$this->redirect_error = sprintf(
				/* translators: %s: status slug */
				__( '"%s" is already used by WooCommerce or by Kramar and cannot be reused.', 'kramar' ),
				$slug
			);
			return;
		}

		$statuses[] = $new_status;
		update_option( self::STATUSES_OPTION, $statuses, false );

		$this->sync_custom_email( $slug, $label, $send_email );
	}

	/**
	 * Update an existing custom status from POST data.
	 *
	 * @since 1.0.0
	 */
	private function handle_edit_status(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$original_slug = sanitize_key( wp_unslash( $_POST['kramar_status_original_slug'] ?? '' ) );
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$label         = sanitize_text_field( wp_unslash( $_POST['kramar_status_label'] ?? '' ) );

		if ( '' === $original_slug || '' === $label ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$badge_color      = sanitize_hex_color( wp_unslash( $_POST['kramar_status_badge_color'] ?? '#4a90d9' ) ) ?? '#4a90d9';
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$badge_text_color = sanitize_hex_color( wp_unslash( $_POST['kramar_status_badge_text_color'] ?? '#ffffff' ) ) ?? '#ffffff';
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$is_paid          = ! empty( $_POST['kramar_status_is_paid'] );
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$is_editable      = ! empty( $_POST['kramar_status_is_editable'] );
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$grants_downloads = ! empty( $_POST['kramar_status_grants_downloads'] );
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$send_email       = ! empty( $_POST['kramar_status_send_email'] );

		$updated_status = [
			'slug'             => $original_slug,
			'label'            => $label,
			'badge_color'      => $badge_color,
			'badge_text_color' => $badge_text_color,
			'is_paid'          => $is_paid,
			'is_editable'      => $is_editable,
			'grants_downloads' => $grants_downloads,
			'send_email'       => $send_email,
		];

		$statuses = $this->get_statuses();
		foreach ( $statuses as $i => $existing ) {
			if ( sanitize_key( $existing['slug'] ) === $original_slug ) {
				$statuses[ $i ] = $updated_status;
				break;
			}
		}

		update_option( self::STATUSES_OPTION, $statuses, false );

		$this->sync_custom_email( $original_slug, $label, $send_email );
	}

	/**
	 * Create, refresh, or disable this status's auto-generated custom email.
	 *
	 * The status's "Sends email" checkbox is authoritative: it drives the
	 * `enabled` flag on the matching `kramar_custom_emails` entry, which is what
	 * Email Manager's Custom_Email_Triggers checks before sending. Nothing in
	 * this module sends the email itself.
	 *
	 * @since 1.0.0
	 *
	 * @param string $slug       Status slug (without wc- prefix).
	 * @param string $label      Human-readable status label.
	 * @param bool   $send_email Whether the status should notify the customer.
	 */
	private function sync_custom_email( string $slug, string $label, bool $send_email ): void {
		$email_id = 'kramar_status_' . $slug;
		$custom   = get_option( 'kramar_custom_emails', [] );
		if ( ! is_array( $custom ) ) {
			$custom = [];
		}

		if ( ! $send_email ) {
			// Don't delete the entry — the shop owner may have built a template
			// for it — just stop it from triggering.
			if ( isset( $custom[ $email_id ] ) ) {
				$custom[ $email_id ]['enabled'] = false;
				update_option( 'kramar_custom_emails', $custom );
			}
			return;
		}

		if ( isset( $custom[ $email_id ] ) ) {
			// The email already exists — refresh only the label-derived display
			// fields so a status rename propagates. The slug (and thus $email_id)
			// never changes on edit, so this is the only place a renamed label can
			// reach the email. None of these fields are independently editable in
			// the Email Builder (a user's own subject edit is stored separately in
			// kramar_email_overrides and still takes precedence at send time), so
			// refreshing them never clobbers a customization.
			/* translators: %s: custom order status label */
			$custom[ $email_id ]['title']               = sprintf( __( 'Order status: %s', 'kramar' ), $label );
			/* translators: %s: custom order status label */
			$custom[ $email_id ]['description']         = sprintf( __( 'Sent to the customer when an order transitions to %s.', 'kramar' ), $label );
			/* translators: %s: status label */
			$custom[ $email_id ]['subject']             = sprintf( __( 'Your order #{order_number} is now: %s', 'kramar' ), $label );
			/* translators: %s: status label */
			$custom[ $email_id ]['trigger_description'] = sprintf( 'Status → %s', $label );
			$custom[ $email_id ]['enabled']             = true;

			update_option( 'kramar_custom_emails', $custom );
			return;
		}

		$custom[ $email_id ] = [
			/* translators: %s: custom order status label */
			'title'               => sprintf( __( 'Order status: %s', 'kramar' ), $label ),
			/* translators: %s: custom order status label */
			'description'         => sprintf( __( 'Sent to the customer when an order transitions to %s.', 'kramar' ), $label ),
			'context'             => 'order',
			'trigger_type'        => 'status_change',
			'trigger_from'        => '',
			'trigger_to'          => $slug,
			'recipient_type'      => 'customer',
			'recipient'           => '',
			/* translators: %s: status label */
			'subject'             => sprintf( __( 'Your order #{order_number} is now: %s', 'kramar' ), $label ),
			'enabled'             => true,
			/* translators: %s: status label */
			'trigger_description' => sprintf( 'Status → %s', $label ),
		];

		update_option( 'kramar_custom_emails', $custom );
	}

	/**
	 * Delete a custom status from POST data.
	 *
	 * @since 1.0.0
	 */
	private function handle_delete_status(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified via check_admin_referer() in handle_status_form()
		$slug = sanitize_key( wp_unslash( $_POST['kramar_status_slug'] ?? '' ) );
		$slug = sanitize_key( preg_replace( '/^wc-/', '', $slug ) ?? '' );

		if ( '' === $slug ) {
			return;
		}

		$statuses = $this->get_statuses();
		$statuses = array_values(
			array_filter(
				$statuses,
				static fn( array $s ) => sanitize_key( $s['slug'] ) !== $slug
			)
		);

		update_option( self::STATUSES_OPTION, $statuses, false );

		// Switch its notification off. The entry is kept (a built template is
		// worth preserving), but leaving it enabled strands an email in the
		// Email Manager for a status that no longer exists — and it would come
		// back to life, still carrying the old wording, if a status with the
		// same slug were created later.
		$custom   = get_option( 'kramar_custom_emails', [] );
		$email_id = 'kramar_status_' . $slug;
		if ( is_array( $custom ) && isset( $custom[ $email_id ] ) ) {
			$custom[ $email_id ]['enabled'] = false;
			update_option( 'kramar_custom_emails', $custom );
		}
	}

	// -------------------------------------------------------------------------
	// Order Statuses Sub-Page
	// -------------------------------------------------------------------------

	/**
	 * Render the dedicated Order Statuses admin page.
	 *
	 * @since 1.0.0
	 */
	public function render_page(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have permission to view this page.', 'kramar' ) );
		}

		$statuses = $this->get_statuses();
		$form_url = admin_url( 'admin-post.php' );
		$updated  = ! empty( $_GET['status-updated'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended

		// Build a map of order counts by status slug.
		$order_counts = $this->get_order_counts( $statuses );

		// Build the list of registered custom status slugs for the developer reference.
		$registered_slugs = array_filter(
			array_map(
				static fn( array $s ) => sanitize_key( $s['slug'] ),
				$statuses
			)
		);
		?>
		<div class="wrap kramar-settings kramar-os-page">

			<?php if ( $updated ) : ?>
				<div class="kramar-os-notice kramar-os-notice--success"><?php esc_html_e( 'Order status saved.', 'kramar' ); ?></div>
			<?php endif; ?>
			<?php
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- read-only display; value is unslashed, URL-decoded, then sanitize_text_field'd
			$error_msg = isset( $_GET['error'] ) ? sanitize_text_field( rawurldecode( wp_unslash( $_GET['error'] ) ) ) : '';
			if ( '' !== $error_msg ) : ?>
				<div class="kramar-os-notice kramar-os-notice--error"><?php echo esc_html( $error_msg ); ?></div>
			<?php endif; ?>

			<?php
			// Statuses saved before slug-length validation existed (or imported)
			// cannot be written to an order at all — flag them loudly.
			$over_length = array_values(
				array_filter(
					array_map(
						static fn( array $s ) => sanitize_key( $s['slug'] ),
						$statuses
					),
					static fn( string $s ) => strlen( $s ) > self::MAX_SLUG_LENGTH
				)
			);
			if ( ! empty( $over_length ) ) :
				?>
				<div class="kramar-os-notice kramar-os-notice--error">
					<?php
					printf(
						/* translators: 1: comma-separated list of status slugs, 2: maximum slug length in characters */
						esc_html__( 'These status slugs are longer than the %2$d characters the database allows: %1$s. Orders cannot be saved with them — the status is silently truncated and the order falls back to Pending. Delete each one and recreate it with a shorter slug, then move any affected orders.', 'kramar' ),
						esc_html( implode( ', ', $over_length ) ),
						(int) self::MAX_SLUG_LENGTH
					);
					?>
				</div>
			<?php endif; ?>

			<?php
			$sends_email = (bool) array_filter( $statuses, static fn( array $s ) => ! empty( $s['send_email'] ) );
			if ( $sends_email && ! $this->email_manager_active() ) :
				?>
				<div class="kramar-os-notice kramar-os-notice--warning">
					<?php esc_html_e( 'One or more statuses are set to send a customer notification, but the Email Manager module is disabled — those emails will not be sent. Enable it under Kramar → Modules.', 'kramar' ); ?>
				</div>
			<?php endif; ?>

			<?php
			// "Sends email" is only real if the matching entry exists and is on —
			// it can have been deleted from the Email Manager after the fact.
			$emails  = (array) get_option( 'kramar_custom_emails', [] );
			$orphans = [];
			foreach ( $statuses as $s ) {
				$s_slug = sanitize_key( $s['slug'] ?? '' );
				if ( '' === $s_slug || empty( $s['send_email'] ) ) {
					continue;
				}
				if ( empty( $emails[ 'kramar_status_' . $s_slug ]['enabled'] ) ) {
					$orphans[] = $s_slug;
				}
			}

			// Orders can still hold a status that was deleted. Its slug is no
			// longer registered, so WooCommerce's status dropdown on the order
			// screen has no matching option and the browser falls back to showing
			// the first one — "Pending payment". An admin who opens such an order
			// just to look at it and presses Update silently downgrades it.
			$unregistered = [];
			if ( class_exists( '\Automattic\WooCommerce\Utilities\OrderUtil' ) ) {
				global $wpdb;
				$known  = array_keys( wc_get_order_statuses() );
				$hpos   = \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled();
				$table  = $hpos ? $wpdb->prefix . 'wc_orders' : $wpdb->posts;
				$column = $hpos ? 'status' : 'post_status';

				// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
				$rows = $wpdb->get_results( "SELECT {$column} AS status_value, COUNT(*) AS total FROM {$table} WHERE {$column} LIKE 'wc-%' GROUP BY {$column}", ARRAY_A );
				// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared

				foreach ( (array) $rows as $row ) {
					if ( ! in_array( $row['status_value'], $known, true ) ) {
						$unregistered[] = sprintf( '%s (%d)', $row['status_value'], (int) $row['total'] );
					}
				}
			}

			if ( ! empty( $unregistered ) ) :
				?>
				<div class="kramar-os-notice kramar-os-notice--error">
					<?php
					printf(
						/* translators: %s: comma-separated status slugs with order counts */
						esc_html__( 'Some orders hold a status that no longer exists: %s. WooCommerce cannot display these, so those order screens show “Pending payment” — and saving one of them will set it to Pending for real. Recreate the status, or move those orders to a status you still use, before editing them.', 'kramar' ),
						esc_html( implode( ', ', $unregistered ) )
					);
					?>
				</div>
				<?php
			endif;

			if ( ! empty( $orphans ) ) :
				?>
				<div class="kramar-os-notice kramar-os-notice--warning">
					<?php
					printf(
						/* translators: %s: comma-separated list of status slugs */
						esc_html__( 'These statuses are set to send a customer notification, but their email is missing or switched off in the Email Manager, so nothing is sent: %s. Open each one, press Save Status, and the email is recreated.', 'kramar' ),
						esc_html( implode( ', ', $orphans ) )
					);
					?>
				</div>
			<?php endif; ?>

			<div class="kramar-os-header">
				<h1><?php esc_html_e( 'Order Statuses', 'kramar' ); ?></h1>
				<button type="button" class="button button-primary kramar-os-add-btn" id="kramar-os-add-btn">
					<?php esc_html_e( 'Add Status', 'kramar' ); ?>
				</button>
			</div>

			<?php /* ── Add form (hidden by default) ── */ ?>
			<div class="kramar-os-form-wrap" id="kramar-os-add-form-wrap" style="display:none;">
				<div class="kramar-os-form-card">
					<h2><?php esc_html_e( 'Add Status', 'kramar' ); ?></h2>
					<form method="post" action="<?php echo esc_url( $form_url ); ?>">
						<?php wp_nonce_field( self::NONCE_ACTION ); ?>
						<input type="hidden" name="action" value="<?php echo esc_attr( self::FORM_ACTION ); ?>" />
						<input type="hidden" name="kramar_status_action" value="add" />
						<?php $this->render_status_form_fields( [] ); ?>
						<div class="kramar-os-form-actions">
							<button type="button" class="button kramar-os-cancel-add"><?php esc_html_e( 'Cancel', 'kramar' ); ?></button>
							<button type="submit" class="button button-primary"><?php esc_html_e( 'Save Status', 'kramar' ); ?></button>
						</div>
					</form>
				</div>
			</div>

			<?php /* ── Status list ── */ ?>
			<?php if ( empty( $statuses ) ) : ?>
				<div class="kramar-os-empty">
					<p><?php esc_html_e( 'No custom order statuses yet.', 'kramar' ); ?></p>
					<button type="button" class="button button-primary kramar-os-add-btn"><?php esc_html_e( 'Add your first status', 'kramar' ); ?></button>
				</div>
			<?php else : ?>
				<div class="kramar-os-list" id="kramar-os-list">
					<?php foreach ( $statuses as $index => $status ) : ?>
						<?php
						$slug  = sanitize_key( $status['slug'] );
						$label = esc_html( $status['label'] );
						$bg    = sanitize_hex_color( $status['badge_color'] ?? '#4a90d9' ) ?? '#4a90d9';
						$fg    = sanitize_hex_color( $status['badge_text_color'] ?? '#ffffff' ) ?? '#ffffff';
						$count = $order_counts[ $slug ] ?? 0;

						$flags = [];
						if ( ! empty( $status['is_paid'] ) )           $flags[] = __( 'Counts as paid', 'kramar' );
						if ( ! empty( $status['is_editable'] ) )       $flags[] = __( 'Editable', 'kramar' );
						if ( ! empty( $status['grants_downloads'] ) )  $flags[] = __( 'Grants downloads', 'kramar' );
						if ( ! empty( $status['send_email'] ) )        $flags[] = __( 'Sends email', 'kramar' );
						?>
						<div class="kramar-os-card" id="kramar-os-card-<?php echo esc_attr( $slug ); ?>">
							<div class="kramar-os-card__row">
								<div class="kramar-os-card__info">
									<strong><?php echo $label; /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $label is esc_html()'d at assignment */ ?></strong>
									<span class="kramar-os-card__slug"><code>wc-<?php echo esc_html( $slug ); ?></code></span>
									<?php if ( strlen( $slug ) > self::MAX_SLUG_LENGTH ) : ?>
										<span class="kramar-os-flag-pill kramar-os-flag-pill--error"><?php esc_html_e( 'Slug too long', 'kramar' ); ?></span>
									<?php endif; ?>
									<span class="kramar-cs-badge" style="background:<?php echo esc_attr( $bg ); ?>;color:<?php echo esc_attr( $fg ); ?>;"><?php echo $label; /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $label is esc_html()'d at assignment */ ?></span>
									<?php if ( ! empty( $flags ) ) : ?>
										<span class="kramar-os-card__flags">
											<?php foreach ( $flags as $flag ) : ?>
												<span class="kramar-os-flag-pill"><?php echo esc_html( $flag ); ?></span>
											<?php endforeach; ?>
										</span>
									<?php endif; ?>
								</div>
								<div class="kramar-os-card__meta">
									<?php if ( $count > 0 ) : ?>
										<?php /* translators: %d: number of orders */ ?>
								<span class="kramar-os-card__count"><?php echo esc_html( sprintf( _n( '%d order', '%d orders', $count, 'kramar' ), $count ) ); ?></span>
									<?php endif; ?>
									<?php if ( ! empty( $status['send_email'] ) ) : ?>
										<a href="<?php echo esc_url( admin_url( 'admin.php?page=kramar-email-builder&email_id=kramar_status_' . $slug ) ); ?>" class="button button-small"><?php esc_html_e( 'Edit Email', 'kramar' ); ?></a>
									<?php endif; ?>
									<button type="button" class="button button-small kramar-os-edit-btn" data-slug="<?php echo esc_attr( $slug ); ?>"><?php esc_html_e( 'Edit', 'kramar' ); ?></button>
									<form method="post" action="<?php echo esc_url( $form_url ); ?>" class="kramar-os-delete-form" style="display:inline;">
										<?php wp_nonce_field( self::NONCE_ACTION ); ?>
										<input type="hidden" name="action" value="<?php echo esc_attr( self::FORM_ACTION ); ?>" />
										<input type="hidden" name="kramar_status_action" value="delete" />
										<input type="hidden" name="kramar_status_slug" value="<?php echo esc_attr( $slug ); ?>" />
										<button type="submit" class="kramar-cs-delete" data-count="<?php echo esc_attr( (string) $count ); ?>" data-label="<?php echo esc_attr( $label ); ?>"><span class="dashicons dashicons-trash"></span></button>
									</form>
								</div>
							</div>
							<?php /* ── Inline edit form (hidden by default) ── */ ?>
							<div class="kramar-os-edit-form-wrap" id="kramar-os-edit-<?php echo esc_attr( $slug ); ?>" style="display:none;">
								<form method="post" action="<?php echo esc_url( $form_url ); ?>">
									<?php wp_nonce_field( self::NONCE_ACTION ); ?>
									<input type="hidden" name="action" value="<?php echo esc_attr( self::FORM_ACTION ); ?>" />
									<input type="hidden" name="kramar_status_action" value="edit" />
									<input type="hidden" name="kramar_status_original_slug" value="<?php echo esc_attr( $slug ); ?>" />
									<?php $this->render_status_form_fields( $status ); ?>
									<div class="kramar-os-form-actions">
										<button type="button" class="button kramar-os-cancel-edit" data-slug="<?php echo esc_attr( $slug ); ?>"><?php esc_html_e( 'Cancel', 'kramar' ); ?></button>
										<button type="submit" class="button button-primary"><?php esc_html_e( 'Save Status', 'kramar' ); ?></button>
									</div>
								</form>
							</div>
						</div>
					<?php endforeach; ?>
				</div>
			<?php endif; ?>

			<?php /* ── Developer Reference ── */ ?>
			<div class="kramar-os-devref">
				<h2><?php esc_html_e( 'Developer Reference', 'kramar' ); ?></h2>

				<p class="kramar-os-devref__intro"><?php esc_html_e( 'Trigger a status change programmatically:', 'kramar' ); ?></p>
				<pre class="kramar-os-devref__code">$order->update_status( 'your-slug' );</pre>

				<p class="kramar-os-devref__intro"><?php esc_html_e( 'Hook into status transitions:', 'kramar' ); ?></p>
				<pre class="kramar-os-devref__code">add_action( 'woocommerce_order_status_your-slug',
    function( $order_id, $order ) { ... }, 10, 2 );</pre>

				<?php if ( ! empty( $registered_slugs ) ) : ?>
					<p class="kramar-os-devref__intro"><?php esc_html_e( 'Available custom statuses:', 'kramar' ); ?></p>
					<p class="kramar-os-devref__slugs">
						<?php foreach ( $registered_slugs as $rslug ) : ?>
							<code>wc-<?php echo esc_html( $rslug ); ?></code>
						<?php endforeach; ?>
					</p>
				<?php endif; ?>
			</div>

		</div>
		<?php
	}

	/**
	 * Render the shared add/edit form fields.
	 *
	 * @since 1.0.0
	 *
	 * @param array<string, mixed> $status Existing status data (empty array for add form).
	 */
	private function render_status_form_fields( array $status ): void {
		$is_new     = empty( $status );
		$slug       = sanitize_key( $status['slug'] ?? '' );
		$label      = esc_attr( $status['label'] ?? '' );
		$bg         = esc_attr( sanitize_hex_color( $status['badge_color'] ?? '#4a90d9' ) ?? '#4a90d9' );
		$fg         = esc_attr( sanitize_hex_color( $status['badge_text_color'] ?? '#ffffff' ) ?? '#ffffff' );
		$is_paid    = ! empty( $status['is_paid'] );
		$is_edit    = ! empty( $status['is_editable'] );
		$grants_dl  = ! empty( $status['grants_downloads'] );
		$send_email = ! empty( $status['send_email'] );
		// Default is_editable to true for new statuses.
		if ( empty( $status ) ) {
			$is_edit = true;
		}
		?>
		<div class="kramar-os-form-row">
			<div class="kramar-settings-field kramar-os-form__name">
				<label><?php esc_html_e( 'Name', 'kramar' ); ?></label>
				<input
					type="text"
					name="kramar_status_label"
					value="<?php echo $label; /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $label is esc_attr()'d at assignment */ ?>"
					placeholder="<?php esc_attr_e( 'e.g. Ready for Pickup, Packed, Awaiting Parts', 'kramar' ); ?>"
					required
				/>
			</div>
			<div class="kramar-settings-field kramar-os-form__slug">
				<label><?php esc_html_e( 'Slug', 'kramar' ); ?></label>
				<?php if ( $is_new ) : ?>
					<input
						type="text"
						name="kramar_status_slug"
						value=""
						class="kramar-os-slug-input"
						maxlength="<?php echo esc_attr( (string) self::MAX_SLUG_LENGTH ); ?>"
						placeholder="<?php esc_attr_e( 'auto from name', 'kramar' ); ?>"
					/>
					<span class="description kramar-os-slug-hint">
						<?php
						printf(
							/* translators: %d: maximum slug length in characters */
							esc_html__( 'Stored as wc-slug. Max %d characters — WooCommerce keeps order statuses in a 20-character column. Leave blank to build one from the name.', 'kramar' ),
							(int) self::MAX_SLUG_LENGTH
						);
						?>
					</span>
				<?php else : ?>
					<code class="kramar-os-slug-static">wc-<?php echo esc_html( $slug ); ?></code>
					<span class="description"><?php esc_html_e( 'Fixed after creation — changing it would orphan existing orders.', 'kramar' ); ?></span>
				<?php endif; ?>
			</div>
			<div class="kramar-settings-field kramar-os-form__color">
				<label><?php esc_html_e( 'Background', 'kramar' ); ?></label>
				<div class="kramar-cs-color">
					<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $bg is esc_attr()'d above ?>
					<input type="color" name="kramar_status_badge_color" value="<?php echo $bg; ?>" />
					<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $bg is esc_attr()'d above ?>
					<input type="text" value="<?php echo $bg; ?>" maxlength="7" class="kramar-cs-hex" />
				</div>
			</div>
			<div class="kramar-settings-field kramar-os-form__color">
				<label><?php esc_html_e( 'Text', 'kramar' ); ?></label>
				<div class="kramar-cs-color">
					<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $fg is esc_attr()'d above ?>
					<input type="color" name="kramar_status_badge_text_color" value="<?php echo $fg; ?>" />
					<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $fg is esc_attr()'d above ?>
					<input type="text" value="<?php echo $fg; ?>" maxlength="7" class="kramar-cs-hex" />
				</div>
			</div>
		</div>
		<div class="kramar-cs-form__flags">
			<label class="kramar-cs-flag">
				<input type="checkbox" name="kramar_status_is_paid" value="1" <?php checked( $is_paid ); ?> />
				<span>
					<strong><?php esc_html_e( 'Counts as paid', 'kramar' ); ?></strong>
					<?php esc_html_e( 'Reduces stock and marks the order as paid in reports', 'kramar' ); ?>
				</span>
			</label>
			<label class="kramar-cs-flag">
				<input type="checkbox" name="kramar_status_is_editable" value="1" <?php checked( $is_edit ); ?> />
				<span>
					<strong><?php esc_html_e( 'Editable', 'kramar' ); ?></strong>
					<?php esc_html_e( 'Shop manager can still edit the order', 'kramar' ); ?>
				</span>
			</label>
			<label class="kramar-cs-flag">
				<input type="checkbox" name="kramar_status_grants_downloads" value="1" <?php checked( $grants_dl ); ?> />
				<span>
					<strong><?php esc_html_e( 'Grants downloads', 'kramar' ); ?></strong>
					<?php esc_html_e( 'Customer gets access to downloadable files', 'kramar' ); ?>
				</span>
			</label>
			<label class="kramar-cs-flag">
				<input type="checkbox" name="kramar_status_send_email" value="1" <?php checked( $send_email ); ?> />
				<span>
					<strong><?php esc_html_e( 'Sends email', 'kramar' ); ?></strong>
					<?php esc_html_e( 'Auto-sends a notification to the customer. Delivered by the Email Manager module, where you can also customize it.', 'kramar' ); ?>
				</span>
			</label>
		</div>
		<?php
	}

	// -------------------------------------------------------------------------
	// Helpers
	// -------------------------------------------------------------------------

	/**
	 * Return the list of saved custom statuses from the database.
	 *
	 * @since 1.0.0
	 *
	 * @return array<int, array<string, mixed>> List of status arrays.
	 */
	private function get_statuses(): array {
		$statuses = get_option( self::STATUSES_OPTION, [] );
		return is_array( $statuses ) ? $statuses : [];
	}

	/**
	 * Whether the Email Manager module is running.
	 *
	 * Status notification emails are delivered by that module, so a status with
	 * "Sends email" checked is a no-op while it is off.
	 *
	 * @since 1.0.0
	 */
	private function email_manager_active(): bool {
		foreach ( $this->plugin->get_modules() as $module ) {
			if ( $module instanceof \Kramar\Modules\Email\Email_Manager ) {
				return $module->is_enabled() && $module->is_available();
			}
		}

		return false;
	}

	/**
	 * Return a map of order counts keyed by status slug.
	 *
	 * Uses wc_orders_count() which works with both CPT and HPOS.
	 *
	 * @since 1.0.0
	 *
	 * @param array<int, array<string, mixed>> $statuses List of status arrays.
	 * @return array<string, int> slug => count.
	 */
	public function render_extra_settings( string $option_name ): void {
		?>
		<div class="kramar-module__extra">
			<p>
				<a href="<?php echo esc_url( admin_url( 'admin.php?page=' . self::PAGE_SLUG ) ); ?>" class="button">
					<?php esc_html_e( 'Manage Order Statuses', 'kramar' ); ?> &rarr;
				</a>
			</p>
		</div>
		<?php
	}

	private function get_order_counts( array $statuses ): array {
		if ( empty( $statuses ) || ! function_exists( 'wc_orders_count' ) ) {
			return [];
		}

		// Only count statuses WooCommerce actually knows about. wc_orders_count()
		// indexes into its per-type count array without checking the key, so
		// asking it about an unregistered status — an over-length slug, or one
		// removed by another plugin — raises an "undefined array key" warning
		// rather than returning zero.
		$registered = wc_get_order_statuses();

		$counts = [];
		foreach ( $statuses as $status ) {
			$slug = sanitize_key( $status['slug'] );
			if ( '' === $slug || ! isset( $registered[ 'wc-' . $slug ] ) ) {
				continue;
			}
			$counts[ $slug ] = (int) wc_orders_count( 'wc-' . $slug );
		}

		return $counts;
	}
}
