<?php
/**
 * Custom Order Statuses — Register wc-confirmed & wc-dispatched.
 *
 * Extends WooCommerce with two custom order statuses for the
 * Hybrid Balanced COD workflow:
 *   pending → wc-confirmed → wc-dispatched → completed
 *
 * Also implements the Admin Override system that prevents
 * Fraud_Gating from overriding admin's explicit confirmation.
 *
 * @package CapiFlow
 */

namespace CapiFlow\Core;

defined( 'ABSPATH' ) || exit;

class Custom_Order_Statuses {

	/**
	 * Register all hooks.
	 */
	public function register_hooks(): void {
		// Register custom post statuses.
		add_action( 'init', array( $this, 'register_statuses' ), 9 );

		// Add to WooCommerce order status dropdown.
		add_filter( 'wc_order_statuses', array( $this, 'add_order_statuses' ) );

		// Add bulk actions for custom statuses.
		add_filter( 'bulk_actions-edit-shop_order', array( $this, 'add_bulk_actions' ) );
		add_filter( 'bulk_actions-woocommerce_page_wc-orders', array( $this, 'add_bulk_actions' ) );

		// ── Admin Override (two-phase): ──────────────────────────────────
		// WooCommerce hook order:
		//   1. woocommerce_order_status_{to}       ← Purchase_Controller P10
		//   2. woocommerce_order_status_{from}_to_{to}
		//   3. woocommerce_order_status_changed
		//
		// Phase 1: Set override FLAG on the SAME hook as Purchase_Controller,
		//          but at lower priority (P1 < P10) so it runs first.
		// Phase 2: Add audit NOTE on woocommerce_order_status_changed (P5)
		//          which provides from_status for detailed logging.
		add_action( 'woocommerce_order_status_confirmed', array( $this, 'set_admin_override_flag' ), 1, 2 );
		add_action( 'woocommerce_order_status_processing', array( $this, 'set_admin_override_flag' ), 1, 2 );
		add_action( 'woocommerce_order_status_changed', array( $this, 'add_admin_override_audit' ), 5, 4 );

		// Status badge styling in admin order list.
		add_action( 'admin_enqueue_scripts', array( $this, 'admin_status_styles' ) );

		// Email notifications for custom statuses.
		add_filter( 'woocommerce_email_actions', array( $this, 'add_email_actions' ) );
	}

	/**
	 * Register custom post statuses for orders.
	 */
	public function register_statuses(): void {
		register_post_status(
			'wc-confirmed',
			array(
				'label'                     => _x( 'Confirmed', 'Order status', 'capiflow' ),
				'public'                    => true,
				'exclude_from_search'       => false,
				'show_in_admin_all_list'    => true,
				'show_in_admin_status_list' => true,
				/* translators: %s: number of orders */
				'label_count'               => _n_noop(
					'Confirmed <span class="count">(%s)</span>',
					'Confirmed <span class="count">(%s)</span>',
					'capiflow'
				),
			)
		);

		register_post_status(
			'wc-dispatched',
			array(
				'label'                     => _x( 'Dispatched', 'Order status', 'capiflow' ),
				'public'                    => true,
				'exclude_from_search'       => false,
				'show_in_admin_all_list'    => true,
				'show_in_admin_status_list' => true,
				/* translators: %s: number of orders */
				'label_count'               => _n_noop(
					'Dispatched <span class="count">(%s)</span>',
					'Dispatched <span class="count">(%s)</span>',
					'capiflow'
				),
			)
		);
	}

	/**
	 * Add custom statuses to WooCommerce order status dropdown.
	 *
	 * @param array $order_statuses Existing statuses.
	 * @return array Modified statuses.
	 */
	public function add_order_statuses( array $order_statuses ): array {
		$new_statuses = array();

		foreach ( $order_statuses as $key => $label ) {
			$new_statuses[ $key ] = $label;

			// Insert 'Confirmed' after 'Pending payment'.
			if ( 'wc-pending' === $key ) {
				$new_statuses['wc-confirmed'] = _x( 'Confirmed', 'Order status', 'capiflow' );
			}

			// Insert 'Dispatched' after 'Processing' (or after Confirmed if Processing exists).
			if ( 'wc-processing' === $key ) {
				$new_statuses['wc-dispatched'] = _x( 'Dispatched', 'Order status', 'capiflow' );
			}
		}

		// If 'Dispatched' wasn't inserted (no processing key), add at end before completed.
		if ( ! isset( $new_statuses['wc-dispatched'] ) ) {
			$new_statuses['wc-dispatched'] = _x( 'Dispatched', 'Order status', 'capiflow' );
		}

		return $new_statuses;
	}

	/**
	 * Add bulk actions for custom statuses.
	 *
	 * @param array $bulk_actions Existing bulk actions.
	 * @return array Modified bulk actions.
	 */
	public function add_bulk_actions( array $bulk_actions ): array {
		$bulk_actions['mark_confirmed']  = __( 'Change status to Confirmed', 'capiflow' );
		$bulk_actions['mark_dispatched'] = __( 'Change status to Dispatched', 'capiflow' );
		return $bulk_actions;
	}

