<?php
namespace AcademyProDeviceLoginRestrictions;

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

class Admin {
	public static $meta_key = 'academy_pro_active_login_session_';
	private static $cookie_expiry = 86400 * 30;
	private static $device_key;
	private static $cookie_name;

	public static function init() {
		$self = new self();
		add_action( 'wp_ajax_nopriv_academy_pro_device_login_restrictions/remove_all_active_sessions', array( $self, 'remove_all_active_sessions' ) );
		add_action( 'wp_ajax_academy_pro/frontend/user_login_session_remove', array( $self, 'device_remove_manually' ) );
		add_action( 'academy/shortcode/after_student_registration', array( $self, 'set_login_cookie_after_registration' ) );
		add_action( 'academy/shortcode/after_instructor_registration', array( $self, 'set_login_cookie_after_registration' ) );
		add_filter( 'authenticate', array( $self, 'academy_student_has_login_access' ), 999 );
		add_action( 'init', array( $self, 'logout_all_active_login_students' ) );
		add_action( 'wp_logout', array( $self, 'academy_student_session_destroy' ) );
	}

	public static function login_device_info() {
		$device_info = [
			'device'   => Helper::get_device_type(),
			'browser'  => Helper::get_browser_name(),
			'location' => Helper::get_location(),
			'time'     => time(),
			'platform' => Helper::get_platform(),
		];
		return wp_json_encode( $device_info );
	}

	public function set_login_cookie_after_registration( $user_id ) {
		if ( ! $user_id ) {
			$user_id = get_current_user_id();
		}

		$current_device = $this->get_current_device_key();
		$device_info    = self::login_device_info();

		add_user_meta( $user_id, self::$meta_key . $current_device, $device_info );
	}

	public function get_current_device_key() {
		if ( is_null( self::$device_key ) ) {
			$auth_key = '';

			if ( isset( $_COOKIE[ self::get_cookie() ] ) ) {
				$auth_key = sanitize_text_field( wp_unslash( $_COOKIE[ self::get_cookie() ] ) );
			} else {
				$auth_key = md5( uniqid( wp_rand(), true ) );

				setcookie(
					self::get_cookie(),
					$auth_key,
					time() + self::$cookie_expiry,
					'/'
				);
			}
			self::$device_key = $auth_key;
		}
		return self::$device_key;
	}

	public function academy_student_has_login_access( $user ) {
		if ( is_wp_error( $user ) || is_null( $user ) ) {
			return $user;
		}
		if ( array_intersect( [ 'administrator', 'academy_instructor' ], $user->roles ) ) {
			return $user;
		}
		if ( $this->has_device_limitation( $user->ID ) ) {
			$device_key = $this->get_current_device_key();
			add_user_meta( $user->ID, self::$meta_key . $device_key, self::login_device_info() );
			return $user;
		}
		$this->set_session_user_id( $user->ID );

		$alert_msg  = sprintf(
			'<p>%s</p><button class="academy-btn academy-btn--xs academy-btn--preset-red" id="device-reset">%s</button>',
			esc_html__( 'Sorry, You are not allowed for login. Please Reset your Active Login Data.', 'academy-pro' ),
			esc_html__( 'Reset Active Device', 'academy-pro' )
		);

		return new \WP_Error( 'academy_login_limit', $alert_msg );
	}

	public function remove_all_active_sessions() {
		check_ajax_referer( 'academy_nonce', 'security' );

		$user_id = $this->get_user_id();
		if ( $user_id ) {
			$is_delete = self::clear_all_access_by_user_id( $user_id );
			if ( $is_delete ) {
				delete_user_meta( $user_id, 'session_tokens' );
				setcookie(
					$this->get_cookie(),
					'',
					time() - 3600,
					'/'
				);
				wp_send_json_success( __( 'Successfully removed all Active Device', 'academy-pro' ) );
			}
			wp_send_json_error( __( 'Failed to remove all Active Device', 'academy-pro' ) );
		}
		wp_send_json_error( __( 'Invalid User ID', 'academy-pro' ) );
	}

	public static function get_cookie() {
		if ( is_null( self::$cookie_name ) ) {
			self::$cookie_name = 'academy_login_cookie_' . md5( get_site_option( 'siteurl' ) );
		}
		return self::$cookie_name;
	}

	private function get_user_id() {
		if ( ! isset( $_COOKIE['academy_user_id'] ) ) {
			return 0;
		}
		$user_id = absint( sanitize_text_field( wp_unslash( $_COOKIE['academy_user_id'] ) ) );
		setcookie( 'academy_user_id', '', time() - 3600, '/' );

		return $user_id;
	}

	public function academy_student_session_destroy( $user_id ) {
		if ( ! $user_id ) {
			return;
		}

		$current_device = $this->get_current_device_key();

		if ( $current_device ) {
			setcookie(
				self::get_cookie(), '', time() - 3600
			);
			delete_user_meta( $user_id, self::$meta_key . $current_device );
		}
	}

