<?php
declare(strict_types=1);

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

/**
 * Reviews element renderer (shared between frontend and editor).
 *
 * A Google-style testimonials block: a header that references the
 * business Google profile (logo, aggregate rating, total count) over a
 * grid of review cards (reviewer name, star rating, date, review text,
 * optional deep-link to the source review).
 *
 * Data is owner-entered (curated REAL reviews — never fabricated, see the
 * no-fake-testimonials rule). The `reviews` setting holds a JSON array;
 * each entry is {name, rating, date, text, url?, avatar?}. This is a pure
 * server-rendered block (no client animation engine), so it renders
 * identically on the frontend, in the editor iframe, and in screenshots.
 *
 * Forward-compatible: a future live review source can populate
 * the same `reviews` array server-side without touching this renderer.
 *
 * @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 (no .impulse-el wrapper).
 */
function impulse_element_render_reviews($el, array $settings, string $context): string {
    if (is_object($el)) $el = (array) $el;
    $elId = (string) ($el['id'] ?? '0');

    // ── Settings ──────────────────────────────────────────────────
    $businessName = trim((string) ($settings['business_name'] ?? ''));
    if ($businessName === '' && function_exists('get_bloginfo')) {
        $businessName = (string) get_bloginfo('name');
    }
    $profileUrl  = trim((string) ($settings['profile_url'] ?? ''));   // "See all reviews"
    $writeUrl    = trim((string) ($settings['write_url'] ?? ''));     // "Leave a review"
    $showHeader  = ($settings['show_header'] ?? '1') !== '0';
    $columns     = max(1, min(3, intval($settings['columns'] ?? 3)));
    $align       = (string) ($settings['align'] ?? 'center');
    $cardBg      = (string) ($settings['card_bg'] ?? '#ffffff');
    $textColor   = (string) ($settings['text_color'] ?? '#1f2937');
    $mutedColor  = (string) ($settings['muted_color'] ?? '#70757a');
    $accent      = (string) ($settings['accent_color'] ?? '#1a73e8'); // links / write button
    $starColor   = (string) ($settings['star_color'] ?? '#fbbc04');   // Google gold
    $borderColor = (string) ($settings['border_color'] ?? '#e8eaed');
    $isEditor    = ($context === 'editor');

    // Per-card decompose is handled by the SECTION's own 3D reveal (its presets),
    // NOT by a separate reveal on this block. Each card renders as a plain grid
    // item with class `.impulse-reviews-card`; the section reveal engine treats
    // each one as a separate decompose unit via
    // DECOMPOSE_SUBS['reviews'] = '.impulse-reviews-card' (impulse-screens.js).
    // So there is no entrance_animation / reveal control on the reviews block.

    // Review cards.
    $reviews = $settings['reviews'] ?? [];
    if (is_string($reviews)) {
        $decoded = json_decode($reviews, true);
        $reviews = is_array($decoded) ? $decoded : [];
    }
    if (!is_array($reviews)) $reviews = [];
    // Keep only entries with at least name or text — defends against blank
    // repeater rows the owner left empty in the builder.
    $reviews = array_values(array_filter($reviews, static function ($r) {
        return is_array($r) && (trim((string) ($r['name'] ?? '')) !== '' || trim((string) ($r['text'] ?? '')) !== '');
    }));

    // Aggregate — explicit settings win; otherwise derive from the cards.
    $aggRating = (string) ($settings['rating'] ?? '');
    $aggCount  = (string) ($settings['review_count'] ?? '');
    if ($aggRating === '' && $reviews) {
        $sum = 0; $n = 0;
        foreach ($reviews as $r) {
            $rv = (float) ($r['rating'] ?? 0);
            if ($rv > 0) { $sum += $rv; $n++; }
        }
        if ($n > 0) $aggRating = number_format($sum / $n, 1);
    }
    if ($aggCount === '' && $reviews) {
        $aggCount = (string) count($reviews);
    }

    // ── Star helper (filled gold to `val`, hollow after) ──────────
    $stars = static function (float $val, int $px, string $on, string $off) {
        $out = '<span class="impulse-reviews-stars" style="display:inline-flex;gap:1px;line-height:1;vertical-align:middle">';
        for ($i = 1; $i <= 5; $i++) {
            $fill = ($val >= $i) ? $on : (($val >= $i - 0.5) ? $on : $off);
            // Half-star: render a clipped star via gradient is overkill here;
            // round to nearest full star for the per-card display, the
            // aggregate number carries the precise value.
            $fill = ($val >= $i - 0.25) ? $on : $off;
            $out .= '<svg width="' . $px . '" height="' . $px . '" viewBox="0 0 24 24" fill="' . esc_attr($fill) . '" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">'
                  . '<path d="M12 2.5l2.9 6.06 6.6.79-4.86 4.55 1.27 6.55L12 17.9l-5.91 3.1 1.27-6.55L2.5 9.9l6.6-.79z"/></svg>';
        }
        $out .= '</span>';
        return $out;
    };

    // Official multi-colour Google "G".
    $googleG = '<svg width="18" height="18" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" style="flex-shrink:0">'
        . '<path fill="#4285F4" d="M45.12 24.5c0-1.56-.14-3.06-.4-4.5H24v8.51h11.84c-.51 2.75-2.06 5.08-4.39 6.64v5.52h7.11c4.16-3.83 6.56-9.47 6.56-16.17z"/>'
        . '<path fill="#34A853" d="M24 46c5.94 0 10.92-1.97 14.56-5.33l-7.11-5.52c-1.97 1.32-4.49 2.1-7.45 2.1-5.73 0-10.58-3.87-12.31-9.07H4.34v5.7C7.96 41.07 15.4 46 24 46z"/>'
        . '<path fill="#FBBC05" d="M11.69 28.18C11.25 26.86 11 25.45 11 24s.25-2.86.69-4.18v-5.7H4.34A21.99 21.99 0 002 24c0 3.55.85 6.91 2.34 9.88z"/>'
        . '<path fill="#EA4335" d="M24 10.75c3.23 0 6.13 1.11 8.41 3.29l6.31-6.31C34.91 4.18 29.93 2 24 2 15.4 2 7.96 6.93 4.34 14.12l7.35 5.7c1.73-5.2 6.58-9.07 12.31-9.07z"/>'
        . '</svg>';

    $flexMap   = ['left' => 'flex-start', 'center' => 'center', 'right' => 'flex-end'];
    $alignFlex = $flexMap[$align] ?? 'center';

    // ── Per-device layout (columns + alignment) ───────────────────
    // Desktop is inline; tablet and mobile are id-scoped @media overrides so
    // the single frontend render adapts and the editor's device resize honours
    // them. Same approach as the grid block. columns/align are responsive keys,
    // so the editor already saves columns_tablet/_mobile + align_tablet/_mobile.
    $colD = $columns;
    $rawT = $settings['columns_tablet'] ?? null;
    $colT = ($rawT !== null && $rawT !== '') ? max(1, min(3, intval($rawT))) : min($colD, 2);
    $rawM = $settings['columns_mobile'] ?? null;
    $colM = ($rawM !== null && $rawM !== '') ? max(1, min(3, intval($rawM))) : 1;
    $alignT = (string) ($settings['align_tablet'] ?? $align);
    $alignM = (string) ($settings['align_mobile'] ?? $alignT);
    $wrapId = 'impulse-reviews-' . preg_replace('/[^A-Za-z0-9_-]/', '', (string) $elId);

    $mq = static function (string $sel, int $cols, string $al) use ($flexMap) {
        $f = $flexMap[$al] ?? 'center';
        return '#' . $sel . '{text-align:' . $al . '!important}'
             . '#' . $sel . ' .impulse-reviews-grid{grid-template-columns:repeat(' . $cols . ',minmax(0,1fr))!important}'
             . '#' . $sel . ' .impulse-reviews-header{justify-content:' . $f . '!important}';
    };
    $scoped  = '@media (min-width:768px) and (max-width:1024px){' . $mq($wrapId, $colT, $alignT) . '}';
    $scoped .= '@media (max-width:767px){' . $mq($wrapId, $colM, $alignM) . '}';

    ob_start();
    wp_add_inline_style('instinctor-page-inline', $scoped);
    echo '<div class="impulse-reviews" id="' . esc_attr($wrapId) . '" style="width:100%;text-align:' . esc_attr($align) . '">';

    // ── Header ────────────────────────────────────────────────────
    if ($showHeader) {
        echo '<div class="impulse-reviews-header" style="display:flex;flex-wrap:wrap;align-items:center;justify-content:' . esc_attr($alignFlex) . ';gap:10px 16px;margin-bottom:22px">';
        echo '<div style="display:flex;align-items:center;gap:8px">' . wp_kses($googleG, impulse_svg_allowed())
           . '<span style="font-size:16px;font-weight:600;color:' . esc_attr($textColor) . '">'
           . esc_html($businessName !== '' ? $businessName : 'Google') . '</span>'
           . '<span style="font-size:13px;color:' . esc_attr($mutedColor) . '">Reviews</span></div>';

        if ($aggRating !== '') {
            echo '<div style="display:flex;align-items:center;gap:8px">'
               . '<span style="font-size:22px;font-weight:700;color:' . esc_attr($textColor) . ';line-height:1">' . esc_html($aggRating) . '</span>'
               . wp_kses($stars((float) $aggRating, 16, $starColor, $borderColor), impulse_svg_allowed());
            if ($aggCount !== '') {
                echo '<span style="font-size:13px;color:' . esc_attr($mutedColor) . '">' . esc_html($aggCount) . ' reviews</span>';
            }
            echo '</div>';
        }

        if ($writeUrl !== '' || $profileUrl !== '') {
            echo '<div style="display:flex;align-items:center;gap:14px;margin-left:auto">';
            if ($writeUrl !== '') {
                echo '<a href="' . esc_url($writeUrl) . '" target="_blank" rel="noopener noreferrer" '
                   . 'style="display:inline-flex;align-items:center;gap:6px;height:34px;padding:0 16px;border-radius:18px;'
                   . 'background:' . esc_attr($accent) . ';color:#fff;font-size:13px;font-weight:600;text-decoration:none;'
                   . 'transition:opacity .2s ease-in-out">Write a review</a>';
            }
            if ($profileUrl !== '') {
                echo '<a href="' . esc_url($profileUrl) . '" target="_blank" rel="noopener noreferrer" '
                   . 'style="font-size:13px;font-weight:600;color:' . esc_attr($accent) . ';text-decoration:none">See all reviews</a>';
            }
            echo '</div>';
        }
        echo '</div>';
    }

    // ── Cards ─────────────────────────────────────────────────────
    if (!$reviews) {
        if ($context === 'editor') {
            echo '<div style="padding:28px;border:1px dashed ' . esc_attr($borderColor) . ';border-radius:12px;text-align:center;color:' . esc_attr($mutedColor) . ';font-size:13px">'
               . 'No reviews yet. Add your real Google reviews in the panel on the left.</div>';
        }
        echo '</div>';
        return ob_get_clean();
    }

    echo '<div class="impulse-reviews-grid" style="display:grid;grid-template-columns:repeat(' . (int) $columns . ',minmax(0,1fr));gap:16px;text-align:left">';
    $cardIdx = 0;
    foreach ($reviews as $r) {
        $name   = trim((string) ($r['name'] ?? ''));
        $rating = (float) ($r['rating'] ?? 5);
        if ($rating <= 0) $rating = 5;
        $date   = trim((string) ($r['date'] ?? ''));
        $text   = trim((string) ($r['text'] ?? ''));
        $url    = trim((string) ($r['url'] ?? ''));
        $avatar = trim((string) ($r['avatar'] ?? ''));
        $initial = $name !== '' ? mb_strtoupper(mb_substr($name, 0, 1)) : '?';

        // Plain grid item. The section's 3D reveal decomposes each card.
        echo '<div class="impulse-reviews-card" style="display:flex;flex-direction:column;flex:1;gap:10px;background:' . esc_attr($cardBg) . ';'
           . 'border:1px solid ' . esc_attr($borderColor) . ';border-radius:12px;padding:18px">';

        // Top: avatar + name + Google G
        echo '<div style="display:flex;align-items:center;gap:10px">';
        if ($avatar !== '') {
            echo '<img src="' . esc_url($avatar) . '" alt="" width="40" height="40" style="width:40px;height:40px;border-radius:50%;object-fit:cover;flex-shrink:0">';
        } else {
            echo '<span style="width:40px;height:40px;border-radius:50%;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;'
               . 'background:' . esc_attr($accent) . ';color:#fff;font-size:16px;font-weight:600">' . esc_html($initial) . '</span>';
        }
        echo '<div style="flex:1;min-width:0">'
           . '<div style="font-size:14px;font-weight:600;color:' . esc_attr($textColor) . ';white-space:nowrap;overflow:hidden;text-overflow:ellipsis">' . esc_html($name) . '</div>';
        if ($date !== '') {
            echo '<div style="font-size:12px;color:' . esc_attr($mutedColor) . '">' . esc_html($date) . '</div>';
        }
        echo '</div>' . wp_kses($googleG, impulse_svg_allowed()) . '</div>';

        // Stars
        echo wp_kses($stars($rating, 16, $starColor, $borderColor), impulse_svg_allowed());

        // Text
        if ($text !== '') {
            echo '<div style="font-size:14px;line-height:1.6;color:' . esc_attr($textColor) . ';white-space:pre-wrap">' . esc_html($text) . '</div>';
        }

        // Source link
        if ($url !== '') {
            echo '<a href="' . esc_url($url) . '" target="_blank" rel="noopener noreferrer" '
               . 'style="font-size:13px;font-weight:600;color:' . esc_attr($accent) . ';text-decoration:none;margin-top:2px">Read on Google</a>';
        }

        echo '</div>'; // card
        $cardIdx++;
    }
    echo '</div>'; // grid

    echo '</div>'; // .impulse-reviews
    return ob_get_clean();
}