	/**
	 * Phase 1: Set admin override FLAG before Purchase_Controller runs.
	 *
	 * Hooked on woocommerce_order_status_confirmed at priority 1.
	 * Purchase_Controller hooks the same event at priority 10.
	 *
	 * WooCommerce fires woocommerce_order_status_{to} BEFORE
	 * woocommerce_order_status_changed, so hooking here at P1
	 * guarantees the flag is set before Purchase_Controller (P10).
	 *
	 * @param int       $order_id Order ID.
	 * @param \WC_Order $order    Order object.
	 */
	public function set_admin_override_flag( int $order_id, $order ): void {
		// Only if this is an admin action (not cron, not auto-confirm, not webhook).
		if ( ! is_admin() || wp_doing_cron() ) {
			return;
		}

		// Only if a real admin user is performing this action.
		$user_id = get_current_user_id();
		if ( ! $user_id || ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}

		// Only if order was previously gated by our fraud system.
		// Prevents unnecessary overrides on fresh, non-gated orders.
		$fraud_action = $order->get_meta( '_capiflow_fraud_action', true );
		if ( empty( $fraud_action ) || 'accepted' === $fraud_action ) {
			return;
		}

		// Set override flag — Purchase_Controller (P10) reads this.
		$order->update_meta_data( '_capiflow_admin_override', $user_id );
		$order->update_meta_data( '_capiflow_admin_override_at', current_time( 'mysql', true ) );

		// Clear stale Purchase lock so CAPI can fire on this status transition.
		// The lock may have been set by a previous gated attempt.
		$order->delete_meta_data( '_capiflow_purchase_sent' );

		$order->save_meta_data();
	}

	/**
	 * Phase 2: Add audit trail note with from_status detail.
	 *
	 * Hooked on woocommerce_order_status_changed at priority 5.
	 * This fires AFTER Phase 1, so the flag is already set.
	 *
	 * @param int       $order_id    Order ID.
	 * @param string    $from_status Previous status (without wc- prefix).
	 * @param string    $to_status   New status (without wc- prefix).
	 * @param \WC_Order $order       Order object.
	 */
	public function add_admin_override_audit( int $order_id, string $from_status, string $to_status, $order ): void {
		// Only for transitions TO confirmed or processing (admin override targets).
		if ( ! in_array( $to_status, array( 'confirmed', 'processing' ), true ) ) {
			return;
		}

		// Only for admin override (flag set in Phase 1).
		$admin_override = $order->get_meta( '_capiflow_admin_override', true );
		if ( empty( $admin_override ) ) {
			return;
		}

		// Save from_status for audit.
		$order->update_meta_data( '_capiflow_admin_override_from', $from_status );
		$order->save_meta_data();

		// Audit trail: order note.
		$user       = get_userdata( (int) $admin_override );
		$user_label = $user ? $user->display_name . ' (' . $user->user_login . ')' : 'User #' . $admin_override;

		$order->add_order_note(
			sprintf(
				/* translators: 1: admin name, 2: previous status */
				__( '✅ Manually confirmed by %1$s (from: %2$s). Fraud gate bypassed.', 'capiflow' ),
				$user_label,
				$from_status
			),
			false, // Not a customer note.
			false
		);
	}

	/**
	 * Output CSS for custom status badges in WooCommerce admin order list.
	 *
	 * WooCommerce uses mark.order-status.status-{status} for badge styling.
	 * Without this, custom statuses show as plain gray badges.
	 *
	 * Uses wp_add_inline_style() attached to WooCommerce's admin stylesheet
	 * for WordPress.org compliance (no raw <style> output).
	 */
	public function admin_status_styles(): void {
		$screen = get_current_screen();
		if ( ! $screen ) {
			return;
		}

		// Only on order list pages (legacy + HPOS).
		$order_screens = array( 'edit-shop_order', 'woocommerce_page_wc-orders' );
		if ( ! in_array( $screen->id, $order_screens, true ) ) {
			return;
		}

		$css = '
			/* Confirmed — green badge */
			mark.order-status.status-confirmed,
			mark.order-status.status-wc-confirmed {
				background: #c6e1c6;
				color: #5b841b;
			}
			mark.order-status.status-confirmed::after,
			mark.order-status.status-wc-confirmed::after {
				content: "\e015";
				font-family: WooCommerce;
			}

			/* Dispatched — blue badge */
			mark.order-status.status-dispatched,
			mark.order-status.status-wc-dispatched {
				background: #c8d7e1;
				color: #2e4453;
			}
			mark.order-status.status-dispatched::after,
			mark.order-status.status-wc-dispatched::after {
				content: "\e019";
				font-family: WooCommerce;
			}
		';

		wp_add_inline_style( 'woocommerce_admin_styles', $css );
	}

	/**
	 * Register custom status transitions as WooCommerce email actions.
	 *
	 * This allows WooCommerce to trigger email notifications when orders
	 * transition to/from custom statuses.
	 *
	 * @param array $actions Existing email actions.
	 * @return array Modified actions.
	 */
	public function add_email_actions( array $actions ): array {
		$actions[] = 'woocommerce_order_status_pending_to_confirmed';
		$actions[] = 'woocommerce_order_status_on-hold_to_confirmed';
		$actions[] = 'woocommerce_order_status_confirmed_to_dispatched';
		return $actions;
	}
}
