<?php

/**
 * Class for Admin Notifications.
 *
 * @package Terms_And_Conditions_Per_Product
 */

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

// If class exists, then don't execute this.
if ( ! class_exists( 'TACPP4_Terms_Conditions_Admin_Notices' ) ) {
    class TACPP4_Terms_Conditions_Admin_Notices {
        const SEEN_NOTICES_OPTION_NAME = 'tacpp_seen_notices';

        public function __construct() {
            add_action( 'admin_notices', array( $this, 'show_admin_notices' ) );

            add_action( 'wp_ajax_tacpp_hide_notice', array( $this, 'tacpp_hide_notice' ) );

            add_action( 'admin_notices', array( $this, 'show_rate_me_admin_notices' ) );

        }

        /**
         * Returns an array of TACPP admin notices.
         *
         * @return mixed
         */
        public function get_admin_notices() {
            $admin_notices = array(
                'tacpp-premium-notice' => array(
                    'text'     => sprintf(
                        /* translators: %s: The plugin's website URL */
                        __( 'Terms and Conditions per product now have a <a href="%s" target="_blank">premium version</a> that allows <strong>terms and conditions per product category</strong> as well as opening the terms in a <strong>modal</strong>.', 'terms-and-conditions-per-product' ),
                        esc_url( 'https://tacpp-pro.com/' )
                    ),
                    'user_cap' => 'activate_plugins',
                    'is_free'  => true,
                ),
            );

            return apply_filters( 'tacpp4_terms_conditions_admin_notices_get_admin_notices',
                $admin_notices );
        }

        /**
         * Show admin notices.
         */
        public function show_admin_notices() {
            $admin_notices = $this->get_admin_notices();

            if ( ! empty( $admin_notices ) ) {

                $seen_notices = $this->get_seen_notices();

                foreach ( $admin_notices as $notice_id => $notice ) {
                    // Skip for paid users
                    if ( $notice['is_free'] && tacppp_fs()->is_paying_or_trial() ) {
                        continue;
                    } // Skip for free users
                    else if ( ! $notice['is_free'] && ! tacppp_fs()->is_paying_or_trial() ) {
                        continue;
                    }

                    // Skip if notice is already seen
                    if ( in_array( $notice_id, $seen_notices ) ) {
                        continue;
                    }

                    $this->show_admin_notice( $notice, $notice_id );
                }
            }
        }


        /**
         * HTML for admin notice.
         *
         * @param        $notice
         * @param string $notice_id
         */
        public function show_admin_notice( $notice, $notice_id = '' ) {

            if ( is_array( $notice ) ) {
                $text = ( isset( $notice['text'] ) ? wp_kses_post( $notice['text'] ) : '' );
            } else {
                $text = wp_kses_post( $notice );
            }
            ?>
			<div id="<?php echo esc_attr( $notice_id ); ?>" class="tacpp-admin-notice notice notice-success is-dismissible">
				<p><?php echo $text; ?></p>
			</div>
            <?php
        }

        /**
         * Ajax callback to hide admin notices.
         */
        public function tacpp_hide_notice() {
            // Verify nonce — wp_die's on failure.
            check_ajax_referer( 'tacpp-ajax-nonce', 'nonce' );

            // Only admins should be able to dismiss admin notices.
            if ( ! current_user_can( 'activate_plugins' ) ) {
                wp_send_json_error( 'forbidden', 403 );
            }

            $notice_id = isset( $_POST['noticeID'] )
                ? trim( sanitize_text_field( wp_unslash( $_POST['noticeID'] ) ) )
                : '';

            if ( '' === $notice_id ) {
                wp_send_json_error( 'No notice ID' );
            }

            $this->update_seen_notices( $notice_id );

            wp_send_json_success( 'Notice hidden' );
        }

        /**
         * Get an array of all seen notice IDs
         *
         * @return mixed
         */

        public function get_seen_notices() {
            $notices = (array) get_user_meta( get_current_user_id(),
                self::SEEN_NOTICES_OPTION_NAME, true );

            $notices = array_filter( $notices );

            return apply_filters( 'tacpp4_terms_conditions_get_seen_notices',
                $notices );
        }

        /**
         * Update seen notices in DB so they do not appear again
         *
         * @param $notice_id
         */
        public function update_seen_notices( $notice_id ) {
            $notice_id    = sanitize_text_field( $notice_id );
            $seen_notices = $this->get_seen_notices();

            // Add notice to hidden notices
            if ( ! in_array( $notice_id, $seen_notices ) ) {
                $seen_notices[] = $notice_id;
            }

            $seen_notices = array_filter( $seen_notices );

            // Update DB option
            update_user_meta(
                get_current_user_id(),
                self::SEEN_NOTICES_OPTION_NAME,
                $seen_notices
            );
        }

        /**
         * Returns an array of TACPP admin notices.
         *
         * @return mixed
         */
        public function get_rate_me_admin_notices() {
            $text = "<p>" . __( '<strong>Awesome!</strong> You have added <strong>[number] custom Terms and Conditions</strong> to your products using the <strong>Terms and Conditions Per Product</strong> plugin. Would you <strong>help us spread the word</strong> by giving it a <strong>5-star rating</strong> on WordPress?', 'terms-and-conditions-per-product' ) . "</p>";
            /* translators: %s: The WP plugin directory link to reviews */
            $text .= "<p>" . sprintf( __( '<a href="%s" target="_blank">Ok, you deserve it.</a>', 'terms-and-conditions-per-product' ), esc_url( 'https://wordpress.org/support/plugin/terms-and-conditions-per-product/reviews/#new-post' ) ) . "<br>";
            $text .= "<a href='#' class='close-notice'>" . __( 'Already did.', 'terms-and-conditions-per-product' ) . "</a></p>";

            $admin_notices = array(
                'tacpp-rate-me-notice' => array(
                    'text'     => $text,
                    'user_cap' => 'manage_options',
                ),
            );

            return apply_filters( 'tacpp4_terms_conditions_admin_notices_get_admin_notices',
                $admin_notices );
        }

        /**
         * Show Rate Me Admin notices.
         */
        public function show_rate_me_admin_notices() {
            $show_after_times = array( 5, 20, 50 );

            // Bail out before touching the DB if the user has already
            // dismissed every threshold. Cuts the COUNT query out of
            // every admin pageload once the user has clicked through.
            $seen_notices = $this->get_seen_notices();
            $pending      = array();
            foreach ( $show_after_times as $after_time ) {
                if ( ! in_array( 'tacpp-rate-me-notice-' . $after_time, $seen_notices, true ) ) {
                    $pending[] = $after_time;
                }
            }
            if ( empty( $pending ) ) {
                return;
            }

            $counter = $this->get_custom_terms_count();

            // Filter array to only show notices after certain number of terms.
            foreach ( $pending as $key => $after_time ) {
                if ( $counter < $after_time ) {
                    unset( $pending[ $key ] );
                }
            }
            if ( empty( $pending ) ) {
                return;
            }

            $admin_notices = $this->get_rate_me_admin_notices();
            if ( empty( $admin_notices ) ) {
                return;
            }

            foreach ( $admin_notices as $base_notice_id => $notice ) {
                foreach ( $pending as $show_after_time ) {

                    // Build the per-threshold id from the base each pass so
                    // we don't compound "-5-20-50" across iterations.
                    $notice_id = $base_notice_id . '-' . $show_after_time;
                    $text      = str_replace( '[number]', $show_after_time, $notice['text'] );

                    $this->show_admin_notice( $text, $notice_id );
                }
            }
        }

        /**
         * Get the count of products with custom terms, cached in a transient
         * so we don't scan postmeta on every admin pageload.
         *
         * @return int
         */
        private function get_custom_terms_count() {
            $counter = get_transient( 'tacpp_custom_terms_count' );
            if ( false !== $counter ) {
                return (int) $counter;
            }

            global $wpdb;
            // Meta key is filterable so it must pass through $wpdb->prepare()
            // to avoid SQL injection from add-ons.
            $counter = (int) $wpdb->get_var( $wpdb->prepare(
                "SELECT COUNT(meta_id) FROM {$wpdb->postmeta} WHERE meta_key = %s AND meta_value != ''",
                TACPP4_Terms_Conditions_Per_Product::$meta_key
            ) );

            set_transient( 'tacpp_custom_terms_count', $counter, HOUR_IN_SECONDS );

            return $counter;
        }

    }

    new TACPP4_Terms_Conditions_Admin_Notices();
}
