<?php
/**
 * Acceso embebido al panel público (sin salir a wp-login ni otras páginas).
 *
 * @package Logistica
 */

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

/**
 * Formulario de acceso y cierre de sesión integrados en JB Planeación.
 */
class Logistica_Panel_Auth {

	public const NONCE_ACTION = 'logistica_panel_auth';

	public const RESET_OPTION = 'jb_password_reset_tokens';

	public const RESET_TTL = 3600;

	/**
	 * @return void
	 */
	public static function init() {
		add_action( 'wp_ajax_nopriv_logistica_panel_login', array( __CLASS__, 'ajax_login' ) );
		add_action( 'wp_ajax_logistica_panel_login', array( __CLASS__, 'ajax_login' ) );
		add_action( 'wp_ajax_logistica_panel_logout', array( __CLASS__, 'ajax_logout' ) );
		add_action( 'wp_ajax_nopriv_logistica_panel_forgot_password', array( __CLASS__, 'ajax_forgot_password' ) );
		add_action( 'wp_ajax_logistica_panel_forgot_password', array( __CLASS__, 'ajax_forgot_password' ) );
		add_action( 'wp_ajax_nopriv_logistica_panel_reset_password', array( __CLASS__, 'ajax_reset_password' ) );
		add_action( 'wp_ajax_logistica_panel_reset_password', array( __CLASS__, 'ajax_reset_password' ) );
		add_action( 'wp_ajax_logistica_session_ping', array( __CLASS__, 'ajax_session_ping' ) );
		add_action( 'wp_ajax_nopriv_logistica_session_ping', array( __CLASS__, 'ajax_session_ping' ) );
	}

	/**
	 * Keep-alive / comprobación de sesión para el panel autenticado.
	 *
	 * @return void
	 */
	public static function enqueue_session_guard() {
		if ( ! is_user_logged_in() ) {
			return;
		}

		wp_enqueue_script(
			'logistica-session-guard',
			LOGISTICA_PLUGIN_URL . 'assets/js/session-guard.js',
			array(),
			logistica_asset_version( 'assets/js/session-guard.js' ),
			true
		);

		wp_localize_script(
			'logistica-session-guard',
			'LogisticaSessionGuard',
			array(
				'ajaxUrl'  => admin_url( 'admin-ajax.php' ),
				'loginUrl' => home_url( '/' ),
			)
		);
	}

	/**
	 * Ping ligero: confirma login y renueva cookie/nonces básicos.
	 *
	 * @return void
	 */
	public static function ajax_session_ping() {
		if ( ! is_user_logged_in() ) {
			wp_send_json_error(
				array(
					'message' => __( 'Sesión expirada. Vuelve a iniciar sesión.', 'logistica' ),
					'code'    => 'session_expired',
				),
				401
			);
		}

		if ( class_exists( 'JB_Auth' ) && method_exists( 'JB_Auth', 'touch_session_cookie' ) ) {
			JB_Auth::touch_session_cookie();
		}

		wp_send_json_success(
			array(
				'ok'     => true,
				'nonces' => array(
					'user_panel' => wp_create_nonce( 'logistica_user_panel' ),
				),
			)
		);
	}

	/**
	 * @return void
	 */
	public static function enqueue_assets() {
		wp_enqueue_script(
			'logistica-panel-auth',
			LOGISTICA_PLUGIN_URL . 'assets/js/panel-auth.js',
			array(),
			logistica_asset_version( 'assets/js/panel-auth.js' ),
			true
		);

		wp_localize_script(
			'logistica-panel-auth',
			'LogisticaPanelAuth',
			array(
				'ajaxUrl'        => admin_url( 'admin-ajax.php' ),
				'authNonce'      => wp_create_nonce( self::NONCE_ACTION ),
				'resetUrl'       => home_url( 'reset-password.php' ),
				'loginUrl'       => home_url( '/' ),
			)
		);
	}

	/**
	 * @return string
	 */
	public static function render_login_screen() {
		ob_start();
		$context = 'login';
		include LOGISTICA_PLUGIN_DIR . 'admin/views/panel-auth.php';
		return (string) ob_get_clean();
	}

