<?php

// Exit if accessed directly
if (!defined("ABSPATH")) {
    exit();
}
if (!class_exists("Pw_New_User_Approve_User_List")) {
    class Pw_New_User_Approve_User_List
    {
        /**
         * The only instance of pw_new_user_approve_user_list.
         *
         * @var Pw_New_User_Approve_User_List
         */
        private static $instance;

        /**
         * Returns the main instance.
         *
         * @return Pw_New_User_Approve_User_List
         */
        public static function instance()
        {
            if (!isset(self::$instance)) {
                self::$instance = new Pw_New_User_Approve_User_List();
            }
            return self::$instance;
        }

        private function __construct()
        {
            // Actions
            add_action("load-users.php", [$this, "update_action"]);
            add_action(
                "restrict_manage_users",
                [$this, "status_filter"],
                10,
                1
            );
            add_action("pre_user_query", [$this, "filter_by_status"]);
            add_action("admin_footer-users.php", [$this, "admin_footer"]);
            add_action("load-users.php", [$this, "bulk_action"]);
            add_action("admin_notices", [$this, "admin_notices"]);
            add_action("show_user_profile", [$this, "profile_status_field"]);
            add_action("edit_user_profile", [$this, "profile_status_field"]);
            add_action("edit_user_profile_update", [
                $this,
                "save_profile_status_field",
            ]);
            add_action("admin_menu", [$this, "pending_users_bubble"], 999);

            // Filters
            add_filter(
                "user_row_actions",
                [$this, "user_table_actions"],
                10,
                2
            );
            add_filter("manage_users_columns", [$this, "add_column"]);
            add_filter(
                "manage_users_custom_column",
                [$this, "status_column"],
                10,
                3
            );
        }

        /**
         * Update the user status if the approve or deny link was clicked.
         *
         * @uses load-users.php
         */
        public function update_action()
        {
            if (
                isset($_GET["action"]) &&
                in_array($_GET["action"], ["approve", "deny"]) &&
                !isset($_GET["new_role"])
            ) {
                check_admin_referer("new-user-approve");

                $sendback = esc_url(
                    remove_query_arg(
                        [
                            "approved",
                            "denied",
                            "deleted",
                            "ids",
                            "pw-status-query-submit",
                            "new_role",
                        ],
                        wp_get_referer()
                    )
                );
                if (!$sendback) {
                    $sendback = admin_url("users.php");
                }

                $wp_list_table = _get_list_table("WP_Users_List_Table");

                $pagenum = $wp_list_table->get_pagenum();
                $sendback = esc_url(
                    add_query_arg("paged", $pagenum, $sendback)
                );

                $status = !empty($_GET["action"])
                    ? sanitize_key($_GET["action"])
                    : "";
                $user = !empty($_GET["user"])
                    ? absint(wp_unslash($_GET["user"]))
                    : "";

                pw_new_user_approve()->update_user_status($user, $status);

                if ($_GET["action"] == "approve") {
                    $sendback = esc_url(
                        add_query_arg(
                            [
                                "approved" => 1,
                                "ids" => $user,
                            ],
                            $sendback
                        )
                    );
                } else {
                    $sendback = esc_url(
                        add_query_arg(
                            [
                                "denied" => 1,
                                "ids" => $user,
                            ],
                            $sendback
                        )
                    );
                }

                wp_redirect($sendback);
                exit();
            }
        }

        /**
         * Add the approve or deny link where appropriate.
         *
         * @uses user_row_actions
         * @param array $actions
         * @param object $user
         * @return array
         */
        public function user_table_actions($actions, $user)
        {
            if ($user->ID == get_current_user_id()) {
                return $actions;
            }

            if (is_super_admin($user->ID)) {
                return $actions;
            }

            $user_status = pw_new_user_approve()->get_user_status($user->ID);

            $approve_link = add_query_arg([
                "action" => "approve",
                "user" => $user->ID,
            ]);
            $approve_link = remove_query_arg(["new_role"], $approve_link);
            $approve_link = wp_nonce_url($approve_link, "new-user-approve");

            $deny_link = add_query_arg([
                "action" => "deny",
                "user" => $user->ID,
            ]);
            $deny_link = remove_query_arg(["new_role"], $deny_link);
            $deny_link = wp_nonce_url($deny_link, "new-user-approve");

            $approve_action =
                '<a href="' .
                esc_url($approve_link) .
                '">' .
                __("Approve", "new-user-approve") .
                "</a>";
            $deny_action =
                '<a href="' .
                esc_url($deny_link) .
                '">' .
                __("Deny", "new-user-approve") .
                "</a>";

            if ($user_status == "pending") {
                $actions[] = $approve_action;
                $actions[] = $deny_action;
            } elseif ($user_status == "approved") {
                $actions[] = $deny_action;
            } elseif ($user_status == "denied") {
                $actions[] = $approve_action;
            }

            return $actions;
        }

        /**
         * Add the status column to the user table
         *
         * @uses manage_users_columns
         * @param array $columns
         * @return array
         */
        public function add_column($columns)
        {
            $the_columns["pw_user_status"] = __("Status", "new-user-approve");

            $newcol = array_slice($columns, 0, -1);
            $newcol = array_merge($newcol, $the_columns);
            $columns = array_merge($newcol, array_slice($columns, 1));

            return $columns;
        }

        /**
         * Show the status of the user in the status column
         *
         * @uses manage_users_custom_column
         * @param string $val
         * @param string $column_name
         * @param int $user_id
         * @return string
         */
        public function status_column($val, $column_name, $user_id)
        {
            switch ($column_name) {
                case "pw_user_status":
                    $status = pw_new_user_approve()->get_user_status($user_id);
                    if ($status == "approved") {
                        $status_i18n = __("approved", "new-user-approve");
                    } elseif ($status == "denied") {
                        $status_i18n = __("denied", "new-user-approve");
                    } elseif ($status == "pending") {
                        $status_i18n = __("pending", "new-user-approve");
                    }
                    return $status_i18n;
                    break;

                default:
            }

            return $val;
        }

        /**
         * Add a filter to the user table to filter by user status
         *
         * @uses restrict_manage_users
         */
        public function status_filter($which)
        {
            $id = "new_user_approve_filter-" . $which;

            $filter_button = submit_button(
                __("Filter", "new-user-approve"),
                "button",
                "pw-status-query-submit-" . $which,
                false,
                ["id" => "pw-status-query-submit-" . $which]
            );
            $filtered_status = $this->selected_status();
            ?>
		<label class="screen-reader-text" for="<?php echo esc_attr(
      $id
  ); ?>"><?php esc_html_e("View all users", "new-user-approve"); ?></label>
		<select id="<?php echo esc_attr(
      $id
  ); ?>" name="<?php echo esc_attr($id); ?>" style="float: none; margin: 0 0 0 15px;">
			<option value="view_all"><?php esc_html_e(
       "View all users",
       "new-user-approve"
   ); ?></option>
		<?php foreach (pw_new_user_approve()->get_valid_statuses() as $status): ?>
			<option value="<?php echo esc_attr($status); ?>"<?php selected(
    $status,
    $filtered_status
); ?>><?php echo esc_html($status); ?></option>
		<?php endforeach; ?>
		</select>
		<?php if (!empty($filter_button)) {
      echo wp_kses_post(
          apply_filters("new_user_approve_filter_button", $filter_button)
      );
  } ?>
		<style>
			#pw-status-query-submit-top,#pw-status-query-submit-bottom {
				float: right;
				margin: 2px 0 0 5px;
			}
		</style>
		<?php
        }

        /**
         * Modify the user query if the status filter is being used.
         *
         * @uses pre_user_query
         * @param $query
         */
        public function filter_by_status($query)
        {
            global $wpdb;

            if (!is_admin()) {
                return;
            }

            if (!function_exists("get_current_screen")) {
                return;
            }

            $screen = get_current_screen();

            if (isset($screen) && "users" != $screen->id) {
                return;
            }

            if ($this->selected_status() != null) {
                $filter = $this->selected_status();
                //$sendback = admin_url( 'users.php' );

                if ($filter == "view_all") {
                    //wp_redirect( $sendback );
                    return;
                }
                $query->query_from .= " INNER JOIN {$wpdb->usermeta} ON ( {$wpdb->users}.ID = $wpdb->usermeta.user_id )";

                if ("approved" == $filter) {
                    $query->query_fields = "DISTINCT SQL_CALC_FOUND_ROWS {$wpdb->users}.ID";
                    $query->query_from .= " LEFT JOIN {$wpdb->usermeta} AS mt1 ON ({$wpdb->users}.ID = mt1.user_id AND mt1.meta_key = 'pw_user_status')";
                    $query->query_where .= " AND ( ( $wpdb->usermeta.meta_key = 'pw_user_status' AND CAST($wpdb->usermeta.meta_value AS CHAR) = 'approved' ) OR mt1.user_id IS NULL )";
                } else {
                    $query->query_where .= " AND ( ($wpdb->usermeta.meta_key = 'pw_user_status' AND CAST($wpdb->usermeta.meta_value AS CHAR) = '{$filter}') )";
                }
            }
        }

        private function selected_status()
        {
            if (
                isset($_REQUEST["pw-status-query-submit-bottom"]) &&
                !empty($_REQUEST["pw-status-query-submit-bottom"])
            ) {
                return esc_attr(
                    isset($_REQUEST["new_user_approve_filter-bottom"]) &&
                    !empty($_REQUEST["new_user_approve_filter-bottom"])
                        ? sanitize_text_field(
                            wp_unslash(
                                $_REQUEST["new_user_approve_filter-bottom"]
                            )
                        )
                        : ""
                );
            } elseif (
                isset($_REQUEST["new_user_approve_filter-top"]) &&
                !empty($_REQUEST["new_user_approve_filter-bottom"])
            ) {
                return esc_attr(
                    sanitize_text_field(
                        wp_unslash($_REQUEST["new_user_approve_filter-top"])
                    )
                );
            }

            return null;
        }

        /**
         * Use javascript to add the ability to bulk modify the status of users.
         *
         * @uses admin_footer-users.php
         */
        public function admin_footer()
        {
            $screen = get_current_screen();

            if ($screen->id == "users"): ?>
			<script type="text/javascript">
				jQuery(document).ready(function ($) {

					$('<option>').val('approve').text('<?php esc_attr_e(
         "Approve",
         "new-user-approve"
     ); ?>').appendTo("select[name='action']");
					$('<option>').val('approve').text('<?php esc_attr_e(
         "Approve",
         "new-user-approve"
     ); ?>').appendTo("select[name='action2']");

					$('<option>').val('deny').text('<?php esc_attr_e(
         "Deny",
         "new-user-approve"
     ); ?>').appendTo("select[name='action']");
					$('<option>').val('deny').text('<?php esc_attr_e(
         "Deny",
         "new-user-approve"
     ); ?>').appendTo("select[name='action2']");
				});
			</script>
			<?php endif;
        }

        /**
         * Process the bulk status updates
         *
         * @uses load-users.php
         */
        public function bulk_action()
        {
            $screen = get_current_screen();

            if ($screen->id == "users") {
                // get the action
                $wp_list_table = _get_list_table("WP_Users_List_Table");
                $action = $wp_list_table->current_action();

                $allowed_actions = ["approve", "deny"];
                if (!in_array($action, $allowed_actions)) {
                    return;
                }

                // security check
                check_admin_referer("bulk-users");

                // make sure ids are submitted
                if (isset($_REQUEST["users"])) {
                    $user_ids = array_map("intval", $_REQUEST["users"]);
                }

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

                $sendback = remove_query_arg(
                    [
                        "approved",
                        "denied",
                        "deleted",
                        "ids",
                        "new_user_approve_filter",
                        "new_user_approve_filter2",
                        "pw-status-query-submit",
                        "new_role",
                    ],
                    wp_get_referer()
                );
                if (!$sendback) {
                    $sendback = admin_url("users.php");
                }

                $pagenum = $wp_list_table->get_pagenum();
                $sendback = add_query_arg("paged", $pagenum, $sendback);

                switch ($action) {
                    case "approve":
                        $approved = 0;
                        foreach ($user_ids as $user_id) {
                            pw_new_user_approve()->update_user_status(
                                $user_id,
                                "approve"
                            );
                            $approved++;
                        }

                        $sendback = add_query_arg(
                            [
                                "approved" => $approved,
                                "ids" => join(",", $user_ids),
                            ],
                            $sendback
                        );
                        break;

                    case "deny":
                        $denied = 0;
                        foreach ($user_ids as $user_id) {
                            pw_new_user_approve()->update_user_status(
                                $user_id,
                                "deny"
                            );
                            $denied++;
                        }

                        $sendback = add_query_arg(
                            [
                                "denied" => $denied,
                                "ids" => join(",", $user_ids),
                            ],
                            $sendback
                        );
                        break;

                    default:
                        return;
                }

                $sendback = remove_query_arg(
                    [
                        "action",
                        "action2",
                        "tags_input",
                        "post_author",
                        "comment_status",
                        "ping_status",
                        "_status",
                        "post",
                        "bulk_edit",
                        "post_view",
                    ],
                    $sendback
                );

                wp_redirect(esc_url($sendback));
                exit();
            }
        }

        /**
         * Show a message on the users page if a status has been updated.
         *
         * @uses admin_notices
         */
        public function admin_notices()
        {
            $screen = get_current_screen();

            if ($screen->id != "users") {
                return;
            }

            $message = null;

            if (isset($_REQUEST["denied"]) && (int) $_REQUEST["denied"]) {
                $denied = sanitize_text_field(wp_unslash($_REQUEST["denied"]));
                // translators: %s is for denied singlular and plural
                $message = sprintf(
                    _n(
                        "%s User denied.",
                        "%s users denied.",
                        $denied,
                        "new-user-approve"
                    ),
                    number_format_i18n($denied)
                );
            }

            if (isset($_REQUEST["approved"]) && (int) $_REQUEST["approved"]) {
                $approved = sanitize_text_field(
                    wp_unslash($_REQUEST["approved"])
                );
                // translators: %s is for approved singlular and plural
                $message = sprintf(
                    _n(
                        "%s User approved.",
                        "%s users approved.",
                        $approved,
                        "new-user-approve"
                    ),
                    number_format_i18n($approved)
                );
            }

            if (!empty($message)) {
                echo wp_kses_post(
                    '<div class="updated"><p>' . $message . "</p></div>"
                );
            }
        }

        /**
         * Display the dropdown on the user profile page to allow an admin to update the user status.
         *
         * @uses show_user_profile
         * @uses edit_user_profile
         * @param object $user
         */
        public function profile_status_field($user)
        {
            if ($user->ID == get_current_user_id()) {
                return;
            }

            $user_status = pw_new_user_approve()->get_user_status($user->ID);
            ?>
		<table class="form-table">
			<tr>
				<th><label for="new_user_approve_status"><?php esc_html_e(
        "Access Status",
        "new-user-approve"
    ); ?></label>
				</th>
				<td>
				<?php wp_nonce_field("nua_approve_status_action", "nua_approve_status_nonce"); ?>

					<select id="new_user_approve_status" name="new_user_approve_status">
						<?php if ($user_status == "pending"): ?>
							<option value=""><?php esc_html_e(
           "-- Status --",
           "new-user-approve"
       ); ?></option>
						<?php endif; ?>
						<?php foreach (["approve", "deny"] as $status): ?>
							<option
								value="<?php echo esc_attr($status); ?>"<?php selected(
    $status,
    $user_status
); ?>><?php echo esc_html(ucfirst($status)); ?></option>
						<?php endforeach; ?>
					</select>
					<span
						class="description"><?php esc_html_e(
          "If user has access to sign in or not.",
          "new-user-approve"
      ); ?></span>
					<?php if ($user_status == "pending"): ?>
						<br/>
						<span class="description">
						<?php // translators: %s is for user pending status
      printf(
          esc_html__("Current user status is %s", "new-user-approve"),
          "<strong>" . esc_html($user_status) . "</strong>"
      ); ?>
						</span>
					<?php endif; ?>
				</td>
			</tr>
		</table>
		<?php
        }

        /**
         * Save the user status when updating from the user profile.
         *
         * @uses edit_user_profile_update
         * @param int $user_id
         * @return bool
         */
        public function save_profile_status_field($user_id)
        {
            if (!current_user_can("edit_user", $user_id)) {
                return false;
            }
            if (
                isset($_POST["nua_approve_status_nonce"]) &&
                wp_verify_nonce(
                    $_POST["nua_approve_status_nonce"],
                    "nua_approve_status_action"
                )
            ) {
                if (!empty($_POST["new_user_approve_status"])) {
                    $new_status = sanitize_text_field(
                        wp_unslash($_POST["new_user_approve_status"])
                    );

                    if ($new_status == "approved") {
                        $new_status = "approve";
                    } elseif ($new_status == "denied") {
                        $new_status = "deny";
                    }

                    pw_new_user_approve()->update_user_status(
                        $user_id,
                        $new_status
                    );
                }
            }
        }

        /**
         * Add bubble for number of users pending to the user menu
         *
         * @uses admin_menu
         */
        public function pending_users_bubble()
        {
            global $menu;

            // Get the count stored in the option
            $users = get_option("new_user_approve_user_statuses_count", []);

            // If option is empty, initialize it
            if (empty($users)) {
                $users = pw_new_user_approve()->_get_user_statuses();
            }

            // Fetch the actual count of pending users from the database
            global $wpdb;
            $actual_pending_users = $wpdb->get_var(
                "SELECT COUNT(*) FROM $wpdb->users 
				 WHERE ID IN (
					SELECT user_id FROM $wpdb->usermeta 
					WHERE meta_key = 'pw_user_status' AND meta_value = 'pending'
				 )"
            );

            // If the stored count is incorrect, update it
            if ($users["pending"] != $actual_pending_users) {
                $users["pending"] = $actual_pending_users;
                update_option("new_user_approve_user_statuses_count", $users);
            }

            // Make sure there are pending users
            if ($actual_pending_users > 0) {
                // Locate the key of users.php in the menu
                $key = $this->recursive_array_search("users.php", $menu);

                // Not found, just in case
                if (!$key) {
                    return;
                }

                // Modify menu item
                // phpcs:ignore
                $menu[$key][0] .= sprintf(
                    '<span class="update-plugins dddd count-%1$s" style="background-color:white;color:black;margin-left:5px;">
						<span class="plugin-count">%1$s</span>
					</span>',
                    $actual_pending_users
                );
            }
        }

        /**
         * Recursively search the menu array to determine the key to place the bubble.
         *
         * @param $needle
         * @param $haystack
         * @return bool|int|string
         */
        public function recursive_array_search($needle, $haystack)
        {
            foreach ($haystack as $key => $value) {
                $current_key = $key;
                if (
                    $needle === $value ||
                    (is_array($value) &&
                        $this->recursive_array_search($needle, $value) !==
                            false)
                ) {
                    return $current_key;
                }
            }
            return false;
        }
    }
}
// phpcs:ignore
function pw_new_user_approve_user_list()
{
    return Pw_New_User_Approve_User_List::instance();
}

pw_new_user_approve_user_list();
