<?php
/**
 * Replaces the author ID by the import author ID.
 *
 * @package Ealab\Deployer
 */

namespace EaLab\WP_Deployer\vendor\Ealab\Deployer\Tracking\ItemValueHandler\ValueProcessor;

use EaLab\WP_Deployer\vendor\Dakwamine\Component\RootDependencyDefinition;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Exception\UnsetPluginConfigException;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Exception\WpDeployException;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Tracking\ItemTracker\ItemTrackerBase;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Tracking\ItemValueHandler\ItemValueHandlerBase;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Tracking\TrackingManager;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Utility\Settings;
use WP_User;
use WP_User_Query;

/**
 * Replaces the author ID by the import author ID.
 *
 * This is needed because we don't want to export users in the default configuration of this library.
 */
class ImportAuthorProcessor extends ValueProcessorBase {
	/**
	 * The option name to use to get the import author ID.
	 */
	public const OPTIONS__IMPORT_AUTHOR = 'import_author';

	/**
	 * Tracking manager.
	 *
	 * @var 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;
	}

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

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

	/**
	 * The user tracker. May not be found (e.g. on multisite subsites).
	 *
	 * @return ItemTrackerBase|null
	 */
	private function getUsersTracker(): ?ItemTrackerBase {
		return $this->tracking_manager->getItemTrackerByTrackerId( $this->getUsersTrackerId() );
	}

	/**
	 * The tracker ID where users are stored.
	 *
	 * @return string The tracker ID where users are stored.
	 */
	private function getUsersTrackerId(): string {
		return 'users';
	}

	/**
	 * {@inheritDoc}
	 *
	 * @throws UnsetPluginConfigException When the import author option is not set.
	 */
	public function process( $value, int $operation, ?callable $progress_callback = null ) {
		if ( null === $value ) {
			// This is an unset value. No need to return a valid user; return null.
			// If it fails on import due to a non-null column, it means the
			// database that exported the data contains corrupted rows.
			return null;
		}

		$user_tracker = null;

		if ( ItemValueHandlerBase::OPERATION__EXPORT === $operation ) {
			// This is also the operation to use when we want to compare the values.
			if ( ! filter_var( $value, FILTER_VALIDATE_INT ) ) {
				// This is not a valid author ID, so we don't want to replace it.
				return $value;
			}

			try {
				$user_tracker = $this->getUsersTracker();
				$uuid         = $user_tracker
					? ( $user_tracker->getItemUuidByLocalId( $value ) ?? '' )
					: '';
			} catch ( WpDeployException $e ) {
				// This should never happen, but let's process as no failure occurred.
				$uuid = '';
			}

			return static::getProcessorPlaceholder( $uuid );
		}

		// Retrieve the UUID from the placeholder, if set.
		// If $uuid is true, it means that the value is a placeholder without UUID.
		// If false, it is not a placeholder we want to replace.
		$uuid = static::isProcessorPlaceholder( $value );

		if ( empty( $uuid ) ) {
			// This is not a value that needs to be replaced.
			return $value;
		}

		if ( is_string( $uuid ) ) {
			try {
				// Attempt to get the local ID of the user from the UUID.
				$user_tracker = $user_tracker ?? $this->getUsersTracker();

				$local_id = $user_tracker
					? ( $user_tracker->getLocalIdFromUuid( $uuid ) ?? null )
					: null;

				if ( ! empty( $local_id ) ) {
					// The user exists, so we can use its ID.
					return $local_id;
				}
			} catch ( WpDeployException $e ) {
				// This should never happen, but let's process as no failure occurred.
			}
		}

		// Check if the import author option is set.
		$dsc_settings_data = get_option( 'deploy_sync_content__settings_data' );

		$import_author = ! empty( $dsc_settings_data[ static::OPTIONS__IMPORT_AUTHOR ] )
			? $dsc_settings_data[ static::OPTIONS__IMPORT_AUTHOR ]
			: '';

		if ( empty( $import_author ) ) {
			$was_unset = true;
		}

		if ( empty( $import_author ) ) {
			// At least try to get the current user.
			$current_user = wp_get_current_user();

			if ( in_array( 'administrator', $current_user->roles ?? array(), true ) ) {
				$import_author = $current_user->ID;
			}
		}

		if ( empty( $import_author ) ) {
			// At least try to use the first admin user.
			$user_query = new WP_User_Query( array( 'role_in' => 'Administrator', 'number' => 1 ) );

			/** @var WP_User[] $maybe_admin_users */
			$maybe_admin_users = $user_query->get_results();

			if ( ! empty( $maybe_admin_users ) ) {
				$import_author = reset( $maybe_admin_users )->ID;
			}
		}

		if ( empty( $import_author ) ) {
			throw new UnsetPluginConfigException( 'The import author option is not set.' );
		}

		if ( ! empty( $was_unset ) ) {
			Settings::getInstance()->set( static::OPTIONS__IMPORT_AUTHOR, $import_author );
		}

		return $import_author;
	}
}