	/**
	 * @return string
	 */
	public static function render_denied_screen() {
		ob_start();
		$context = 'denied';
		include LOGISTICA_PLUGIN_DIR . 'admin/views/panel-auth.php';
		return (string) ob_get_clean();
	}

	/**
	 * @return string
	 */
	public static function render_reset_password_screen() {
		ob_start();
		$context = 'reset';
		include LOGISTICA_PLUGIN_DIR . 'admin/views/panel-auth.php';
		return (string) ob_get_clean();
	}

	/**
	 * @return void
	 */
	public static function ajax_login() {
		check_ajax_referer( self::NONCE_ACTION, 'nonce' );

		if ( is_user_logged_in() && Logistica_Roles::user_can_access_plugin() ) {
			wp_send_json_success();
		}

		$username = isset( $_POST['username'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['username'] ) ) : '';
		$password = isset( $_POST['password'] ) ? (string) wp_unslash( $_POST['password'] ) : '';
		$remember = ! empty( $_POST['remember'] );

		if ( $username === '' || $password === '' ) {
			wp_send_json_error(
				array(
					'message' => __( 'Completa usuario y contraseña.', 'logistica' ),
				)
			);
		}

		$user = wp_signon(
			array(
				'user_login'    => $username,
				'user_password' => $password,
				'remember'      => $remember,
			),
			is_ssl()
		);

		if ( is_wp_error( $user ) ) {
			wp_send_json_error(
				array(
					'message' => self::login_error_message( $user ),
				)
			);
		}

		if ( ! Logistica_Roles::user_can_access_plugin( $user->ID ) ) {
			wp_logout();
			wp_send_json_error(
				array(
					'message' => __( 'Tu usuario no tiene permisos para acceder a JB Planeación.', 'logistica' ),
				)
			);
		}

		wp_set_current_user( $user->ID );

		$redirect = Logistica_Roles::get_operations_panel_url( 'logistica' );

		wp_send_json_success( array( 'redirect' => $redirect ) );
	}

	/**
	 * @return void
	 */
	public static function ajax_logout() {
		check_ajax_referer( self::NONCE_ACTION, 'nonce' );

		if ( is_user_logged_in() ) {
			wp_logout();
		}

		wp_send_json_success();
	}

	/**
	 * @return void
	 */
	public static function ajax_forgot_password() {
		check_ajax_referer( self::NONCE_ACTION, 'nonce' );

		$identity = isset( $_POST['identity'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['identity'] ) ) : '';
		if ( '' === $identity ) {
			wp_send_json_error( array( 'message' => __( 'Indica tu usuario o correo.', 'logistica' ) ) );
		}

		$user = get_user_by( 'login', $identity );
		if ( ! $user ) {
			$user = get_user_by( 'email', $identity );
		}

		if ( ! $user || ! Logistica_Roles::user_can_access_plugin( $user->ID ) ) {
			wp_send_json_success(
				array(
					'message' => __( 'Si existe una cuenta con esos datos, recibirás un enlace para restablecer la contraseña.', 'logistica' ),
				)
			);
		}

		$token = self::create_reset_token( $user );
		$link  = self::reset_link( $token, $user->user_login );

		$sent = wp_mail(
			$user->user_email,
			__( 'Restablecer contraseña — JB Planeación', 'logistica' ),
			sprintf(
				"Hola %s,\n\nUsa este enlace para crear una nueva contraseña (válido 1 hora):\n%s\n\nSi no solicitaste este cambio, ignora este mensaje.",
				$user->display_name ?: $user->user_login,
				$link
			)
		);

		wp_send_json_success(
			array(
				'message'  => $sent
					? __( 'Te enviamos un correo con el enlace para restablecer tu contraseña.', 'logistica' )
					: __( 'Usa el enlace siguiente para restablecer tu contraseña (válido 1 hora).', 'logistica' ),
				'resetUrl' => $sent ? '' : $link,
			)
		);
	}

