<?php
/**
 * Base class for Vehicle Data meta box sections.
 *
 * Each concrete section (Details, Specifications, Classification, Gallery,
 * Video, CustomFields) lives under `Admin/MetaBoxes/Sections/` and owns its
 * own render + save lifecycle. The orchestrator `VehicleDataMetaBox` calls
 * `render($post)` while drawing the panel and `save($postId)` from the
 * `save_post_{cpt}` hook.
 *
 * @package ThemeREX\AutoDealer\Admin\MetaBoxes
 */

declare(strict_types=1);

namespace ThemeREX\AutoDealer\Admin\MetaBoxes;

defined( 'ABSPATH' ) || exit;

use ThemeREX\AutoDealer\Database\VehicleSpecsSync;

abstract class AbstractVehicleDataSection {

	/**
	 * Per-request cache of specs rows, keyed by post ID, so a panel with many
	 * fields resolves the fallback with a single DB read.
	 *
	 * @var array<int, array<string,mixed>|null>
	 */
	private static array $specsRowCache = array();

	/**
	 * Stable section key. Used as the tab/panel data attribute in the UI
	 * and (where present) as the hidden submission marker so `save()` can
	 * distinguish a real form post from REST/Gutenberg/autosave traffic.
	 */
	abstract public function getKey(): string;

	abstract public function render( \WP_Post $post ): void;

	abstract public function save( int $postId ): void;

	/**
	 * Read a field value for the edit form, falling back to the denormalized
	 * specs table when the post meta is empty.
	 *
	 * Standard fields live in post meta and sync to `wp_trx_ad_vehicle_specs`
	 * via `save_post`. Listings written specs-first (seed scripts, direct DB
	 * writes) have no post meta, which left the editor blank and risked
	 * overwriting the specs row with empties on the next save. Falling back to
	 * the specs column keeps the editor consistent with the list table,
	 * frontend, and feeds. Mirrors the resolver in `Admin\ListTable\Columns`.
	 *
	 * @param int    $postId  Listing post ID.
	 * @param string $metaKey Post-meta key, with the `_trx_ad_` prefix.
	 * @return string Resolved value, or '' when neither source has one.
	 */
	protected function metaOrSpec( int $postId, string $metaKey ): string {
		$meta = get_post_meta( $postId, $metaKey, true );
		if ( '' !== (string) $meta && null !== $meta && false !== $meta ) {
			return (string) $meta;
		}

		$column = VehicleSpecsSync::columnForMeta( $metaKey );
		if ( null === $column ) {
			return '';
		}

		if ( ! array_key_exists( $postId, self::$specsRowCache ) ) {
			self::$specsRowCache[ $postId ] = VehicleSpecsSync::get( $postId );
		}
		$row = self::$specsRowCache[ $postId ];

		if ( is_array( $row ) && isset( $row[ $column ] ) && '' !== (string) $row[ $column ] && null !== $row[ $column ] ) {
			return (string) $row[ $column ];
		}

		return '';
	}
}