	public function device_remove_manually() {
		check_ajax_referer( 'academy_nonce', 'security' );

		$device_key = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '';
		if ( ! $device_key ) {
			wp_send_json_error( __( 'Invalid Your Device Key', 'academy-pro' ) );
		}

		$user_id = get_current_user_id();
		$user_meta = get_user_meta( $user_id );

		$session_tokens = isset( $user_meta['session_tokens'] ) ? $user_meta['session_tokens'] : [];
		$device_login_info = isset( $user_meta[ $device_key ] ) ? $user_meta[ $device_key ] : [];

		if ( empty( $session_tokens ) || empty( $device_login_info ) ) {
			wp_send_json_error( __( 'No session tokens or login info found for this device.', 'academy-pro' ) );
		}

		// Extract the login time from the device's login info
		$login_time = null;
		foreach ( $device_login_info as $login_info ) {
			$login_info = json_decode( $login_info );
			if ( isset( $login_info->time ) ) {
				$login_time = $login_info->time;
				break;
			}
		}

		if ( ! $login_time ) {
			wp_send_json_error( __( 'Invalid login time for the device.', 'academy-pro' ) );
		}

		// Process session tokens to remove the matching session
		$session_updated = false;
		foreach ( $session_tokens as $session_value ) {
			$session_data = maybe_unserialize( $session_value );
			$token = (string) key( $session_data );
			// If session token matches login time, remove it
			foreach ( $session_data as $key => $value ) {
				if ( in_array( $login_time, $value ) && $token === (string) $key ) {// phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
					unset( $session_data[ $key ] );
					update_user_meta( $user_id, 'session_tokens', $session_data );
					$session_updated = true;
					break;
				}
			}

			if ( $session_updated ) {
				break;
			}
		}

		$is_delete = delete_user_meta( $user_id, $device_key );

		$current_device_key = self::$meta_key . $this->get_current_device_key();
		if ( $current_device_key === $device_key ) {
			wp_logout();
			wp_send_json_success( __( 'Successfully deleted the user device.', 'academy-pro' ) );
		}

		if ( $is_delete ) {
			wp_send_json_success( __( 'Successfully deleted the user device.', 'academy-pro' ) );
		}
		wp_send_json_error( __( 'Failed to delete the user device.', 'academy-pro' ) );
	}

	public function set_session_user_id( $user_id ) {
		if ( $user_id ) {
			setcookie( 'academy_user_id', $user_id, time() + 3600, '/' );
		}
	}

	private function has_device_limitation( $user_id ) {
		$user_id = absint( $user_id );

		if ( ! \Academy\Helper::get_settings( 'is_enable_device_login_restriction' ) ) {
			return true;
		}

		$device_limit = (int) \Academy\Helper::get_settings( 'device_login_restriction_limit' );
		if ( 0 === $device_limit ) {
			return true;
		}
		$logged_in_devices = self::get_active_login_devices( $user_id );
		if ( self::is_existing_device( $user_id ) ) {
			return $device_limit >= $logged_in_devices;
		}
		return $device_limit > $logged_in_devices;
	}

	private function is_existing_device( $user_id ) {
		global $wpdb;
		$current_device = $this->get_current_device_key();
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$result = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->usermeta} WHERE meta_key = %s AND user_id = %d",
				self::$meta_key . $current_device,
				$user_id
			)
		);
		return ! empty( $result );
	}

	public static function clear_all_access_by_user_id( $user_id ) {
		global $wpdb;

		$key = self::$meta_key . '%';
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		return $wpdb->query(
			$wpdb->prepare(
				"DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE %s AND user_id = %d",
				$key,
				$user_id
			)
		);
	}

	public static function get_active_login_devices( $user_id ) {
		$session_data = get_user_meta( $user_id, 'session_tokens', true );
		return is_array( $session_data ) ? count( $session_data ) : 0;
	}

	public function logout_all_active_login_students() {
		global $wpdb;

		if ( get_option( 'is_delete_academy_students_login_session' ) ) {
			return;
		}

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$results = $wpdb->get_col( $wpdb->prepare(
			"SELECT user_id 
			 FROM {$wpdb->usermeta} 
			 WHERE meta_key = %s",
			'is_academy_student'
		) );

		if ( empty( $results ) ) {
			return;
		}

		foreach ( $results as $user_id ) {
			$user = get_userdata( $user_id );

			if ( $user && empty( array_intersect( [ 'administrator', 'academy_instructor' ], $user->roles ) ) ) {
				delete_user_meta( $user_id, 'session_tokens' );
			}
		}

		add_option( 'is_delete_academy_students_login_session', true );
	}
}
