<?php
/**
 * WooCommerce Measurement Price Calculator
 *
 * This source file is subject to the GNU General Public License v3.0
 * that is bundled with this package in the file license.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.gnu.org/licenses/gpl-3.0.html
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@skyverge.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade WooCommerce Measurement Price Calculator to newer
 * versions in the future. If you wish to customize WooCommerce Measurement Price Calculator for your
 * needs please refer to http://docs.woocommerce.com/document/measurement-price-calculator/ for more information.
 *
 * @author    SkyVerge
 * @copyright Copyright (c) 2012-2026, SkyVerge, Inc. (info@skyverge.com)
 * @license   http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
 */

namespace SkyVerge\WooCommerce\Measurement_Price_Calculator\Measurements\Abilities;

use SkyVerge\WooCommerce\Measurement_Price_Calculator\Abilities\Provider;
use SkyVerge\WooCommerce\PluginFramework\v6_2_0\Abilities\Contracts\MakesAbilityContract;
use SkyVerge\WooCommerce\PluginFramework\v6_2_0\Abilities\DataObjects\Ability;
use SkyVerge\WooCommerce\PluginFramework\v6_2_0\Abilities\DataObjects\AbilityAnnotations;
use WC_Price_Calculator_Measurement;
use WP_Error;

defined( 'ABSPATH' ) or exit;

/**
 * Ability that converts a measurement value from one unit to another.
 *
 * @since 3.24.0
 */
class MeasurementConvert implements MakesAbilityContract {

	const NAME = 'woocommerce-measurement-price-calculator/measurements-convert';

	/** @inheritDoc */
	public function makeAbility() : Ability {
		return new Ability(
			static::NAME,
			__( 'Convert Measurement', 'woocommerce-measurement-price-calculator' ),
			__( 'Converts a measurement value from one unit to another.', 'woocommerce-measurement-price-calculator' ),
			Provider::MEASUREMENTS_CATEGORY_SLUG,
			function ( array $params ) {
				$compatibilityError = $this->validateUnitCompatibility( $params['from_unit'], $params['to_unit'] );

				if ( $compatibilityError ) {
					return $compatibilityError;
				}

				return [
					'value' => WC_Price_Calculator_Measurement::convert( $params['value'], $params['from_unit'], $params['to_unit'] ),
					'unit'  => $params['to_unit'],
				];
			},
			'__return_true',
			$this->getInputSchema(),
			$this->getOutputSchema(),
			new AbilityAnnotations( true, false, true ),
			true
		);
	}

	/**
	 * Validates that the source and target units belong to compatible measurement systems.
	 *
	 * The input schema's `enum` restricts values to known units, but cross-field compatibility
	 * (e.g. length → weight is not convertible) is not expressible in JSON Schema.
	 *
	 * @since 3.24.0
	 *
	 * @param string $fromUnit
	 * @param string $toUnit
	 * @return ?WP_Error
	 */
	protected function validateUnitCompatibility( string $fromUnit, string $toUnit ) : ?WP_Error {
		$fromStandard    = WC_Price_Calculator_Measurement::get_standard_unit( $fromUnit );
		$toStandard      = WC_Price_Calculator_Measurement::get_standard_unit( $toUnit );
		$conversionTable = WC_Price_Calculator_Measurement::get_conversion_table();

		if ( $fromStandard !== $toStandard && ! isset( $conversionTable[ $fromStandard ][ $toUnit ] ) ) {
			return new WP_Error(
				'incompatible_units',
				/* translators: 1: source unit, 2: target unit */
				sprintf( __( 'Units "%1$s" and "%2$s" are not compatible for conversion.', 'woocommerce-measurement-price-calculator' ), $fromUnit, $toUnit ),
				[ 'status' => 422 ]
			);
		}

		return null;
	}

	/**
	 * Gets the input schema for the ability.
	 *
	 * @since 3.24.0
	 *
	 * @return array<string, mixed>
	 */
	protected function getInputSchema() : array {
		$knownUnits = array_keys( WC_Price_Calculator_Measurement::get_normalize_table() );

		return [
			'type'                 => 'object',
			'required'             => [ 'value', 'from_unit', 'to_unit' ],
			'additionalProperties' => false,
			'properties'           => [
				'value'     => [
					'type'        => 'number',
					'description' => __( 'The measurement value to convert.', 'woocommerce-measurement-price-calculator' ),
				],
				'from_unit' => [
					'type'        => 'string',
					'enum'        => $knownUnits,
					'description' => __( 'The source unit (e.g. "ft", "sq m", "kg").', 'woocommerce-measurement-price-calculator' ),
				],
				'to_unit'   => [
					'type'        => 'string',
					'enum'        => $knownUnits,
					'description' => __( 'The target unit to convert to (e.g. "m", "sq. ft.", "lbs").', 'woocommerce-measurement-price-calculator' ),
				],
			],
		];
	}

	/**
	 * Gets the output schema for the ability.
	 *
	 * @since 3.24.0
	 *
	 * @return array<string, mixed>
	 */
	protected function getOutputSchema() : array {
		return [
			'type'       => 'object',
			'properties' => [
				'value' => [
					'type'        => 'number',
					'description' => __( 'The converted measurement value in the target unit.', 'woocommerce-measurement-price-calculator' ),
				],
				'unit'  => [
					'type'        => 'string',
					'description' => __( 'The target unit of the converted value.', 'woocommerce-measurement-price-calculator' ),
				],
			],
		];
	}
}
