<?php
/**
 * Unified Vehicle Data meta box with vertical (left-side) tabs.
 *
 * Combines Details, Specifications, Classification, Custom Fields, Gallery,
 * and Video into a single organized meta box on the vehicle edit screen.
 *
 * Per QUALITY-IMPROVEMENT-PLAN.md §T2-2 the per-section render + save logic
 * lives under `Admin/MetaBoxes/Sections/`. This class only orchestrates:
 *  - Which sections render in which order.
 *  - The meta box registration + nonce + dispatch to per-section save().
 *  - Suppression of WP's default sidebar taxonomy boxes (those are now in
 *    the Classification tab).
 *
 * @package ThemeREX\AutoDealer
 */

declare(strict_types=1);

namespace ThemeREX\AutoDealer\Admin;

defined( 'ABSPATH' ) || exit;

use ThemeREX\AutoDealer\Admin\MetaBoxes\AbstractVehicleDataSection;
use ThemeREX\AutoDealer\Admin\MetaBoxes\Sections\ClassificationSection;
use ThemeREX\AutoDealer\Admin\MetaBoxes\Sections\CustomFieldsSection;
use ThemeREX\AutoDealer\Admin\MetaBoxes\Sections\DetailsSection;
use ThemeREX\AutoDealer\Admin\MetaBoxes\Sections\GallerySection;
use ThemeREX\AutoDealer\Admin\MetaBoxes\Sections\SpecificationsSection;
use ThemeREX\AutoDealer\Admin\MetaBoxes\Sections\VideoSection;
use ThemeREX\AutoDealer\PostTypes\VehiclePostType;
use ThemeREX\AutoDealer\Taxonomies\UserTaxonomyManager;

class VehicleDataMetaBox {

	/**
	 * Section companions extracted per QUALITY-IMPROVEMENT-PLAN.md §T2-2.
	 *
	 * Order is render order. The `details` section reads `$rehookGuard` so its
	 * recursive `wp_update_post()` (writes post_content) doesn't re-enter this
	 * class's save_post handler.
	 *
	 * @var array<string, AbstractVehicleDataSection>
	 */
	private array $sections = array();

	private CustomFieldsSection $customFieldsSection;

	public function __construct() {
		$detailsSection            = new DetailsSection( array( $this, 'withSaveUnhooked' ) );
		$this->customFieldsSection = new CustomFieldsSection();

		$this->sections = array(
			'details'        => $detailsSection,
			'specifications' => new SpecificationsSection(),
			'classification' => new ClassificationSection(),
			'custom_fields'  => $this->customFieldsSection,
			'gallery'        => new GallerySection(),
			'video'          => new VideoSection(),
		);
	}

	/**
	 * Per-tab metadata used by the renderer: icon + translated label.
	 *
	 * Built on demand (not in the constructor) because this class is
	 * instantiated on `plugins_loaded`, before the text domain is loaded on
	 * `init`. Calling `__()` at construction time triggers WordPress 6.7's
	 * "translation loading triggered too early" notice. All callers run at
	 * render time (well after `init`), so deferring is safe.
	 *
	 * @return array<string, array{icon:string, label:string}>
	 */
	private function tabMeta(): array {
		return array(
			'details'        => array(
				'icon'  => 'dashicons-edit-page',
				'label' => __( 'Details', 'trx-auto-dealer' ),
			),
			'specifications' => array(
				'icon'  => 'dashicons-clipboard',
				'label' => __( 'Specifications', 'trx-auto-dealer' ),
			),
			'classification' => array(
				'icon'  => 'dashicons-tag',
				'label' => __( 'Classification', 'trx-auto-dealer' ),
			),
			'custom_fields'  => array(
				'icon'  => 'dashicons-admin-generic',
				'label' => __( 'Custom Fields', 'trx-auto-dealer' ),
			),
			'gallery'        => array(
				'icon'  => 'dashicons-format-gallery',
				'label' => __( 'Gallery', 'trx-auto-dealer' ),
			),
			'video'          => array(
				'icon'  => 'dashicons-video-alt3',
				'label' => __( 'Video', 'trx-auto-dealer' ),
			),
		);
	}

	public function register(): void {
		add_action( 'add_meta_boxes_' . VehiclePostType::POST_TYPE, array( $this, 'addMetaBox' ) );
		add_action( 'add_meta_boxes_' . VehiclePostType::POST_TYPE, array( $this, 'removeDefaultMetaBoxes' ), 99 );
		add_action( 'save_post_' . VehiclePostType::POST_TYPE, array( $this, 'save' ), 12 );
	}

	public function addMetaBox(): void {
		add_meta_box(
			'trx_ad_vehicle_data',
			__( 'Vehicle Data', 'trx-auto-dealer' ),
			array( $this, 'render' ),
			VehiclePostType::POST_TYPE,
			'normal',
			'high'
		);
	}

