<?php
/**
 * Builds the `Car` / `Vehicle` / `Motorcycle` schema piece for a vehicle.
 *
 * @package ThemeREX\AutoDealer
 */

declare(strict_types=1);

namespace ThemeREX\AutoDealer\Integrations\Schema;

use ThemeREX\AutoDealer\PostTypes\VehiclePostType;
use function ThemeREX\AutoDealer\getSettings;
use function ThemeREX\AutoDealer\getVehicleSpecs;

class CarSchema {

	/**
	 * Build the JSON-LD piece. Returns `[]` for non-vehicle posts so the
	 * orchestrator can skip empty pieces.
	 *
	 * @return array<string, mixed>
	 */
	public function buildPiece( int $postId ): array {
		if ( $postId <= 0 || VehiclePostType::POST_TYPE !== get_post_type( $postId ) ) {
			return array();
		}

		$specs = getVehicleSpecs( $postId );
		if ( ! is_array( $specs ) ) {
			$specs = array();
		}

		$permalink = (string) get_permalink( $postId );
		$piece     = array(
			'@type' => SchemaGenerator::vehicleTypeFor( $postId ),
			'@id'   => $permalink . '#car',
			'name'  => (string) get_the_title( $postId ),
			'url'   => $permalink,
		);

		$thumb = get_the_post_thumbnail_url( $postId, 'large' );
		if ( $thumb ) {
			$piece['image'] = $thumb;
		}

		// Description: post excerpt > full content (stripped) > nothing.
		$desc = trim( (string) get_the_excerpt( $postId ) );
		if ( '' === $desc ) {
			$content = get_post_field( 'post_content', $postId );
			$desc    = is_string( $content ) ? trim( wp_strip_all_tags( $content ) ) : '';
		}
		if ( '' !== $desc ) {
			$piece['description'] = $desc;
		}

		// Identification.
		if ( ! empty( $specs['vin'] ) ) {
			$piece['vehicleIdentificationNumber'] = (string) $specs['vin'];
		}
		if ( ! empty( $specs['stock_number'] ) ) {
			$piece['sku'] = (string) $specs['stock_number'];
		}
		if ( ! empty( $specs['year'] ) ) {
			$piece['modelDate']        = (int) $specs['year'];
			$piece['productionDate']   = (string) (int) $specs['year'];
			$piece['vehicleModelDate'] = (string) (int) $specs['year'];
		}

		// Make/model — taxonomy term names beat the (legacy) string columns.
		$make_name = $this->firstTermName( $postId, 'trx_ad_make' )
			?: ( ! empty( $specs['make'] ) ? ucwords( (string) $specs['make'] ) : '' );
		if ( '' !== $make_name ) {
			$piece['manufacturer'] = array(
				'@type' => 'Organization',
				'name'  => $make_name,
			);
			$piece['brand']        = $make_name;
		}
		$model_name = $this->firstTermName( $postId, 'trx_ad_model' )
			?: ( ! empty( $specs['model'] ) ? ucwords( (string) $specs['model'] ) : '' );
		if ( '' !== $model_name ) {
			$piece['model'] = $model_name;
		}

		// Body style → vehicleConfiguration.
		$body = $this->firstTermName( $postId, 'trx_ad_body_style' );
		if ( '' === $body && ! empty( $specs['body_style'] ) ) {
			$body = ucwords( (string) $specs['body_style'] );
		}
		if ( '' !== $body ) {
			$piece['vehicleConfiguration'] = $body;
			$piece['bodyType']             = $body;
		}

		// Fuel / transmission / drivetrain.
		$fuel = $this->firstTermName( $postId, 'trx_ad_fuel_type' )
			?: ( ! empty( $specs['fuel_type'] ) ? ucwords( (string) $specs['fuel_type'] ) : '' );
		if ( '' !== $fuel ) {
			$piece['fuelType'] = $fuel;
		}
		$trans = $this->firstTermName( $postId, 'trx_ad_transmission' )
			?: ( ! empty( $specs['transmission'] ) ? ucwords( (string) $specs['transmission'] ) : '' );
		if ( '' !== $trans ) {
			$piece['vehicleTransmission'] = $trans;
		}
		$drive = $this->firstTermName( $postId, 'trx_ad_drivetrain' )
			?: ( ! empty( $specs['drivetrain'] ) ? strtoupper( (string) $specs['drivetrain'] ) : '' );
		if ( '' !== $drive ) {
			$piece['driveWheelConfiguration'] = $drive;
		}

		// Color (exterior preferred).
		if ( ! empty( $specs['color_ext'] ) ) {
			$piece['color'] = ucwords( (string) $specs['color_ext'] );
		} elseif ( ! empty( $specs['color_int'] ) ) {
			$piece['color'] = ucwords( (string) $specs['color_int'] );
		}

		// Capacities.
		if ( ! empty( $specs['doors'] ) ) {
			$piece['numberOfDoors'] = (int) $specs['doors'];
		}
		if ( ! empty( $specs['seats'] ) ) {
			$piece['seatingCapacity']        = (int) $specs['seats'];
			$piece['vehicleSeatingCapacity'] = (int) $specs['seats'];
		}

		// Mileage.
		if ( isset( $specs['mileage'] ) && is_numeric( $specs['mileage'] ) ) {
			$mileage_unit                 = strtolower( (string) getSettings( 'distance_unit', 'km' ) );
			$piece['mileageFromOdometer'] = array(
				'@type'    => 'QuantitativeValue',
				'value'    => (float) $specs['mileage'],
				'unitCode' => 'mi' === $mileage_unit ? 'SMI' : 'KMT',
			);
		}

		// Engine.
		$engine = trim( (string) ( $specs['engine'] ?? '' ) );
		if ( '' !== $engine || ! empty( $specs['horsepower'] ) || ! empty( $specs['torque'] ) ) {
			$engine_node = array( '@type' => 'EngineSpecification' );
			if ( '' !== $engine ) {
				$engine_node['name'] = $engine;
			}
			if ( ! empty( $specs['horsepower'] ) ) {
				$engine_node['enginePower'] = array(
					'@type'    => 'QuantitativeValue',
					'value'    => (float) $specs['horsepower'],
					'unitCode' => 'BHP',
				);
			}
			if ( ! empty( $specs['torque'] ) ) {
				$engine_node['torque'] = array(
					'@type'    => 'QuantitativeValue',
					'value'    => (float) $specs['torque'],
					'unitCode' => 'NU', // Newton metres.
				);
			}
			$piece['vehicleEngine'] = $engine_node;
		}

		// EV-specific.
		if ( ! empty( $specs['battery_capacity'] ) ) {
			$piece['emissionsCO2'] = 0; // EV. Will be overridden below if explicit value present.
		}
		if ( isset( $specs['co2_emissions'] ) && '' !== $specs['co2_emissions'] && is_numeric( $specs['co2_emissions'] ) ) {
			$piece['emissionsCO2'] = (float) $specs['co2_emissions'];
		}

		// Fuel economy.
		if ( ! empty( $specs['mpg_combined'] ) ) {
			$piece['fuelEfficiency'] = array(
				'@type'    => 'QuantitativeValue',
				'value'    => (float) $specs['mpg_combined'],
				'unitCode' => 'M40', // Miles per gallon (US). Schema.org accepts plain unit text too.
			);
		}

		// Condition: new/used → schema.org enums.
		$condition = $this->firstTermName( $postId, 'trx_ad_condition' )
			?: ( ! empty( $specs['condition_type'] ) ? (string) $specs['condition_type'] : '' );
		if ( '' !== $condition ) {
			$cond_lower = strtolower( $condition );
			$map        = array(
				'new'         => 'https://schema.org/NewCondition',
				'used'        => 'https://schema.org/UsedCondition',
				'certified'   => 'https://schema.org/UsedCondition',
				'cpo'         => 'https://schema.org/UsedCondition',
				'damaged'     => 'https://schema.org/DamagedCondition',
				'refurbished' => 'https://schema.org/RefurbishedCondition',
			);
			if ( isset( $map[ $cond_lower ] ) ) {
				$piece['itemCondition'] = $map[ $cond_lower ];
			}
		}

		// Features (taxonomy → array of strings).
		$features = wp_get_post_terms( $postId, 'trx_ad_feature', array( 'fields' => 'names' ) );
		if ( ! is_wp_error( $features ) && ! empty( $features ) ) {
			$piece['vehicleSpecialUsage'] = array_values( array_map( 'strval', $features ) );
		}

		// Link the offer (built by OfferSchema with the same permalink).
		$piece['offers'] = array( '@id' => $permalink . '#offer' );

		/**
		 * Filter the Car/Vehicle/Motorcycle JSON-LD piece before it's
		 * added to the graph.
		 *
		 * @param array $piece   The schema piece.
		 * @param int   $postId  Vehicle post ID.
		 * @param array $specs   Specs row.
		 */
		return (array) apply_filters( 'trx_ad_schema_car_piece', $piece, $postId, $specs );
	}

	private function firstTermName( int $postId, string $taxonomy ): string {
		$terms = wp_get_post_terms( $postId, $taxonomy, array( 'fields' => 'names' ) );
		if ( is_wp_error( $terms ) || empty( $terms ) ) {
			return '';
		}
		return (string) reset( $terms );
	}
}
