<?php
declare(strict_types=1);

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

/**
 * Countdown block renderer (shared frontend + editor).
 *
 * Emits the `.impulse-countdown` carrier that assets/js/impulse-countdown.js
 * builds and ticks. One look, procedural: a typographic readout whose digits
 * roll one way on every change, optionally wrapped in two counter-rotating
 * circles of live label text. Flip, odometer and drops retired 2026-08-05.
 *
 * Settings (stored on the element):
 *   cd_epoch    absolute target, ms since epoch (picked in the owner's local
 *               time in the panel, stored absolute - every visitor counts to
 *               the same moment). Missing/past-invalid => now + 7 days, so a
 *               freshly dropped block ticks immediately.
 *   cd_rings    1 = wrap the readout in the circling text (default on)
 *   cd_labels_on 1 = show DAYS/HOURS/... under the digits (default on)
 *   cd_units    csv of d,h,m,s                    (default all four)
 *   cd_labels   JSON {d,h,m,s}                    (default Days/Hours/...)
 *   cd_ring     the circling label text (cd_rings only)
 *   cd_size     digit font px 20-220              (default 64)
 *   cd_digit    numbers colour                    (default #1d2327)
 *   cd_accent   labels + secondary ring colour    (default #999999)
 *   cd_zero     keep | hide | message             (default keep)
 *   cd_message  message shown when cd_zero=message
 *
 * Free for everyone.
 *
 * @param array|object $el       Element node.
 * @param array        $settings Resolved (editor) or raw (frontend) settings.
 * @param string       $context  'frontend' or 'editor'.
 * @return string Inner HTML.
 *
 * @sideeffect Frontend flags $GLOBALS['impulse_needs_countdown'] so the page
 *             template enqueues the engine only when a countdown exists.
 */
function impulse_element_render_countdown($el, array $settings, string $context): string {
    if (is_object($el)) $el = (array) $el;
    $isEditor = ($context === 'editor');
    if (!$isEditor) { $GLOBALS['impulse_needs_countdown'] = true; }

    $epoch = is_numeric($settings['cd_epoch'] ?? null) ? (float) $settings['cd_epoch'] : 0;
    // A block with no target (or a target in the past on a fresh drop) still
    // has to LOOK alive in the canvas - default a week out.
    if ($epoch <= 0) { $epoch = (time() + 7 * 86400) * 1000; }

    // Rings are a toggle over one readout, not a style among four. Absent
    // means ON: the circling text is what the block is for, and a block that
    // arrives bare on drop reads as broken. The panel collects checkboxes as
    // real booleans, so an unticked box arrives as false (which casts to '',
    // not '0') - empty() is the only test that catches every shape.
    $rings = !isset($settings['cd_rings']) ? true : !empty($settings['cd_rings']);

    $unitsRaw = (string) ($settings['cd_units'] ?? 'd,h,m,s');
    $units = implode(',', array_values(array_intersect(
        array_map('trim', explode(',', strtolower($unitsRaw))),
        ['d', 'h', 'm', 's']
    )));
    if ($units === '') { $units = 'd,h,m,s'; }

    $labels = [
        'd' => (string) ($settings['cd_label_d'] ?? 'Days'),
        'h' => (string) ($settings['cd_label_h'] ?? 'Hours'),
        'm' => (string) ($settings['cd_label_m'] ?? 'Minutes'),
        's' => (string) ($settings['cd_label_s'] ?? 'Seconds'),
    ];

    $size = (int) ($settings['cd_size'] ?? 64);
    $size = max(20, min(220, $size ?: 64));

    $digit  = (string) ($settings['cd_digit'] ?? '#1d2327');
    $accent = (string) ($settings['cd_accent'] ?? '#999999');
    $ring   = (string) ($settings['cd_ring'] ?? 'limited offer');
    $zeroRaw = strtolower((string) ($settings['cd_zero'] ?? 'keep'));
    $zero = in_array($zeroRaw, ['keep', 'hide', 'message'], true) ? $zeroRaw : 'keep';
    $message = (string) ($settings['cd_message'] ?? 'We are live');

    return '<div class="impulse-countdown"'
        . ' data-cd-target="' . esc_attr((string) round($epoch)) . '"'
        . ' data-cd-rings="' . ($rings ? '1' : '0') . '"'
        . ' data-cd-labels-on="' . ((!isset($settings['cd_labels_on']) || !empty($settings['cd_labels_on'])) ? '1' : '0') . '"'
        . ' data-cd-units="' . esc_attr($units) . '"'
        . ' data-cd-labels="' . esc_attr(rawurlencode((string) wp_json_encode($labels))) . '"'
        . ' data-cd-ring="' . esc_attr(rawurlencode($ring)) . '"'
        . ' data-cd-size="' . esc_attr((string) $size) . '"'
        . ' data-cd-accent="' . esc_attr($accent) . '"'
        . ' data-cd-font="' . esc_attr(in_array((string) ($settings['cd_font'] ?? ''), ['system', 'serif', 'geometric', 'mono'], true) ? (string) $settings['cd_font'] : '') . '"'
        . ' data-cd-digit="' . esc_attr($digit) . '"'
        . ' data-cd-gap="' . esc_attr((string) max(0, min(80, (int) ($settings['cd_gap'] ?? 0)))) . '"'
        . ' data-cd-align="' . esc_attr(in_array((string) ($settings['cd_align'] ?? 'center'), ['left', 'center', 'right'], true) ? (string) $settings['cd_align'] : 'center') . '"'
        . ' data-cd-ring-size="' . esc_attr((string) max(30, min(100, (int) ($settings['cd_ring_size'] ?? 100)))) . '"'
        . ' data-cd-ring-color="' . esc_attr((string) ($settings['cd_ring_color'] ?? '')) . '"'
        . ' data-cd-parallax="' . ((!empty($settings['cd_parallax']) && (string) $settings['cd_parallax'] !== '0') ? '1' : '0') . '"'
        . ' data-cd-zero="' . esc_attr($zero) . '"'
        . ' data-cd-message="' . esc_attr(rawurlencode($message)) . '"'
        . ' style="position:relative;width:100%;"'
        . '></div>';
}
