<?php

namespace CleantalkSP\SpbctWP\AdminBannersModule;

use CleantalkSP\SpbctWP\AdminBannersModule\AdminBanners\AdminBannerReview;
use CleantalkSP\SpbctWP\AdminBannersModule\AdminBanners\AdminBannerTrialAndRenew;
use CleantalkSP\SpbctWP\AdminBannersModule\AdminBanners\AdminBannerWrongKey;
use CleantalkSP\SpbctWP\AdminBannersModule\AdminBanners\AdminBannerEmptyKey;
use CleantalkSP\SpbctWP\AdminBannersModule\AdminBanners\AdminBannerCriticalFilesWarning;
use CleantalkSP\SpbctWP\AdminBannersModule\AdminBanners\AdminBannerFileEditorDashboard;
use CleantalkSP\SpbctWP\AdminBannersModule\AdminBanners\AdminBannerFileEditorSettings;
use CleantalkSP\SpbctWP\AdminBannersModule\AdminBanners\AdminBannerPassLeak;
use CleantalkSP\SpbctWP\AdminBannersModule\AdminBanners\AdminBannerTrialAndRenewFullpage;
use CleantalkSP\SpbctWP\API;
use CleantalkSP\SpbctWP\Sanitize;
use CleantalkSP\SpbctWP\State;
use CleantalkSP\Variables\Post;
use CleantalkSP\Variables\Server;

/**
 * Description
 */
class AdminBannersHandler
{
    /**
     * @type State
     * @var object $spbc
     */
    public $spbc;

    /**
     * @var string $user_token
     */
    private $user_token;

    /**
     * @var int $user_id
     */
    private $user_id;

    /**
     * @var array $banners_register
     */
    private $banners_register;

    /**
     * @var string
     */
    private $plugin_settings_tag_link;

    /**
     * @var string
     */
    private $plugin_settings_link;

    public function __construct(State $spbc)
    {
        $this->spbc                 = $spbc;
        $this->user_token           = $this->spbc->user_token ?: '';
        $this->user_id              = get_current_user_id();
        $this->plugin_settings_tag_link = '<a href="'
                                      . (is_network_admin() ? 'settings.php' : 'options-general.php') .
                                      '?page=spbc">'
                                      . $spbc->data["wl_brandname"] .
                                      '</a>';
        $this->plugin_settings_link = (is_network_admin() ? 'settings.php' : 'options-general.php') . '?page=spbc';

        // The register of banners
        $this->banners_register = array(
            AdminBannerTrialAndRenew::class,
            AdminBannerWrongKey::class,
            AdminBannerEmptyKey::class,
            AdminBannerReview::class,
            AdminBannerCriticalFilesWarning::class,
            AdminBannerFileEditorDashboard::class,
            AdminBannerFileEditorSettings::class,
            AdminBannerPassLeak::class,
        );
    }

    /**
     * Launches an array of admin banners to display.
     * Prepare common data for banners.
     */
    public function handle()
    {
        add_action('admin_notices', function () {
            if ( $this->isFullpageTrialBannerActive() ) {
                return;
            }
            foreach ( $this->banners_register as $banner_class ) {
                $banner = new $banner_class($this);
                $banner->show();
            }
        });
        add_action('network_admin_notices', function () {
            if ( $this->isFullpageTrialBannerActive() ) {
                return;
            }
            foreach ( $this->banners_register as $banner_class ) {
                $banner = new $banner_class($this);
                $banner->show();
            }
        });
        add_action('wp_ajax_spbc_dismiss_banner', array($this, 'dismissBanner'));
        add_filter('cleantalk_admin_bar__parent_node__after', array($this, 'addAttentionMark'), 20, 1);
    }

    /**
     * Check if fullpage trial banner is active on the settings page.
     * If so, all other banners should be suppressed.
     *
     * Since the fullpage trial banner dismiss state is now managed client-side
     * via sessionStorage, we cannot reliably suppress other banners server-side.
     * Other banners will be visually hidden by the fullpage overlay when it is shown.
     *
     * @return bool
     */
    private function isFullpageTrialBannerActive()
    {
        return false;
    }

    public function getUserId()
    {
        return $this->user_id;
    }

    public function getUserToken()
    {
        return $this->user_token;
    }

    /**
     * @psalm-suppress PossiblyUnusedMethod
     */
    public function getPluginSettingsTagLink()
    {
        return $this->plugin_settings_tag_link;
    }

    public function getPluginSettingsLink()
    {
        return $this->plugin_settings_link;
    }

