<?php
/**
 * Canonical conversion item.
 *
 * @package Carticy\Conversions\Domain
 */

declare(strict_types=1);

namespace Carticy\Conversions\Domain;

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

/**
 * Provider-neutral item data used by purchase, refund, and renewal events.
 */
final class ConversionItem {

	/**
	 * Product or variation identifier.
	 *
	 * @var string
	 */
	private string $item_id;

	/**
	 * Item name.
	 *
	 * @var string
	 */
	private string $name;

	/**
	 * Quantity.
	 *
	 * @var int
	 */
	private int $quantity;

	/**
	 * Unit or refunded item price.
	 *
	 * @var Money
	 */
	private Money $price;

	/**
	 * SKU.
	 *
	 * @var string
	 */
	private string $sku;

	/**
	 * Category label.
	 *
	 * @var string
	 */
	private string $category;

	/**
	 * Variant label.
	 *
	 * @var string
	 */
	private string $variant;

	/**
	 * Constructor.
	 *
	 * @param string $item_id Product or variation identifier.
	 * @param string $name Item name.
	 * @param int    $quantity Quantity.
	 * @param Money  $price Unit or refunded item price.
	 * @param string $sku SKU.
	 * @param string $category Category label.
	 * @param string $variant Variant label.
	 *
	 * @throws \InvalidArgumentException When the item ID is empty or the quantity is not positive.
	 */
	public function __construct(
		string $item_id,
		string $name,
		int $quantity,
		Money $price,
		string $sku = '',
		string $category = '',
		string $variant = ''
	) {
		if ( '' === trim( $item_id ) ) {
			throw new \InvalidArgumentException( 'Item ID is required.' );
		}

		if ( $quantity <= 0 ) {
			throw new \InvalidArgumentException( 'Item quantity must be positive.' );
		}

		$this->item_id  = trim( $item_id );
		$this->name     = trim( $name );
		$this->quantity = $quantity;
		$this->price    = $price;
		$this->sku      = trim( $sku );
		$this->category = trim( $category );
		$this->variant  = trim( $variant );
	}

	/**
	 * Rebuild from serialized data.
	 *
	 * @param array<string, mixed> $data Serialized item.
	 * @return self
	 */
	public static function from_array( array $data ): self {
		return new self(
			(string) ( $data['item_id'] ?? '' ),
			(string) ( $data['name'] ?? '' ),
			isset( $data['quantity'] ) ? (int) $data['quantity'] : 1,
			Money::from_array( is_array( $data['price'] ?? null ) ? $data['price'] : array() ),
			(string) ( $data['sku'] ?? '' ),
			(string) ( $data['category'] ?? '' ),
			(string) ( $data['variant'] ?? '' )
		);
	}

	/**
	 * Serialize for storage.
	 *
	 * @return array<string, mixed>
	 */
	public function to_array(): array {
		return array(
			'item_id'  => $this->item_id,
			'name'     => $this->name,
			'quantity' => $this->quantity,
			'price'    => $this->price->to_array(),
			'sku'      => $this->sku,
			'category' => $this->category,
			'variant'  => $this->variant,
		);
	}
}
