<?php
/**
 * Trazabilidad y papelera para usuarios JB (standalone).
 *
 * @package Logistica
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Soft delete / restore / purge de usuarios de la app.
 */
final class Logistica_User_Lifecycle {

	public const META_DELETED    = 'jb_user_deleted';

	public const META_DELETED_AT = 'jb_user_deleted_at';

	public const MODULE_KEY      = 'jb_users';

	public const ENTITY_TYPE     = 'user';

	/**
	 * @return void
	 */
	public static function init() {
		add_action( 'logistica_lifecycle_restore', array( __CLASS__, 'handle_restore' ), 10, 5 );
		add_action( 'logistica_lifecycle_purge_entity', array( __CLASS__, 'handle_purge' ), 10, 4 );
	}

	/**
	 * @param int $user_id User ID.
	 * @return bool
	 */
	public static function is_deleted( $user_id ) {
		return '1' === (string) get_user_meta( (int) $user_id, self::META_DELETED, true );
	}

	/**
	 * @param int $user_id User ID.
	 * @return array<string, mixed>|WP_Error
	 */
	public static function soft_delete( $user_id ) {
		$user_id = (int) $user_id;
		$user    = get_userdata( $user_id );

		if ( ! $user || ! $user->exists() ) {
			return new WP_Error( 'not_found', __( 'Usuario no encontrado.', 'logistica' ) );
		}

		if ( ! Logistica_Roles::user_can_manage_config() ) {
			return new WP_Error( 'forbidden', __( 'No tienes permisos para eliminar usuarios.', 'logistica' ) );
		}

		if ( (int) get_current_user_id() === $user_id ) {
			return new WP_Error( 'self_delete', __( 'No puedes eliminar tu propio usuario.', 'logistica' ) );
		}

		if ( self::is_deleted( $user_id ) ) {
			return new WP_Error( 'already_deleted', __( 'El usuario ya está en la papelera.', 'logistica' ) );
		}

		if ( self::is_last_admin( $user_id ) ) {
			return new WP_Error( 'last_admin', __( 'No puedes eliminar el último administrador del sistema.', 'logistica' ) );
		}

		$payload = self::build_payload( $user );
		$label   = trim( $user->display_name . ' (' . $user->user_login . ')' );

		Logistica_Entity_Lifecycle::record_delete(
			self::MODULE_KEY,
			self::ENTITY_TYPE,
			(string) $user_id,
			$payload,
			$label,
			sprintf(
				/* translators: %s: user login */
				__( 'Usuario %s enviado a papelera', 'logistica' ),
				$user->user_login
			)
		);

		update_user_meta( $user_id, self::META_DELETED, '1' );
		update_user_meta( $user_id, self::META_DELETED_AT, current_time( 'mysql', true ) );

		if ( (int) get_current_user_id() === $user_id ) {
			wp_logout();
		}

		return $payload;
	}

	/**
	 * @param int                  $user_id User ID.
	 * @param array<string, mixed> $payload Snapshot.
	 * @return true|WP_Error
	 */
	public static function restore( $user_id, $payload ) {
		$user_id = (int) $user_id;
		$user    = get_userdata( $user_id );

		if ( ! $user || ! $user->exists() ) {
			return new WP_Error( 'not_found', __( 'Usuario no encontrado.', 'logistica' ) );
		}

		delete_user_meta( $user_id, self::META_DELETED );
		delete_user_meta( $user_id, self::META_DELETED_AT );

		if ( ! empty( $payload['jb_role'] ) ) {
			update_user_meta( $user_id, Logistica_Roles::USER_META_ROLE, sanitize_key( (string) $payload['jb_role'] ) );
		}

		if ( isset( $payload['tab_overrides'] ) && is_array( $payload['tab_overrides'] ) ) {
			update_user_meta( $user_id, Logistica_Roles::USER_META_TABS, $payload['tab_overrides'] );
		}

		return true;
	}

