<?php
/**
 * Value handler for Toolset's toolset_connected_elements.group_id fields.
 *
 * @package Ealab\Deployer
 */

namespace EaLab\WP_Deployer\vendor\Ealab\Deployer\Tracking\ItemValueHandler\Compatibility\types;

use EaLab\WP_Deployer\vendor\Dakwamine\Component\RootDependencyDefinition;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Exception\WpDeployException;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Tracking\ItemValueHandler\ItemValueHandlerBase;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Tracking\SqlChangesTracker;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Tracking\TrackingManager;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Utility\Database;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Utility\Plugin;
use OTGS\Toolset\Common\Relationships\DatabaseLayer\DatabaseLayerFactory;

/**
 * Value handler for Toolset's toolset_connected_elements.group_id fields.
 */
class ToolsetGroupIdItemValueHandler extends ItemValueHandlerBase {
	/**
	 * The final value to set on import.
	 *
	 * @var int
	 */
	private int $group_id_to_set = 0;

	/**
	 * The tracking manager.
	 *
	 * @var \EaLab\WP_Deployer\vendor\Ealab\Deployer\Tracking\TrackingManager|null
	 */
	private ?TrackingManager $tracking_manager = null;

	/**
	 * {@inheritDoc}
	 */
	public function getDependencyDefinitions(): array {
		$definitions = parent::getDependencyDefinitions();

		$definitions[] = new RootDependencyDefinition( TrackingManager::class, $this->tracking_manager );

		return $definitions;
	}

	/**
	 * Generates a new ID.
	 *
	 * @return int The generated id.
	 */
	private function generateId(): int {
		$wpdb = Database::getDatabaseHandle();

		// Get the ID similarly to ConnectedElementPersistence:create_element_group_id().
		return 1 + (int) $wpdb->get_var( "SELECT MAX(group_id) FROM {$wpdb->prefix}toolset_connected_elements;" . SqlChangesTracker::IGNORE_TRACKING );
	}

	/**
	 * {@inheritDoc}
	 */
	public static function getHandlerBaseId(): string {
		return 'toolset_group_id';
	}

	/**
	 * {@inheritDoc}
	 */
	public static function getLabel(): string {
		return _dpgettext( 'deployer-core', 'processor label', 'Toolset group_id' );
	}

	/**
	 * Gets the group ID from element_type and element_id.
	 *
	 * @param string $domain The domain. See ConnectedElementPersistence::get_element_group_by_element_id().
	 *     Usually "posts". Dev note: implement other domains if needed.
	 * @param string $element_id_as_full_uuid The element ID as full UUID. This is the value from the exported data.
	 *
	 * @return int|null The group ID, null if not found.
	 *
	 * @throws \EaLab\WP_Deployer\vendor\Ealab\Deployer\Exception\WpDeployException
	 */
	private function getGroupIdFromElementTypeAndId( string $domain, string $element_id_as_full_uuid ): ?int {
		/** @noinspection PhpUnhandledExceptionInspection */
		/** @var DatabaseLayerFactory $database_layer_factory */
		$database_layer_factory = toolset_dic()->make( DatabaseLayerFactory::class );

		$connected_element_persistence = $database_layer_factory->connected_element_persistence();

		if ( empty( $connected_element_persistence ) ) {
			throw new WpDeployException( _dpgettext( 'deployer-core', 'item value handler', 'Could not retrieve the ConnectedElementPersistence instance. The Toolset database layer may be incompatible.' ) );
		}

		// Convert the element_id_as_full_uuid to the real element_id.
		$tracker = $this->tracking_manager->getItemTrackerByItemFullUuid( $element_id_as_full_uuid );

		if ( empty( $tracker ) ) {
			return null;
		}

		$element_id = $tracker->getLocalIdFromUuid( $element_id_as_full_uuid );

		$group_id = $connected_element_persistence->get_element_group_by_element_id( $element_id, $domain );

		if ( null !== $group_id ) {
			// Use the currently set group ID.
			return $group_id->get_id();
		}

		return null;
	}

	/**
	 * {@inheritDoc}
	 */
	public function getUnprocessedValue( int $operation, ?callable $progress_callback = null ) {
		if ( ! Plugin::isPluginActive( 'types/wpcf.php' ) ) {
			// The plugin is not enabled, do not process anything.
			return $this->value;
		}

		$holder_item_fields = $this->holder_item->getRawDataFields();

		switch ( $operation ) {
			case ItemValueHandlerBase::OPERATION__EXPORT:
				// Export the value as-is. We don't use it.
				return static::getProcessorPlaceholder();

			case ItemValueHandlerBase::OPERATION__IMPORT__FINALIZE:
				// This should not fail because we already assigned an ID if not existing yet.
				return $this->group_id_to_set;

			case ItemValueHandlerBase::OPERATION__IMPORT__PRESAVE:
				// Get the current group_id (translation group) of this item, or generate a new one.
				$this->group_id_to_set = $this->getGroupIdFromElementTypeAndId( $holder_item_fields['domain'], $holder_item_fields['element_id'] ) ?? $this->generateId();

				return $this->group_id_to_set;

			default:
				throw new WpDeployException( 'Invalid operation in ToolsetGroupIdItemValueHandler::getUnprocessedValue() : ' . $operation . '.' );
		}
	}
}
