<?php
/**
 * Email Verification
 */

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! class_exists( 'OPL_Email_Verification' ) ) {

    class OPL_Email_Verification {

        /**
         * Ocean_Popup_Login The single instance of Ocean_Popup_Login.
         *
         * @var     object
         * @access  private
         * @since   2.2.1
         */
        private static $_instance = null;

        /**
         * Constructor function.
         *
         * @access  public
         * @since   2.2.1
         * @return  void
         */
        public function __construct() {
            add_filter('query_vars', array( $this, 'verify_email_query_var' ) );
            add_action('template_redirect', array( $this, 'handle_email_verification' ) );
            add_filter('wp_authenticate_user', array( $this, 'check_user_verification_status' ), 10, 2 );

            if (true === get_theme_mod('opl_user_email_verification', false)) {
                add_filter('manage_users_columns', array( $this, 'opl_add_user_verification_column' ) );
                add_action('manage_users_custom_column', array( $this, 'opl_show_user_verification_column' ), 10, 3 );
                add_filter('user_row_actions', array( $this, 'add_resend_verification_link' ), 10, 2);
                add_action('wp_ajax_opl_resend_verification', array($this, 'send_verification_email_to_user'));
                add_action('wp_enqueue_scripts', array($this, 'opl_user_email_verification_status_popup' ));
                add_action('admin_enqueue_scripts', array( $this, 'admin_scripts' ) );
                add_action('wp_ajax_opl_toggle_user_verification', array($this, 'handle_user_verification_toggle'));
                add_action('wp_ajax_opl_check_email_verified', array( $this, 'opl_check_email_verified' ));
                add_action('wp_ajax_nopriv_opl_check_email_verified', array( $this, 'opl_check_email_verified' ));
            }
        }

        public function verify_email_query_var($vars) {

            $vars[] = 'verify_email';
            $vars[] = 'id';
            $vars[] = 'auth';
            $vars[] = '_wpnonce';

            return $vars;
        }

        public function handle_email_verification() {

            if (absint(get_query_var('verify_email')) === 1) {

                $user_id = absint(get_query_var('id'));
                $token   = sanitize_text_field(get_query_var('auth'));

                $register_redirect = get_theme_mod( 'opl_popup_register_redirect' );

                $saved_token = get_user_meta($user_id, 'email_verification_token', true);

                if ($user_id && $token) {

                    $saved_token = get_user_meta($user_id, 'email_verification_token', true);
                    $token_timestamp = get_user_meta($user_id, '_email_verification_token_timestamp', true);

                    $expiry_seconds = self::opl_verification_link_expiry_time();

                    $token_timestamp = (int) $token_timestamp;

                    if ($token === $saved_token && (time() - $token_timestamp) <= $expiry_seconds) {
                        update_user_meta($user_id, 'email_verified', 'true');
                        delete_user_meta($user_id, 'email_verification_token');
                        delete_user_meta($user_id, '_email_verification_token_timestamp');

                        do_action( 'opl_after_email_verification_success', $user_id );

                        $user_data = get_userdata($user_id);

                        Ocean_Popup_Login::opl_log_user_in($user_id, $user_data->user_login, null);

                        setcookie('email_verification_done', 'success', time() + 600, "/");

                        if ( ! empty( $register_redirect ) ) {
                            $url = strpos( $register_redirect, '?' ) === false
                                ? $register_redirect . '/?email-verification=success'
                                : $register_redirect . '&email-verification=success';

                            wp_redirect( $url );
                            do_action( 'opl_after_email_verification_success_redirection', $user_id );
                            exit;
                        } else {
                            wp_redirect(home_url('/?email-verification=success'));
                            do_action( 'opl_after_email_verification_success_redirection', $user_id );
                            exit;
                        }
                    } else {
                        setcookie('email_verification_done', 'expired', time() + 600, "/");
                        wp_redirect(home_url('/?email-verification=link-expired'));
                        do_action( 'opl_after_email_verification_link_expired', $user_id );
                        exit;
                    }
                }

                setcookie('email_verification_done', 'fail', time() + 600, "/");
                wp_redirect(home_url('/?email-verification=fail'));
                do_action( 'opl_after_email_verification_fail', $user_id );
                exit;
            }
        }

        public function check_user_verification_status($user, $password) {

            $excluded_roles = Ocean_Popup_Login::opl_excludes_roles_from_verification();

            if ( ! empty( $user->roles ) && array_intersect( $user->roles, $excluded_roles ) ) {
                return $user;
            }

            if (!is_wp_error($user)) {

                $is_verified = get_user_meta($user->ID, 'email_verified', true);

                if ( $is_verified === '' || $is_verified === null ) {
                    return $user;
                }

                if ($is_verified === 'false') {
                    return new WP_Error('not_verified', __('<strong>Error:</strong> Please verify your email before logging in.', 'ocean-popup-login'));
                }

            }

            return $user;
        }

        public function opl_add_user_verification_column($columns) {

            if ( true === get_theme_mod('opl_admin_user_email_verification_status', true) ) {
                $columns['email_verification'] = __('Verified', 'ocean-popup-login');
            }

            return $columns;
        }

        public function opl_show_user_verification_column($value, $column_name, $user_id) {
            if ($column_name == 'email_verification') {
                ob_start();

                $email_verified = get_user_meta($user_id, 'email_verified', true);

                $checked = $email_verified == 'true' ? 'checked' : '';

                ?>

                <label class="opl-default-user-status-switch" id="opl-default-status-user_lab-<?php echo esc_attr($user_id); ?>">
                    <input
                        class="opl-status-user"
                        id="opl-status-user-<?php echo esc_attr($user_id); ?>"
                        type="checkbox"
                        value="<?php echo esc_attr($user_id); ?>"
                        <?php echo esc_attr($checked); ?>
                        data-user-id="<?php echo esc_attr($user_id); ?>"
                        data-nonce="<?php echo esc_attr(wp_create_nonce('opl_toggle_user_verification')); ?>"
                    >
                    <span class="opl-slider">
                        <span><?php esc_html__('Yes', 'ocean-popup-login'); ?></span>
                        <span><?php esc_html__('No', 'ocean-popup-login'); ?></span>
                    </span>
                    <a>&nbsp;</a>
                </label>

                <?php

                return ob_get_clean();
            }

            return $value;
        }

        public function handle_user_verification_toggle() {
            // Verify nonce
            if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'opl_toggle_user_verification')) {
                wp_send_json_error(array(
                    'message' => __('Nonce verification failed.', 'ocean-popup-login')
                ));
            }

            // Ensure required data is provided
            if (!isset($_POST['user_id']) || !isset($_POST['is_verified'])) {
                wp_send_json_error(array(
                    'message' => __('Missing parameters.', 'ocean-popup-login')
                ));
            }

            $user_id = intval($_POST['user_id']);
            $is_verified = sanitize_text_field($_POST['is_verified']);

            // Ensure user exists
            if (!get_user_by('ID', $user_id)) {
                wp_send_json_error(array(
                    'message' => __('User not found.', 'ocean-popup-login')
                ));
            }

            update_user_meta($user_id, 'email_verified', $is_verified);

            wp_send_json_success(array(
                'message' => __('User verification status updated.', 'ocean-popup-login')
            ));
        }

        public function send_verification_email_to_user() {

            if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'opl_resend_verification_nonce')) {
                wp_send_json_error(array(
                    'message' => __('Nonce verification failed.', 'ocean-popup-login')
                ));
            }

            if (!isset($_POST['user_id'])) {
                wp_send_json_error(array(
                    'message' => __('User ID is missing.', 'ocean-popup-login')
                ));
            }

            $user_id = intval($_POST['user_id']);

            $user = get_user_by('ID', $user_id);
            if (!$user) {
                wp_send_json_error(array(
                    'message' => __('User not found.', 'ocean-popup-login')
                ));
            }

            $verification_url = self::generate_verification_url($user_id);

            $subject = __('Email Verification', 'ocean-popup-login');

            $message  = esc_html__('Hi there,', 'ocean-popup-login') . "\r\n\r\n";
            /* translators: %s is replaced with the site name from get_option( 'blogname' ). */
            $message .= sprintf( esc_html__( "Welcome to %s!", 'ocean-popup-login' ), get_option( 'blogname' ) ) . "\r\n\r\n";
            $message .= esc_html__('To complete your registration, kindly verify your email by following the link provided:', 'ocean-popup-login') . "\r\n\r\n";
            $message .= wp_specialchars_decode(esc_url_raw($verification_url)) . "\r\n\r\n";
            $message .= esc_html__('Thank you!', 'ocean-popup-login');

            $message = apply_filters( 'opl_email_content_for_resend_verification', $message, $user_id, wp_specialchars_decode(esc_url_raw($verification_url)) );

            $sent = wp_mail($user->user_email, $subject, $message);

            $email_verified = get_user_meta($user_id, 'email_verified', true);

            update_user_meta($user_id, 'email_verified', 'false');

            do_action( 'opl_after_resend_verification_link', $user_id );

            if ($sent) {
                wp_send_json_success(array(
                    'message' => __('Verification email sent successfully.', 'ocean-popup-login')
                ));
            } else {
                wp_send_json_error(array(
                    'message' => __('Failed to send verification email.', 'ocean-popup-login')
                ));
            }
        }

        public function opl_check_email_verified() {
            $verification_status = isset($_COOKIE['email_verification_done']) ? $_COOKIE['email_verification_done'] : null;

            setcookie('email_verification_done', '', time() - 3600, "/");

            wp_send_json_success(['verification_done' => $verification_status]);
        }

        public function admin_scripts($hook) {
            if ($hook === 'users.php') {
                wp_enqueue_style(
                    'opl-admin-user-style',
                    plugins_url( '/assets/css/admin.min.css', __DIR__ ),
                    array(),
                    false
                );

                wp_enqueue_script(
                    'opl-admin-user-verification',
                    plugins_url( '/assets/js/email-verification.min.js', __DIR__ ),
                    array('jquery'),
                    null,
                    true
                );

                wp_localize_script('opl-admin-user-verification', 'oplAdmin', array(
                    'ajax_url' => admin_url('admin-ajax.php'),
                    'nonce'    => wp_create_nonce('opl_nonce')
                ));
            }
        }

        public function add_resend_verification_link($actions, $user) {

            $current_user_id = get_current_user_id();

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

            ob_start();
            ?>
            <div id="opl-resend-email-<?php echo esc_attr($user->ID); ?>" class="opl-resend-container">
                <a
                    class="opl-verification-link"
                    href="#"
                    data-user-id="<?php echo esc_attr($user->ID); ?>"
                    data-nonce="<?php echo esc_attr(wp_create_nonce('opl_resend_verification_nonce')); ?>"
                >
                    <?php echo esc_html__('Resend Verification', 'ocean-popup-login'); ?>
                </a>

                <span class="opl-spinner dashicons dashicons-update" style="display: none;"></span>
                <span class="opl-success dashicons dashicons-yes" style="display: none; color: green;"></span>
                <span class="opl-error" style="display: none; color: red;">
                    <?php echo esc_html__('Failed to send. ', 'ocean-popup-login'); ?>
                    <a
                        class="opl-verification-link"
                        href="#"
                        data-user-id="<?php echo esc_attr($user->ID); ?>"
                        data-nonce="<?php echo esc_attr(wp_create_nonce('opl_resend_verification_nonce')); ?>"
                    >
                        <?php echo esc_html__('Try again', 'ocean-popup-login'); ?>
                    </a>
                </span>
            </div>

            <?php
            $resend_verification_html = ob_get_clean();

            $actions['oplresendemailverification'] = $resend_verification_html;

            return ($actions) ;
        }

        public static function generate_verification_url($user_id) {

            if ( ! $user_id ) {
                return;
            }

            if ( true !== get_theme_mod('opl_user_email_verification', false) ) {
                return;
            }

            $expiry_seconds = self::opl_verification_link_expiry_time();

            $email_verified = get_user_meta($user_id, 'email_verified', true);
            $unique_key = get_user_meta($user_id, 'email_verification_token', true);
            $token_timestamp = get_user_meta($user_id, '_email_verification_token_timestamp', true);

            $token_timestamp = (int) $token_timestamp;

            if ( !$unique_key || $token_timestamp === 0 || (time() - $token_timestamp) > $expiry_seconds) {
                $unique_key = md5(uniqid(bin2hex(random_bytes(16)), true));
                update_user_meta($user_id, 'email_verification_token', $unique_key);
                update_user_meta($user_id, '_email_verification_token_timestamp', time());
            }

            update_user_meta($user_id, 'email_verified', 'false');

            $base_url = add_query_arg(array(
                'verify_email' => 1,
                'id' => $user_id,
                'auth' => $unique_key,
            ), site_url());

            return wp_nonce_url($base_url, 'email_verification_' . $unique_key);
        }

        /**
         * Get the expiry time in seconds based on the type and value.
         *
         * @since 2.2.1
         * @return int Expiry time in seconds.
         */
        public static function opl_verification_link_expiry_time() {

            $expiry_type = get_theme_mod('opl_user_email_verification_expiry_type', 'hour');
            $expiry_value = get_theme_mod('opl_user_email_verification_expiry_time', 12);

            $expiry_seconds = 0;

            switch ($expiry_type) {
                case 'second':
                    $expiry_seconds = (int) $expiry_value;
                    break;
                case 'minute':
                    $expiry_seconds = (int) $expiry_value * 60;
                    break;
                case 'hour':
                    $expiry_seconds = (int) $expiry_value * 3600;
                    break;
                case 'day':
                    $expiry_seconds = (int) $expiry_value * 86400;
                    break;
                default:
                    $expiry_seconds = (int) $expiry_value * 3600;
                    break;
            }

            return apply_filters('opl_verification_link_expiry_time', $expiry_seconds, $expiry_type, $expiry_value);
        }


        public function opl_user_email_verification_status_popup() {

            if ( isset( $_GET['email-verification'] ) ) {

                wp_enqueue_style(
                    'email-verification-popup',
                    plugins_url( '/assets/css/email-verification-popup.min.css', __DIR__ ),
                    array(),
                    false
                );

                wp_enqueue_script(
                    'email-verification-popup',
                    plugins_url( '/assets/js/email-verification-popup.min.js', __DIR__ ),
                    array(),
                    null,
                    true
                );

                /* translators: %s is replaced with the site name from get_option( 'blogname' ). */
                $success_default = sprintf( __( 'Verification successfully completed. Welcome to %s', 'ocean-popup-login' ), get_bloginfo( 'name' ) );
                /* translators: %s is replaced with admin email. */
                $failed_default = sprintf( __( 'Ooops, we were unable to verify your email. Reach us at %s to report an issue and request a new verification link.', 'ocean-popup-login' ), get_theme_mod( 'opl_email_content_admin_email', get_option( 'admin_email' ) ) );
                /* translators: %s is replaced with admin email. */
                $expired_default = sprintf( __( 'Ooops, your verification link has expired. Reach us at %s to request a new verification link.', 'ocean-popup-login' ), get_theme_mod( 'opl_email_content_admin_email', get_option( 'admin_email' ) ) );

                $msgSuccess = get_theme_mod( 'opl_email_verification_status_success_notice', $success_default );
                $msgFailed  = get_theme_mod( 'opl_email_verification_status_failed_notice', $failed_default );
                $msgExpired = get_theme_mod( 'opl_email_verification_status_expired_notice', $expired_default );

                wp_localize_script('email-verification-popup', 'oplEmailVerificationPopup', array(
                    'ajax_url'   => admin_url('admin-ajax.php'),
                    'msgSuccess' => $msgSuccess,
                    'msgFailed'  => $msgFailed,
                    'msgExpired' => $msgExpired
                ));
            }
        }

    }

    new OPL_Email_Verification();
}