	/**
	 * @param int $user_id User ID.
	 * @return true|WP_Error
	 */
	public static function hard_delete( $user_id ) {
		global $wpdb;

		if ( ! Logistica_Entity_Lifecycle::can_purge() ) {
			return new WP_Error( 'forbidden', __( 'No tienes permiso para eliminar definitivamente.', 'logistica' ) );
		}

		$user_id = (int) $user_id;
		if ( $user_id <= 0 ) {
			return new WP_Error( 'invalid_user', __( 'Usuario no válido.', 'logistica' ) );
		}

		if ( self::is_last_admin( $user_id ) ) {
			return new WP_Error( 'last_admin', __( 'No puedes eliminar el último administrador del sistema.', 'logistica' ) );
		}

		$wpdb->delete( $wpdb->prefix . 'usermeta', array( 'user_id' => $user_id ), array( '%d' ) );
		$wpdb->delete( $wpdb->prefix . 'users', array( 'ID' => $user_id ), array( '%d' ) );

		return true;
	}

	/**
	 * @param WP_User $user User.
	 * @return array<string, mixed>
	 */
	private static function build_payload( $user ) {
		$overrides = get_user_meta( $user->ID, Logistica_Roles::USER_META_TABS, true );

		return array(
			'_storage'      => 'jb_user',
			'ID'            => (int) $user->ID,
			'user_login'    => (string) $user->user_login,
			'user_email'    => (string) $user->user_email,
			'display_name'  => (string) $user->display_name,
			'user_nicename' => (string) $user->user_nicename,
			'jb_role'       => (string) get_user_meta( $user->ID, Logistica_Roles::USER_META_ROLE, true ),
			'tab_overrides' => is_array( $overrides ) ? $overrides : array(),
			'is_admin'      => JB_Auth::user_has_cap( $user->ID, 'manage_options' ),
		);
	}

	/**
	 * @param int $user_id User ID.
	 * @return bool
	 */
	private static function is_last_admin( $user_id ) {
		if ( ! JB_Auth::user_has_cap( $user_id, 'manage_options' ) ) {
			return false;
		}

		global $wpdb;
		$count = (int) $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(DISTINCT u.ID)
				FROM {$wpdb->prefix}users u
				INNER JOIN {$wpdb->prefix}usermeta um ON um.user_id = u.ID AND um.meta_key = %s AND um.meta_value = %s
				LEFT JOIN {$wpdb->prefix}usermeta um_del ON um_del.user_id = u.ID AND um_del.meta_key = %s AND um_del.meta_value = %s
				WHERE um_del.umeta_id IS NULL",
				'jb_is_admin',
				'1',
				self::META_DELETED,
				'1'
			)
		);

		return $count <= 1;
	}

	/**
	 * @param string               $module_key  Module.
	 * @param string               $entity_type Type.
	 * @param string               $entity_id   ID.
	 * @param array<string, mixed> $payload     Snapshot.
	 * @param array<string, mixed> $row         Trash row.
	 * @return void
	 */
	public static function handle_restore( $module_key, $entity_type, $entity_id, $payload, $row ) {
		unset( $row );

		if ( self::MODULE_KEY !== $module_key || self::ENTITY_TYPE !== $entity_type ) {
			return;
		}

		self::restore( (int) $entity_id, is_array( $payload ) ? $payload : array() );
	}

	/**
	 * @param string               $module_key  Module.
	 * @param string               $entity_type Type.
	 * @param string               $entity_id   ID.
	 * @param array<string, mixed> $payload     Snapshot.
	 * @return void
	 */
	public static function handle_purge( $module_key, $entity_type, $entity_id, $payload ) {
		unset( $payload );

		if ( self::MODULE_KEY !== $module_key || self::ENTITY_TYPE !== $entity_type ) {
			return;
		}

		self::hard_delete( (int) $entity_id );
	}
}