	/**
	 * Remove default WP sidebar taxonomy meta boxes — Classification tab
	 * is the canonical place to edit them now.
	 */
	public function removeDefaultMetaBoxes(): void {
		$allSlugs = array_merge(
			ClassificationSection::DISPLAY_ORDER,
			UserTaxonomyManager::getSlugs()
		);

		foreach ( $allSlugs as $slug ) {
			if ( UserTaxonomyManager::isDisabled( $slug ) ) {
				continue;
			}

			$taxonomy = get_taxonomy( $slug );
			if ( ! $taxonomy instanceof \WP_Taxonomy ) {
				continue;
			}

			if ( $taxonomy->hierarchical ) {
				remove_meta_box( $slug . 'div', VehiclePostType::POST_TYPE, 'side' );
			} else {
				remove_meta_box( 'tagsdiv-' . $slug, VehiclePostType::POST_TYPE, 'side' );
			}
		}
	}

	public function render( \WP_Post $post ): void {
		wp_nonce_field( 'trx_ad_vehicle_data_save', '_trx_ad_vehicle_data_nonce' );

		$tabs = $this->buildTabs( $post );

		?>
		<div class="trx-ad-vdata">
			<nav class="trx-ad-vdata-nav">
				<?php $first = true; ?>
				<?php foreach ( $tabs as $key => $tab ) : ?>
					<a href="#"
						class="trx-ad-vdata-tab<?php echo $first ? ' trx-ad-vdata-tab--active' : ''; ?>"
						data-tab="<?php echo esc_attr( $key ); ?>">
						<span class="dashicons <?php echo esc_attr( $tab['icon'] ); ?>"></span>
						<span class="trx-ad-vdata-tab-label"><?php echo esc_html( $tab['label'] ); ?></span>
						<?php if ( ! empty( $tab['badge'] ) ) : ?>
							<span class="trx-ad-vdata-badge"><?php echo (int) $tab['badge']; ?></span>
						<?php endif; ?>
					</a>
					<?php $first = false; ?>
				<?php endforeach; ?>
			</nav>

			<div class="trx-ad-vdata-content">
				<?php $firstTab = array_key_first( $tabs ); ?>
				<?php foreach ( $tabs as $key => $tab ) : ?>
					<?php
					if ( ! isset( $this->sections[ $key ] ) ) {
						continue; }
					?>
					<div class="trx-ad-vdata-panel<?php echo $key === $firstTab ? ' trx-ad-vdata-panel--active' : ''; ?>" data-panel="<?php echo esc_attr( $key ); ?>">
						<?php if ( 'specifications' === $key ) : ?>
							<input type="hidden" name="_trx_ad_specs_panel" value="1" />
						<?php endif; ?>
						<?php $this->sections[ $key ]->render( $post ); ?>
					</div>
				<?php endforeach; ?>
			</div>
		</div>
		<?php
	}

	/**
	 * Compose the visible tab list: omit `custom_fields` when none configured,
	 * compute Gallery + Video badges, then pass through the
	 * `trx_ad_vehicle_data_tabs` filter for extension.
	 *
	 * @return array<string, array{icon:string, label:string, badge:int}>
	 */
	private function buildTabs( \WP_Post $post ): array {
		$tabs = array();
		foreach ( $this->tabMeta() as $key => $meta ) {
			if ( 'custom_fields' === $key && ! $this->customFieldsSection->hasFields() ) {
				continue;
			}
			$tabs[ $key ] = array(
				'icon'  => $meta['icon'],
				'label' => $meta['label'],
				'badge' => 0,
			);
		}

		// Dynamic badges.
		if ( isset( $tabs['gallery'] ) ) {
			$tabs['gallery']['badge'] = count( VehicleMediaMetaBox::getGalleryIds( $post->ID ) );
		}
		if ( isset( $tabs['video'] ) ) {
			$tabs['video']['badge'] = count( VehicleMediaMetaBox::getSelfVideos( $post->ID ) )
				+ count( VehicleMediaMetaBox::getExternalVideos( $post->ID ) );
		}

		/**
		 * Filter the tabs displayed in the Vehicle Data meta box.
		 *
		 * @param array<string, array{icon:string, label:string, badge:int}> $tabs Tab definitions.
		 * @param \WP_Post $post Current post.
		 */
		return (array) apply_filters( 'trx_ad_vehicle_data_tabs', $tabs, $post );
	}

	public function save( int $postId ): void {
		if (
			! isset( $_POST['_trx_ad_vehicle_data_nonce'] )
			|| ! wp_verify_nonce(
				sanitize_text_field( wp_unslash( $_POST['_trx_ad_vehicle_data_nonce'] ) ),
				'trx_ad_vehicle_data_save'
			)
		) {
			return;
		}

		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}

		if ( ! current_user_can( 'edit_post', $postId ) ) {
			return;
		}

		foreach ( $this->sections as $section ) {
			$section->save( $postId );
		}
	}

	/**
	 * Run `$inner` with this class's save_post hook temporarily detached.
	 * Used by `DetailsSection::save()` when it calls `wp_update_post()` to
	 * write post_content — that call would otherwise re-trigger this same
	 * save handler and recurse. Same priority + same callable args required
	 * for the unhook+rehook pair.
	 */
	public function withSaveUnhooked( callable $inner ): void {
		$hook = 'save_post_' . VehiclePostType::POST_TYPE;
		remove_action( $hook, array( $this, 'save' ), 12 );
		$inner();
		add_action( $hook, array( $this, 'save' ), 12 );
	}
}
