<?php
/**
 * Block Bindings source — `trx-auto-dealer/vehicle-meta`.
 *
 * Lets editors bind native core blocks (Paragraph, Heading, Button, Image)
 * to vehicle data without needing a custom block. Example block markup:
 *
 *   <!-- wp:paragraph {
 *     "metadata":{"bindings":{
 *       "content":{"source":"trx-auto-dealer/vehicle-meta",
 *                  "args":{"key":"price"}}
 *     }}
 *   } -->
 *
 * Resolves the post the same way the rest of the suite does: an explicit
 * `postId` arg → the bindings runtime context (`$context->postId` /
 * `$block->context['postId']`) → the global post.
 *
 * Whitelisted keys are intentionally limited to formatted/display-friendly
 * fields. The `format=raw` arg returns the raw value instead of formatted.
 *
 * @package ThemeREX\AutoDealer
 * @version 1.0.0
 */

declare(strict_types=1);

namespace ThemeREX\AutoDealer\Blocks;

defined( 'ABSPATH' ) || exit;
use ThemeREX\AutoDealer\PostTypes\VehiclePostType;
use function ThemeREX\AutoDealer\formatPrice;
use function ThemeREX\AutoDealer\getSettings;
use function ThemeREX\AutoDealer\getVehicleSpecs;

final class BindingsSource {

	public const NAME = 'trx-auto-dealer/vehicle-meta';

	/**
	 * Keys exposed to the editor. Anything else returns `null`.
	 *
	 * Each value is a short label shown in the block-bindings UI.
	 *
	 * @var array<string, string>
	 */
	private const KEYS = array(
		'year'           => 'Year',
		'make'           => 'Make',
		'model'          => 'Model',
		'trim_level'     => 'Trim',
		'price'          => 'Price',
		'sale_price'     => 'Sale price',
		'mileage'        => 'Mileage',
		'fuel_type'      => 'Fuel type',
		'transmission'   => 'Transmission',
		'drivetrain'     => 'Drivetrain',
		'body_style'     => 'Body style',
		'condition_type' => 'Condition',
		'status'         => 'Status',
		'vin'            => 'VIN',
		'stock_number'   => 'Stock number',
		'horsepower'     => 'Horsepower',
		'engine'         => 'Engine',
		'color'          => 'Exterior colour',
	);

	public function register(): void {
		add_action( 'init', array( $this, 'registerSource' ) );
	}

	public function registerSource(): void {
		if ( ! function_exists( 'register_block_bindings_source' ) ) {
			return; // WP < 6.5
		}

		register_block_bindings_source(
			self::NAME,
			array(
				'label'              => __( 'Vehicle Meta', 'trx-auto-dealer' ),
				'get_value_callback' => array( $this, 'resolveValue' ),
				'uses_context'       => array( 'postId', 'postType' ),
			)
		);
	}

	/**
	 * Bindings-API callback.
	 *
	 * @param array<string, mixed> $args    Args from the binding markup
	 *                                      (`{"key":"price","format":"raw"}`).
	 * @param \WP_Block            $block   The block being rendered.
	 * @param string               $attr    The attribute name being bound
	 *                                      (e.g. `content`, `url`).
	 * @return string|null The resolved value, or null to skip binding.
	 */
	public function resolveValue( array $args, $block, string $attr ): ?string {
		$key = isset( $args['key'] ) ? (string) $args['key'] : '';
		if ( '' === $key || ! isset( self::KEYS[ $key ] ) ) {
			return null;
		}

		$post_id = isset( $args['postId'] ) ? (int) $args['postId'] : 0;
		if ( $post_id <= 0 && $block instanceof \WP_Block && isset( $block->context['postId'] ) ) {
			$post_id = (int) $block->context['postId'];
		}
		if ( $post_id <= 0 ) {
			$post_id = (int) get_the_ID();
		}
		if ( $post_id <= 0 || VehiclePostType::POST_TYPE !== get_post_type( $post_id ) ) {
			return null;
		}

		$specs = getVehicleSpecs( $post_id );
		if ( ! is_array( $specs ) || ! array_key_exists( $key, $specs ) ) {
			return null;
		}

		$raw    = $specs[ $key ];
		$format = isset( $args['format'] ) ? (string) $args['format'] : 'formatted';

		if ( 'raw' === $format ) {
			return null === $raw ? null : (string) $raw;
		}

		return $this->formatValue( $key, $raw );
	}

	/**
	 * Format a spec value for display.
	 *
	 * @param mixed $raw
	 */
	private function formatValue( string $key, $raw ): ?string {
		if ( null === $raw || '' === $raw ) {
			return null;
		}

		switch ( $key ) {
			case 'price':
			case 'sale_price':
				$value = (float) $raw;
				return $value > 0 ? formatPrice( $value, false ) : null;

			case 'mileage':
				$value = (int) $raw;
				$unit  = (string) getSettings( 'distance_unit', 'km' );
				return number_format( $value, 0, '.', ',' ) . ' ' . $unit;

			case 'horsepower':
				return (int) $raw . ' hp';

			case 'condition_type':
			case 'status':
			case 'fuel_type':
			case 'transmission':
			case 'drivetrain':
			case 'body_style':
				return ucwords( str_replace( array( '_', '-' ), ' ', (string) $raw ) );

			case 'year':
				return (string) (int) $raw;

			default:
				return (string) $raw;
		}
	}

	/**
	 * Public accessor — handy for tests + dynamic UI.
	 *
	 * @return array<string, string>
	 */
	public static function exposedKeys(): array {
		return self::KEYS;
	}
}
