<?php
/**
 * Frontend campaign renderer.
 *
 * @package SwairishXHeaderBarNotificationOffer
 */

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

class SwairishX_Renderer {
    private $storage;

    public function __construct(SwairishX_Storage $storage) {
        $this->storage = $storage;
    }

    public function hooks() {
        add_action('wp_enqueue_scripts', array($this, 'assets'));
        add_action('wp_body_open', array($this, 'render_top'));
        add_action('wp_footer', array($this, 'render_footer'));
    }

    public function assets() {
        if (!$this->storage->campaigns(array('publish'))) {
            return;
        }
        wp_enqueue_style('swairishx-frontend', SWAIRISHX_URL . 'assets/css/frontend-v2.css', array(), SWAIRISHX_VERSION);
        wp_enqueue_script('swairishx-frontend', SWAIRISHX_URL . 'assets/js/frontend.js', array(), SWAIRISHX_VERSION, true);
        wp_localize_script('swairishx-frontend', 'SwairishXRuntime', array(
            'ajaxUrl' => admin_url('admin-ajax.php'),
            'action' => 'swairishx_track',
            'token' => wp_create_nonce('swairishx_public_tracking'),
            'reducedMotion' => __('Animations are reduced by your browser preference.', 'swairish-header-bar-offer-notifications'),
        ));
    }

    public function render_top() {
        $this->render_position('top');
    }

    public function render_footer() {
        $this->render_position('bottom');
        do_action('swairishx_custom_display_location', $this);
    }

    public function render_position($position) {
        $campaigns = apply_filters('swairishx_render_campaigns', $this->storage->campaigns(array('publish')), $position);
        foreach ($campaigns as $post) {
            $config = $this->storage->get_campaign($post->ID);
            if (!$config || $position !== $config['position'] || !$this->eligible($config)) {
                continue;
            }
            echo wp_kses($this->render($post->ID, $config), $this->notice_allowed_html());
        }
    }

    public function render($campaign_id, array $config) {
        $message = apply_filters('swairishx_notice_message', $this->compose_message($config), $config, $campaign_id);
        $classes = array('swairishx-notice', 'swairishx-' . sanitize_html_class($config['type']), 'swairishx-theme-' . sanitize_html_class($config['theme']));
        if (!empty($config['sticky'])) {
            $classes[] = 'is-sticky';
        }
        $style = sprintf('--swx-bg:%s;--swx-fg:%s;--swx-accent:%s;', esc_attr($config['background']), esc_attr($config['foreground']), esc_attr($config['accent']));
        $cta_url = $this->add_utm($config['cta_url'], $config);
        $deadline = !empty($config['show_countdown']) && !empty($config['end_at']) ? $this->campaign_timestamp($config['end_at']) : 0;
        ob_start();
        ?>
        <aside class="<?php echo esc_attr(implode(' ', $classes)); ?>" style="<?php echo esc_attr($style); ?>" data-swairishx-id="<?php echo esc_attr($campaign_id); ?>" data-notification-type="<?php echo esc_attr($config['type']); ?>" data-position="<?php echo esc_attr($config['position']); ?>" data-tracking="<?php echo esc_attr(!empty($config['tracking']) ? '1' : '0'); ?>" data-delay="<?php echo esc_attr($config['delay_ms']); ?>" data-auto-hide="<?php echo esc_attr($config['auto_hide_ms']); ?>" data-dismiss-hours="<?php echo esc_attr($config['dismiss_hours']); ?>" data-reappearance="<?php echo esc_attr($config['reappearance']); ?>" aria-label="<?php esc_attr_e('Site notification', 'swairish-header-bar-offer-notifications'); ?>" hidden>
            <div class="swairishx-notice__inner">
                <?php if (!empty($config['image_url'])) : ?>
                    <img class="swairishx-notice__image is-<?php echo esc_attr(isset($config['image_position']) ? $config['image_position'] : 'start'); ?>" src="<?php echo esc_url($config['image_url']); ?>" alt="<?php echo esc_attr(isset($config['image_alt']) ? $config['image_alt'] : ''); ?>" width="48" height="48" decoding="async">
                <?php endif; ?>
                <div class="swairishx-notice__copy">
                    <?php if ($config['headline']) : ?><strong><?php echo esc_html($config['headline']); ?></strong><?php endif; ?>
                    <span><?php echo wp_kses_post($message); ?></span>
                    <?php if ($deadline) : ?><time class="swairishx-countdown" data-swairishx-deadline="<?php echo esc_attr($deadline * 1000); ?>" datetime="<?php echo esc_attr($config['end_at']); ?>" aria-live="polite"></time><?php endif; ?>
                </div>
                <?php echo wp_kses(apply_filters('swairishx_notice_extra_html', '', $config, $campaign_id), apply_filters('swairishx_notice_extra_allowed_html', array('video' => array('class' => true, 'controls' => true, 'preload' => true, 'playsinline' => true), 'source' => array('src' => true, 'type' => true)))); ?>
                <?php if ($cta_url && $config['cta_label']) : ?>
                    <a class="swairishx-notice__cta" href="<?php echo esc_url($cta_url); ?>" data-swairishx-click><?php echo esc_html($config['cta_label']); ?></a>
                <?php endif; ?>
                <?php if (!empty($config['coupon_code'])) : ?>
                    <button class="swairishx-notice__coupon" type="button" data-swairishx-coupon data-coupon-code="<?php echo esc_attr($config['coupon_code']); ?>" data-copied-text="<?php echo esc_attr($config['coupon_copied_text']); ?>"><span data-coupon-label><?php echo esc_html($config['coupon_code']); ?></span><span class="swairishx-notice__coupon-status" data-coupon-status aria-live="polite"></span></button>
                <?php endif; ?>
                <?php if (!empty($config['close_button'])) : ?>
                    <button class="swairishx-notice__close" type="button" data-swairishx-dismiss aria-label="<?php esc_attr_e('Dismiss notification', 'swairish-header-bar-offer-notifications'); ?>"><span aria-hidden="true">&times;</span></button>
                <?php endif; ?>
            </div>
        </aside>
        <?php
        return ob_get_clean();
    }