	/**
	 * @return void
	 */
	public static function ajax_reset_password() {
		check_ajax_referer( self::NONCE_ACTION, 'nonce' );

		$key      = isset( $_POST['key'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['key'] ) ) : '';
		$login    = isset( $_POST['login'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['login'] ) ) : '';
		$password = isset( $_POST['password'] ) ? (string) wp_unslash( $_POST['password'] ) : '';
		$confirm  = isset( $_POST['password_confirm'] ) ? (string) wp_unslash( $_POST['password_confirm'] ) : '';

		if ( '' === $key || '' === $login ) {
			wp_send_json_error( array( 'message' => __( 'Enlace de recuperación no válido.', 'logistica' ) ) );
		}

		if ( strlen( $password ) < 8 ) {
			wp_send_json_error( array( 'message' => __( 'La contraseña debe tener al menos 8 caracteres.', 'logistica' ) ) );
		}

		if ( $password !== $confirm ) {
			wp_send_json_error( array( 'message' => __( 'Las contraseñas no coinciden.', 'logistica' ) ) );
		}

		$user = self::validate_reset_token( $key, $login );
		if ( ! $user ) {
			wp_send_json_error( array( 'message' => __( 'El enlace expiró o ya no es válido. Solicita uno nuevo.', 'logistica' ) ) );
		}

		JB_Auth::update_password( $user->ID, $password );
		self::delete_reset_token( $key );

		wp_send_json_success(
			array(
				'message'  => __( 'Contraseña actualizada. Ya puedes iniciar sesión.', 'logistica' ),
				'redirect' => home_url( '/' ),
			)
		);
	}

	/**
	 * @param object $user Usuario.
	 * @return string Token.
	 */
	private static function create_reset_token( $user ) {
		$token  = bin2hex( random_bytes( 32 ) );
		$tokens = get_option( self::RESET_OPTION, array() );
		if ( ! is_array( $tokens ) ) {
			$tokens = array();
		}

		foreach ( $tokens as $stored_key => $data ) {
			if ( (int) ( $data['user_id'] ?? 0 ) === (int) $user->ID ) {
				unset( $tokens[ $stored_key ] );
			}
		}

		$tokens[ $token ] = array(
			'user_id' => (int) $user->ID,
			'login'   => (string) $user->user_login,
			'expires' => time() + self::RESET_TTL,
		);

		update_option( self::RESET_OPTION, $tokens );
		return $token;
	}

	/**
	 * @param string $key   Token.
	 * @param string $login Login.
	 * @return object|false
	 */
	public static function validate_reset_token( $key, $login ) {
		$tokens = get_option( self::RESET_OPTION, array() );
		if ( ! is_array( $tokens ) || ! isset( $tokens[ $key ] ) ) {
			return false;
		}

		$data = $tokens[ $key ];
		if ( time() > (int) ( $data['expires'] ?? 0 ) ) {
			self::delete_reset_token( $key );
			return false;
		}

		if ( sanitize_user( $login, true ) !== (string) ( $data['login'] ?? '' ) ) {
			return false;
		}

		return get_userdata( (int) ( $data['user_id'] ?? 0 ) );
	}

	/**
	 * @param string $key Token.
	 * @return void
	 */
	private static function delete_reset_token( $key ) {
		$tokens = get_option( self::RESET_OPTION, array() );
		if ( is_array( $tokens ) && isset( $tokens[ $key ] ) ) {
			unset( $tokens[ $key ] );
			update_option( self::RESET_OPTION, $tokens );
		}
	}

	/**
	 * @param string $token Token.
	 * @param string $login Login.
	 * @return string
	 */
	private static function reset_link( $token, $login ) {
		return add_query_arg(
			array(
				'key'   => $token,
				'login' => rawurlencode( $login ),
			),
			home_url( 'reset-password.php' )
		);
	}

	/**
	 * @param WP_Error $error Error de autenticación.
	 * @return string
	 */
	private static function login_error_message( WP_Error $error ) {
		$code = $error->get_error_code();

		if ( in_array( $code, array( 'empty_username', 'empty_password' ), true ) ) {
			return __( 'Completa usuario y contraseña.', 'logistica' );
		}

		if ( in_array( $code, array( 'invalid_username', 'invalid_email' ), true ) ) {
			return __( 'Usuario o correo no reconocido.', 'logistica' );
		}

		if ( 'incorrect_password' === $code ) {
			return __( 'Contraseña incorrecta.', 'logistica' );
		}

		return __( 'No se pudo iniciar sesión. Revisa tus datos.', 'logistica' );
	}
}