    public function dismissBanner()
    {
        global $spbc;

        $banner_id = Sanitize::cleanTextField(Post::getString('banner_id'));

        if ( ! $banner_id || strpos($banner_id, 'spbc_') !== 0 ) {
            wp_send_json_error(esc_html__('Wrong request.', 'security-malware-firewall'));
        }

        // Validate format: spbc_<banner_name>_<user_id> and extract user_id
        if ( ! preg_match('/^spbc_\w+_(\d+)$/', $banner_id, $matches) ) {
            wp_send_json_error(esc_html__('Wrong request.', 'security-malware-firewall'));
        }

        if ( !isset($matches[1]) || $matches[1] != $this->getUserId() ) {
            wp_send_json_error(esc_html__('Wrong request.', 'security-malware-firewall'));
        }

        // Password leak banners can be closed by non-admin users (Author+),
        // but only nonce + logged-in check is needed for those.
        // All other banners require admin capabilities.
        if ( strpos($banner_id, 'spbc_passleak') === 0 ) {
            /** @psalm-suppress ForbiddenCode */
            if (!check_ajax_referer('spbc_secret_nonce', 'security')) {
                wp_send_json_error(esc_html__('Wrong request.', 'security-malware-firewall'));
            }
        } else {
            spbc_check_ajax_referer('spbc_secret_nonce', 'security');
        }

        if ( update_option($banner_id, current_time('Y-m-d')) ) {
            if ( strpos($banner_id, 'spbc_review') !== false ) {
                $api_update = API::methodUserDataUpdate($spbc->data['user_token'], json_encode(['show_review' => 0]));
                if ( isset($api_update['error']) ) {
                    wp_send_json_error($api_update['error']);
                }
            }
            wp_send_json_success();
        } else {
            wp_send_json_error(esc_html__('Notice status not updated.', 'security-malware-firewall'));
        }
    }

    public function addAttentionMark($after)
    {
        global $spbc;
        if ( self::adminBarHasExclamationDueBanners($spbc) ) {
            return $after . '<i class="spbc-icon-attention-alt"></i>';
        }

        return $after;
    }

    public function isOnSpbcSettingsPage()
    {
        return Server::hasString('REQUEST_URI', 'page=spbc');
    }

    /**
     * Get JSON representation of post notices.
     *
     * This function returns a JSON-encoded string of post notices. Each notice contains
     * a dismissed banner name, notice level (css-class-like), and post-notice text.
     *
     * @return string JSON-encoded string of post notices.
     */
    public static function getJSONOfPostNotices()
    {
        $notices = array(
            '0' => array(
                'bannerName' => 'spbc_critical_files_warning',
                'noticeLevel' => 'notice-error',
                'postNoticeText' => esc_html__('Dismissed. Please, visit your Wordpress Security dashboard anytime to get the current health status.', 'security-malware-firewall')
            ),
        );
        $notices = json_encode($notices);
        return !empty($notices) ? $notices : '{}';
    }

    /**
     * @param State $spbc
     *
     * @return bool
     */
    public static function adminBarHasExclamationDueBanners($spbc)
    {
        if (!$spbc instanceof State || !$spbc->notice_show) {
            return false;
        }
        $user_id = get_current_user_id();

        $banners = array(
            'trial' => array(
                'has_flag' => $spbc->notice_trial,
                'is_dismissed' => (
                    isset($spbc->data['dismissed_banners']['trial'][$user_id])
                )
            ),
            'renew' => array(
                'has_flag' => $spbc->notice_renew,
                'is_dismissed' => (
                    isset($spbc->data['dismissed_banners']['renew'][$user_id])
                )
            ),
            'critical_files_warning' => array(
                'has_flag' => $spbc->notice_critical_files_warning,
                'is_dismissed' => (
                    isset($spbc->data['dismissed_banners']['critical_files_warning'][$user_id])
                )
            ),
        );

        foreach ($banners as $_data) {
            if ($_data['has_flag'] && !$_data['is_dismissed']) {
                return true; // Show exclaim if at least one banner is not dismissed
            }
        }

        return false; // No banners require attention
    }

    /**
     * @param string $banner_type
     * @param int|string $user_id
     * @param bool $remove
     *
     * @return void
     */
    public static function updateDismissedBannerData($banner_type, $user_id, $remove = false)
    {
        global $spbc;
        $user_id = (int) $user_id;

        if (!$banner_type || !$user_id) {
            return;
        }
        $dismissed_banners_data = $spbc->data['dismissed_banners'];

        if (!$remove) {
            if (empty($dismissed_banners_data[$banner_type][$user_id])) {
                $dismissed_banners_data[$banner_type][$user_id] = true;
            }
        } elseif (isset($dismissed_banners_data[$banner_type][$user_id])) {
            unset($dismissed_banners_data[$banner_type][$user_id]);
        }

        if ($dismissed_banners_data !== $spbc->data['dismissed_banners']) {
            $spbc->data['dismissed_banners'] = $dismissed_banners_data;
            $spbc->save('data');
        }
    }
}
