<?php
/**
 * Order statuses.
 *
 * @package WPDudeProducts
 */

declare(strict_types=1);

namespace WPDude\Products\Orders;

/**
 * Order status constants and transitions.
 */
final class Statuses {

	public const PENDING  = 'pending';
	public const FAILED   = 'failed';
	public const EXPIRED  = 'expired';
	public const NEW      = 'new';
	public const SHIPPED  = 'shipped';
	public const RETURNED = 'returned';
	public const REFUNDED = 'refunded';

	/**
	 * @return list<string>
	 */
	public static function all(): array {
		return array(
			self::PENDING,
			self::FAILED,
			self::EXPIRED,
			self::NEW,
			self::SHIPPED,
			self::RETURNED,
			self::REFUNDED,
		);
	}

	/**
	 * Statuses an admin may set manually.
	 *
	 * @return list<string>
	 */
	public static function admin_actionable(): array {
		return array(
			self::NEW,
			self::SHIPPED,
			self::RETURNED,
			self::REFUNDED,
		);
	}

	/**
	 * Human-readable label for admin UI.
	 */
	public static function label( string $status ): string {
		$labels = array(
			self::PENDING  => __( 'Pending', 'dude-commerce' ),
			self::FAILED   => __( 'Failed', 'dude-commerce' ),
			self::EXPIRED  => __( 'Expired', 'dude-commerce' ),
			self::NEW      => __( 'New Order', 'dude-commerce' ),
			self::SHIPPED  => __( 'Shipped', 'dude-commerce' ),
			self::RETURNED => __( 'Returned', 'dude-commerce' ),
			self::REFUNDED => __( 'Refunded', 'dude-commerce' ),
		);

		return $labels[ $status ] ?? $status;
	}

	/**
	 * Colored status lozenge HTML for admin lists.
	 */
	public static function badge_html( string $status ): string {
		$status = sanitize_key( $status );
		$class  = 'wpdude-dc-status wpdude-dc-status--' . ( in_array( $status, self::all(), true ) ? $status : 'pending' );

		return sprintf(
			'<span class="%1$s">%2$s</span>',
			esc_attr( $class ),
			esc_html( self::badge_label( $status ) )
		);
	}

	/**
	 * Short label for status lozenges.
	 */
	public static function badge_label( string $status ): string {
		$labels = array(
			self::PENDING  => __( 'Pending', 'dude-commerce' ),
			self::FAILED   => __( 'Failed', 'dude-commerce' ),
			self::EXPIRED  => __( 'Expired', 'dude-commerce' ),
			self::NEW      => __( 'New Order', 'dude-commerce' ),
			self::SHIPPED  => __( 'Shipped', 'dude-commerce' ),
			self::RETURNED => __( 'Returned', 'dude-commerce' ),
			self::REFUNDED => __( 'Refunded', 'dude-commerce' ),
		);

		return $labels[ $status ] ?? self::label( $status );
	}

	/**
	 * Button label for an admin status action.
	 */
	public static function action_label( string $to ): string {
		if ( self::NEW === $to ) {
			return __( 'Revert to New Order', 'dude-commerce' );
		}
		if ( self::REFUNDED === $to ) {
			return __( 'Mark Refunded', 'dude-commerce' );
		}

		return sprintf(
			/* translators: %s: status label */
			__( 'Mark %s', 'dude-commerce' ),
			self::label( $to )
		);
	}

	/**
	 * Whether a status transition is allowed.
	 */
	public static function can_transition( string $from, string $to ): bool {
		if ( $from === $to ) {
			return false;
		}

		$map = array(
			self::PENDING  => array( self::NEW, self::FAILED, self::EXPIRED ),
			self::FAILED   => array(),
			self::EXPIRED  => array(),
			self::NEW      => array( self::SHIPPED, self::REFUNDED, self::RETURNED ),
			self::SHIPPED  => array( self::NEW, self::RETURNED, self::REFUNDED ),
			self::RETURNED => array( self::REFUNDED ),
			self::REFUNDED => array(),
		);

		return isset( $map[ $from ] ) && in_array( $to, $map[ $from ], true );
	}

	/**
	 * Allowed next statuses from a given status (admin-actionable only).
	 *
	 * @return list<string>
	 */
	public static function next_admin_statuses( string $from ): array {
		$next = array();
		foreach ( self::admin_actionable() as $to ) {
			if ( self::can_transition( $from, $to ) ) {
				$next[] = $to;
			}
		}
		return $next;
	}
}