    private function compose_message(array $config) {
        $event = 'manual' === $config['integration'] ? array() : $this->storage->latest_event($config['integration']);
        if (!$event || empty($event['payload'])) {
            return $config['message'];
        }
        $payload = $event['payload'];
        $replace = array(
            '{actor}' => isset($payload['actor']) ? $payload['actor'] : '',
            '{subject}' => isset($payload['subject']) ? $payload['subject'] : '',
            '{location}' => isset($payload['location']) ? $payload['location'] : '',
        );
        $template = $config['message'] ?: __('{actor} recently interacted with {subject}', 'swairish-header-bar-offer-notifications');
        return strtr($template, array_map('esc_html', $replace));
    }

    private function eligible(array $config) {
        if (is_admin() || is_feed() || wp_doing_ajax()) {
            return false;
        }
        $now = current_time('timestamp');
        if ($config['start_at'] && $this->campaign_timestamp($config['start_at']) > $now) {
            return false;
        }
        if ($config['end_at'] && $this->campaign_timestamp($config['end_at']) < $now) {
            return false;
        }
        $request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_url(wp_unslash($_SERVER['REQUEST_URI'])) : '/';
        $path = wp_parse_url($request_uri, PHP_URL_PATH);
        if (!$this->path_matches($path, $config['include_paths'], true)) {
            return false;
        }
        if ($this->path_matches($path, $config['exclude_paths'], false)) {
            return false;
        }
        return (bool) apply_filters('swairishx_campaign_is_eligible', true, $config);
    }

    private function path_matches($path, $rules, $empty_value) {
        if (!$rules) {
            return $empty_value;
        }
        foreach (array_filter(array_map('trim', explode("\n", $rules))) as $rule) {
            $pattern = '#^' . str_replace('\*', '.*', preg_quote($rule, '#')) . '$#';
            if (preg_match($pattern, $path)) {
                return true;
            }
        }
        return false;
    }

    private function add_utm($url, array $config) {
        if (!$url || !$config['utm_source']) {
            return $url;
        }
        return add_query_arg(array(
            'utm_source' => $config['utm_source'],
            'utm_medium' => $config['utm_medium'],
            'utm_campaign' => sanitize_title($config['name']),
        ), $url);
    }

    private function campaign_timestamp($value) {
        try {
            $date = new DateTimeImmutable((string) $value, wp_timezone());
            return $date->getTimestamp();
        } catch (Exception $exception) {
            return 0;
        }
    }

    /**
     * Allowed markup for the final rendered notification.
     *
     * @return array<string, array<string, bool>>
     */
    private function notice_allowed_html() {
        $allowed = array(
            'aside' => array(
                'class' => true,
                'style' => true,
                'data-swairishx-id' => true,
                'data-notification-type' => true,
                'data-position' => true,
                'data-tracking' => true,
                'data-delay' => true,
                'data-auto-hide' => true,
                'data-dismiss-hours' => true,
                'data-reappearance' => true,
                'aria-label' => true,
                'hidden' => true,
            ),
            'div' => array('class' => true),
            'img' => array('class' => true, 'src' => true, 'alt' => true, 'width' => true, 'height' => true, 'decoding' => true),
            'strong' => array(),
            'span' => array('class' => true, 'aria-hidden' => true, 'aria-live' => true, 'data-coupon-label' => true, 'data-coupon-status' => true),
            'time' => array('class' => true, 'data-swairishx-countdown' => true, 'data-swairishx-deadline' => true, 'datetime' => true, 'aria-live' => true),
            'video' => array('class' => true, 'controls' => true, 'preload' => true, 'playsinline' => true),
            'source' => array('src' => true, 'type' => true),
            'a' => array('class' => true, 'href' => true, 'data-swairishx-click' => true),
            'button' => array('class' => true, 'type' => true, 'data-swairishx-dismiss' => true, 'data-swairishx-coupon' => true, 'data-coupon-code' => true, 'data-copied-text' => true, 'aria-label' => true),
        );
        return apply_filters('swairishx_notice_allowed_html', $allowed);
    }
}
