<?php
declare(strict_types=1);

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

/**
 * Image Carousel element renderer (shared).
 *
 * Phase 1, step 23. The two renderers were already strongly aligned
 * on the data-attr set, mode list, and rendering branches — same
 * scroll / slots / jackpot / reels / 3D-stack / turntable families.
 * Extraction consolidates the parallel implementations.
 *
 * Per-context differences preserved:
 *
 *   - Editor auto-optimizes for mobile device tab: defaults
 *     items_to_show to 1, max_width to 100% when no per-device
 *     override exists (matches the @media rules the frontend emits).
 *
 *   - Editor resolves image URLs via impulse_resolve_image($id,
 *     'large') when an image has an id — handles the standalone
 *     image library + WP attachment fallback. Frontend uses the URL
 *     direct from $img['full_url'] or $img['url'] (those keys are
 *     populated at save-time from the media picker).
 *
 *   - Editor renders placeholder grids when no images (grey boxes +
 *     Instinctor logo SVG) so empty blocks look intentional in the
 *     builder. Frontend breaks out early.
 *
 *   - Frontend emits responsive @media for items_to_show / gap /
 *     height / max_width per device. Editor doesn't (auto-optimize
 *     above handles its preview).
 *
 *   - Frontend has data-tilt-sens attr for 3D rotational modes
 *     (orbit, table, cube). Editor doesn't need it (no real motion).
 *
 * Arc CSS + parallax script is emitted in BOTH (mode list currently
 * makes arcModeSupported = false; the code exists for future modes
 * that opt into the Plans-style arc fan).
 *
 * @sideeffect Primes $GLOBALS['impulse_needs_carousel'] +
 *             impulse_has_carousel. Emits responsive @media via
 *             wp_add_inline_style on frontend.
 */
function impulse_element_render_carousel($el, array $settings, string $context): string {
    if (is_object($el)) $el = (array) $el;
    $elId     = preg_replace('/[^A-Za-z0-9_-]/', '', (string) ($el['id'] ?? 0));
    $isEditor = ($context === 'editor');
    $device   = $isEditor ? ($GLOBALS['impulse_preview_device'] ?? 'desktop') : 'desktop';

    $read = function (string $key, $default) use ($settings, $isEditor) {
        if ($isEditor && function_exists('impulse_get_responsive')) {
            return impulse_get_responsive($settings, $key, $default);
        }
        return $settings[$key] ?? $default;
    };

    $GLOBALS['impulse_needs_carousel'] = true;
    $GLOBALS['impulse_has_carousel']   = true;

    $height       = intval($read('height', 400));
    $borderRadius = intval($read('border_radius', 0));
    $itemsToShow  = intval($read('items_to_show', 1));

    // Editor auto-optimize per device tab.
    if ($isEditor) {
        if ($device === 'mobile' && !isset($settings['items_to_show_mobile'])) $itemsToShow = 1;
        elseif ($device === 'tablet' && !isset($settings['items_to_show_tablet']) && $itemsToShow > 2) $itemsToShow = 2;
    }
    if ($itemsToShow < 1) $itemsToShow = 1;

    $gap          = intval($read('gap', 0));
    $objectFit    = (string) ($settings['object_fit']    ?? 'cover');
    $slideBgColor = (string) ($settings['bg_color']      ?? '');
    $slideBgStyle = $slideBgColor !== '' ? 'background:' . $slideBgColor . ';' : '';
    $animMode     = (string) ($settings['animation_mode'] ?? 'scroll');
    $direction    = (string) ($settings['direction']      ?? 'left');
    // Lower bound dropped from 3 to 1 so callers can crank scroll_speed
    // higher and get an actually-fast marquee. With floor of 3 the JS
    // pxPerFrame couldn't drop below parentWidth/180, which read as a
    // slow crawl in compact viewports (e.g. the demo canvas).
    $speed        = max(1, round(60 / max(1, intval($isEditor && function_exists('impulse_device_val') ? impulse_device_val($settings, 'scroll_speed', $device, 3) : ($settings['scroll_speed'] ?? 3)))));
    $autoplay     = ($settings['autoplay']    ?? true) !== false;
    $autoplaySpeed = intval($read('autoplay_speed', 4));
    if ($autoplaySpeed <= 100) $autoplaySpeed *= 1000;
    $pauseHover   = ($settings['pause_hover'] ?? true) !== false;

    // max_width — slider_width canonical, max_width legacy.
    if ($isEditor) {
        $maxWidth = intval($read('slider_width', null) ?? $read('max_width', 100));
    } else {
        $maxWidth = intval($settings['slider_width'] ?? $settings['max_width'] ?? 100);
    }
    if ($maxWidth > 100) $maxWidth = 100;
    if ($maxWidth < 1)   $maxWidth = 100;
    if ($isEditor && $device === 'mobile' && !isset($settings['slider_width_mobile']) && !isset($settings['max_width_mobile'])) {
        $maxWidth = 100;
    }

    $images = $settings['images'] ?? [];
    if (is_string($images)) $images = json_decode($images, true) ?: [];
    $slideCount = count($images);

    // Frontend: skip block entirely when no images. Editor: render placeholders.
    if (!$isEditor && $slideCount < 1) return '';

    $carouselId = 'carousel-' . ($elId ?: (function_exists('wp_rand') ? wp_rand(1000, 9999) : random_int(1000, 9999)));
    $slideWidth = $itemsToShow > 1
        ? 'calc(' . (100 / $itemsToShow) . '% - ' . ($gap * ($itemsToShow - 1) / $itemsToShow) . 'px)'
        : '100%';

    // Arc settings (currently arcModeSupported=false in both renderers
    // — scaffold for future modes that opt into the Plans-style fan).
    $arcIntensity     = max(0, min(100, intval($settings['arc_intensity'] ?? 0)));
    $arcModeSupported = false;
    $arcActive        = $arcIntensity > 0 && $arcModeSupported && $itemsToShow > 1;

    // card_flip rotates slides through 3D space — overflow:hidden on the
    // wrapper clips the rotating card's edges mid-flip. Include card_flip
    // in both editor and frontend so the flip animation reads cleanly.
    $_3dTiltModes = ['coverflow', 'cube', 'conveyor', 'depth_rush', 'portal', 'card_flip', 'table', 'orbit'];
    $overflowOpen   = in_array($animMode, $_3dTiltModes, true);
    $overflowWrap   = $overflowOpen ? 'visible' : 'hidden';
    $overflowTrack  = $overflowOpen ? 'visible' : 'hidden';

    // Tilt-sens attr (frontend only, for 3D rotational modes).
    $imgTiltSens = null;
    if (!$isEditor && in_array($animMode, ['orbit', 'table', 'cube'], true)) {
        $imgTiltSens = isset($settings['tilt_sens']) ? max(0, min(10, intval($settings['tilt_sens']))) : 5;
    }

    // Resolve image URL — editor goes through impulse_resolve_image when id is set;
    // frontend uses the URL keys directly.
    $resolveUrl = function ($img) use ($isEditor) {
        if (!is_array($img)) return '';
        if ($isEditor) {
            $id = intval($img['id'] ?? 0);
            if ($id > 0 && function_exists('impulse_resolve_image')) {
                $src = impulse_resolve_image($id, 'large');
                if (is_array($src) && !empty($src[0])) return (string) $src[0];
            }
        }
        return (string) ($img['full_url'] ?? ($img['url'] ?? ''));
    };

    $logoUrl = (defined('INSTINCTOR_PLUGIN_URL') ? INSTINCTOR_PLUGIN_URL : '/instinctor-plugin/') . 'assets/images/placeholder-logo.svg';

    ob_start();

    echo '<div id="' . esc_attr($carouselId) . '" class="impulse-carousel impulse-image-carousel"'
       . ' data-mode="' . esc_attr($animMode) . '"'
       . ' data-direction="' . esc_attr($direction) . '"'
       . ' data-speed="' . (int) $speed . '"'
       . ' data-autoplay="' . ($autoplay ? 'true' : 'false') . '"'
       . ' data-interval="' . (int) $autoplaySpeed . '"'
       . ' data-pause="' . ($pauseHover ? 'true' : 'false') . '"'
       . ' data-items="' . (int) $itemsToShow . '"'
       . ' data-gap="' . (int) $gap . '"'
       . ' data-slide-count="' . (int) $slideCount . '"'
       . ($imgTiltSens !== null ? ' data-tilt-sens="' . (int) $imgTiltSens . '"' : '')
       . ' style="position:relative;border-radius:' . (int) $borderRadius . 'px;overflow:' . esc_attr($overflowWrap) . ';width:' . (int) $maxWidth . '%;margin:' . intval($settings['margin_top'] ?? 0) . 'px auto 0">';

    $trackArcExtra = $arcActive ? ';perspective:1200px;perspective-origin:center top;transform-style:preserve-3d' : '';
    echo '<div class="impulse-carousel-track" style="overflow:' . esc_attr($overflowTrack) . ';height:' . (int) $height . 'px' . esc_attr($trackArcExtra) . '">';

    if ($animMode === 'scroll') {
        $totalSets = $slideCount > 0 ? min(12, max(5, ceil(($itemsToShow * 6) / $slideCount))) : 5;
        echo '<div class="impulse-carousel-slides" style="display:flex;gap:' . (int) $gap . 'px;height:100%">';
        if (!empty($images)) {
            for ($s = 0; $s < $totalSets; $s++) {
                foreach ($images as $img) {
                    $url  = $resolveUrl($img);
                    $link = (string) (is_array($img) ? ($img['link'] ?? '') : '');
                    echo '<div class="impulse-carousel-slide" style="flex:0 0 ' . esc_attr($slideWidth) . ';min-width:0;height:100%;' . esc_attr($slideBgStyle) . '">';
                    if ($url !== '') {
                        if ($link !== '') echo '<a href="' . esc_url($link) . '" class="imp-fill" style="display:block;width:100%;height:100%">';
                        echo '<img src="' . esc_url($url) . '" style="width:100%;height:100%;object-fit:' . esc_attr($objectFit) . ';display:block">';
                        if ($link !== '') echo '</a>';
                    } else {
                        echo '<div style="width:100%;height:100%;background:#e0e0e0"></div>';
                    }
                    echo '</div>';
                }
            }
        } elseif ($isEditor) {
            for ($i = 0; $i < max(6, $itemsToShow * 3); $i++) {
                echo '<div class="impulse-carousel-slide" style="flex:0 0 ' . esc_attr($slideWidth) . ';min-width:0;height:100%;background:#e0e0e0;display:flex;align-items:center;justify-content:center">';
                echo '<img src="' . esc_url($logoUrl) . '" style="width:60px;height:auto">';
                echo '</div>';
            }
        }
        echo '</div>';
    } elseif ($animMode === 'slots' || $animMode === 'jackpot' || $animMode === 'reels') {
        $isJackpot = ($animMode === 'jackpot');
        $isReels   = ($animMode === 'reels');
        // Strip length sized so JS can animate SPIN_CYCLES (3 by default) full
        // cycles plus the advance step in one go without overflowing the strip.
        //   max endY = (count - 1) * h + (SPIN_CYCLES * count + 1) * h
        //            = (SPIN_CYCLES + 1) * count * h
        //   strip items needed = (SPIN_CYCLES + 1) * count + 1
        // With SPIN_CYCLES=3 → 4 * count + 1 items.
        $repeats   = $isJackpot ? ($slideCount * 5 + 1) : ($isReels ? ($slideCount * 4 + 1) : ($slideCount * 4 + 1));
        echo '<div class="impulse-carousel-slides impulse-slots-container" data-items="' . (int) $itemsToShow . '" style="display:flex;gap:' . (int) $gap . 'px;width:100%;height:100%">';
        if (!empty($images) && $slideCount > 0) {
            for ($reel = 0; $reel < $itemsToShow; $reel++) {
                echo '<div class="impulse-slot-reel" data-reel="' . (int) $reel . '" data-count="' . (int) $slideCount . '" style="flex:0 0 ' . esc_attr($slideWidth) . ';height:100%;overflow:hidden;position:relative">';
                echo '<div class="impulse-slot-strip" style="position:absolute;top:0;left:0;width:100%">';
                for ($r = 0; $r < $repeats; $r++) {
                    $img = $images[($reel + $r) % $slideCount];
                    $url = $resolveUrl($img);
                    echo '<div class="impulse-slot-item" style="width:100%;height:' . (int) $height . 'px">';
                    if ($url !== '') {
                        echo '<img src="' . esc_url($url) . '" style="width:100%;height:100%;object-fit:' . esc_attr($objectFit) . ';display:block">';
                    } else {
                        echo '<div style="width:100%;height:100%;background:#e0e0e0"></div>';
                    }
                    echo '</div>';
                }
                echo '</div></div>';
            }
        } elseif ($isEditor) {
            for ($reel = 0; $reel < max(3, $itemsToShow); $reel++) {
                echo '<div class="impulse-slot-reel" data-reel="' . (int) $reel . '" data-count="3" style="flex:0 0 ' . esc_attr($slideWidth) . ';height:100%;overflow:hidden;position:relative">';
                echo '<div class="impulse-slot-strip" style="position:absolute;top:0;left:0;width:100%">';
                for ($r = 0; $r < 4; $r++) {
                    echo '<div class="impulse-slot-item" style="width:100%;height:' . (int) $height . 'px;background:#e0e0e0;display:flex;align-items:center;justify-content:center">';
                    echo '<img src="' . esc_url($logoUrl) . '" style="width:60px;height:auto">';
                    echo '</div>';
                }
                echo '</div></div>';
            }
        }
        echo '</div>';
    } elseif (in_array($animMode, ['depth_rush', 'card_flip', 'pixel_decode', 'coverflow', 'cube', 'conveyor', 'portal'], true)) {
        $perspective = $animMode === 'depth_rush' ? 'perspective:1200px;' : ($animMode === 'card_flip' ? 'perspective:1000px;' : '');
        echo '<div class="impulse-carousel-slides" style="position:relative;width:100%;height:100%;' . esc_attr($perspective) . '">';
        $slideList = !empty($images) ? $images : ($isEditor ? null : []);
        $totalRender = $slideList ? count($slideList) : ($isEditor ? 3 : 0);
        for ($idx = 0; $idx < $totalRender; $idx++) {
            $active = ($idx === 0) ? 'opacity:1;z-index:2' : 'opacity:0;z-index:0';
            $img    = $slideList ? $slideList[$idx] : null;
            $url    = $img ? $resolveUrl($img) : '';
            $link   = $img ? (string) ($img['link'] ?? '') : '';
            echo '<div class="impulse-carousel-slide" data-index="' . (int) $idx . '" style="position:absolute;inset:0;' . esc_attr($slideBgStyle) . esc_attr($active) . ';will-change:transform,opacity">';
            if ($url !== '') {
                if ($link !== '') echo '<a href="' . esc_url($link) . '" class="imp-fill" style="display:block;width:100%;height:100%">';
                echo '<img src="' . esc_url($url) . '" style="width:100%;height:100%;object-fit:' . esc_attr($objectFit) . ';display:block;border-radius:' . (int) $borderRadius . 'px">';
                if ($link !== '') echo '</a>';
            } elseif ($isEditor) {
                echo '<div style="width:100%;height:100%;background:#e0e0e0;display:flex;align-items:center;justify-content:center;border-radius:' . (int) $borderRadius . 'px"><img src="' . esc_url($logoUrl) . '" style="width:60px;height:auto"></div>';
            }
            echo '</div>';
        }
        echo '</div>';
    } else {
        // Turntable / Orbit / Ring.
        $minItems    = 8;
        $totalItems  = $slideCount > 0 ? $slideCount : $minItems;
        if ($slideCount > 0) {
            while ($totalItems < $minItems) $totalItems += $slideCount;
        }
        $itemWidth = 30;
        echo '<div class="impulse-carousel-slides impulse-turntable" data-variant="' . esc_attr($animMode) . '" data-total="' . (int) $totalItems . '" data-real="' . (int) $slideCount . '" style="position:relative;width:100%;height:100%;perspective:1000px">';
        if (!empty($images) && $slideCount > 0) {
            for ($i = 0; $i < $totalItems; $i++) {
                $img  = $images[$i % $slideCount];
                $url  = $resolveUrl($img);
                $link = (string) ($img['link'] ?? '');
                echo '<div class="impulse-turntable-item" data-index="' . (int) $i . '" style="position:absolute;width:' . (int) $itemWidth . '%;height:80%;top:10%;left:50%;transform:translateX(-50%);will-change:transform,filter,opacity">';
                if ($url !== '') {
                    if ($link !== '') echo '<a href="' . esc_url($link) . '" class="imp-fill" style="display:block;width:100%;height:100%">';
                    echo '<img src="' . esc_url($url) . '" style="width:100%;height:100%;object-fit:' . esc_attr($objectFit) . ';display:block;border-radius:' . (int) $borderRadius . 'px">';
                    if ($link !== '') echo '</a>';
                } else {
                    echo '<div style="width:100%;height:100%;background:#e0e0e0;border-radius:' . (int) $borderRadius . 'px"></div>';
                }
                echo '</div>';
            }
        } elseif ($isEditor) {
            for ($i = 0; $i < $minItems; $i++) {
                echo '<div class="impulse-turntable-item" data-index="' . (int) $i . '" style="position:absolute;width:' . (int) $itemWidth . '%;height:80%;top:10%;left:50%;transform:translateX(-50%)">';
                echo '<div style="width:100%;height:100%;background:#e0e0e0;border-radius:' . (int) $borderRadius . 'px;display:flex;align-items:center;justify-content:center"><img src="' . esc_url($logoUrl) . '" style="width:60px;height:auto"></div>';
                echo '</div>';
            }
        }
        echo '</div>';
    }

    echo '</div></div>';

    $html = ob_get_clean();

    // ── Mobile fallback for 3D grid modes ────────────────────────
    // Coverflow / cube / conveyor / portal etc. rely on width, perspective and
    // a hover/drag affordance that collapse into cropped, blurry portrait cards
    // on a phone. For <=767px we hide the 3D carousel and render a clean native
    // scroll-snap slider (one landscape photo, neighbours peeking) in its place.
    // Desktop keeps the 3D effect untouched. Frontend only.
    $mobileFallbackCss = '';
    if (!$isEditor && in_array($animMode, $_3dTiltModes, true) && $slideCount >= 1) {
        $mid   = $carouselId . '-m';
        $mHtml = '<div id="' . esc_attr($mid) . '" class="impulse-carousel-mobile" aria-label="Gallery">';
        foreach ($images as $img) {
            $u = $resolveUrl($img);
            if ($u === '') continue;
            $lnk   = is_array($img) ? (string) ($img['link'] ?? '') : '';
            $inner = '<img src="' . esc_url($u) . '" loading="lazy" alt="">';
            if ($lnk !== '') $inner = '<a href="' . esc_url($lnk) . '" style="display:block;width:100%;height:100%">' . $inner . '</a>';
            $mHtml .= '<div>' . $inner . '</div>';
        }
        $mHtml .= '</div>';
        $html  .= $mHtml;

        $br = (int) $borderRadius;
        $mobileFallbackCss =
            '#' . $mid . '{display:none}'
          . '@media(max-width:767px){'
          .   '#' . $carouselId . '{display:none!important}'
          .   '#' . $mid . '{display:flex;gap:10px;overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none;width:100%;margin:0 auto;padding:0 4px}'
          .   '#' . $mid . '::-webkit-scrollbar{display:none}'
          .   '#' . $mid . '>div{flex:0 0 88%;scroll-snap-align:center;aspect-ratio:3/2;border-radius:' . $br . 'px;overflow:hidden}'
          .   '#' . $mid . ' img{width:100%;height:100%;object-fit:cover;display:block}'
          . '}';
    }

    // ── Frontend responsive @media ───────────────────────────────
    if (!$isEditor && function_exists('wp_add_inline_style')) {
        $itemsTablet = intval($settings['items_to_show_tablet'] ?? min($itemsToShow, 2));
        $itemsMobile = intval($settings['items_to_show_mobile'] ?? 1);
        $gapTablet   = intval($settings['gap_tablet'] ?? $gap);
        $gapMobile   = intval($settings['gap_mobile'] ?? $gap);
        $heightTablet = intval($settings['height_tablet'] ?? 0);
        $heightMobile = intval($settings['height_mobile'] ?? 0);
        $mwTabletRaw = $settings['slider_width_tablet'] ?? $settings['max_width_tablet'] ?? null;
        $mwMobileRaw = $settings['slider_width_mobile'] ?? $settings['max_width_mobile'] ?? null;
        $mwTablet    = $mwTabletRaw !== null ? max(1, min(100, intval($mwTabletRaw))) : $maxWidth;
        $mwMobile    = $mwMobileRaw !== null ? max(1, min(100, intval($mwMobileRaw))) : 100;

        $rCss = '';
        if ($itemsTablet !== $itemsToShow || $gapTablet !== $gap || $heightTablet > 0 || $mwTablet !== $maxWidth) {
            $rCss .= '@media(max-width:1024px){';
            if ($itemsTablet !== $itemsToShow || $gapTablet !== $gap) {
                $twT = $itemsTablet > 1 ? 'calc(' . (100 / $itemsTablet) . '% - ' . ($gapTablet * ($itemsTablet - 1) / $itemsTablet) . 'px)' : '100%';
                $rCss .= '#' . $carouselId . ' .impulse-carousel-slide{flex:0 0 ' . $twT . '!important}';
                $rCss .= '#' . $carouselId . ' .impulse-carousel-slides{gap:' . $gapTablet . 'px!important}';
            }
            if ($heightTablet > 0) $rCss .= '#' . $carouselId . ' .impulse-carousel-track{height:' . $heightTablet . 'px!important}';
            if ($mwTablet !== $maxWidth) $rCss .= '#' . $carouselId . '{width:' . $mwTablet . '%!important}';
            $rCss .= '}';
        }
        if ($itemsMobile !== $itemsToShow || $gapMobile !== $gap || $heightMobile > 0 || $mwMobile !== $maxWidth) {
            $rCss .= '@media(max-width:767px){';
            if ($itemsMobile !== $itemsToShow || $gapMobile !== $gap) {
                $twM = $itemsMobile > 1 ? 'calc(' . (100 / $itemsMobile) . '% - ' . ($gapMobile * ($itemsMobile - 1) / $itemsMobile) . 'px)' : '100%';
                $rCss .= '#' . $carouselId . ' .impulse-carousel-slide{flex:0 0 ' . $twM . '!important}';
                $rCss .= '#' . $carouselId . ' .impulse-carousel-slides{gap:' . $gapMobile . 'px!important}';
            }
            if ($heightMobile > 0) $rCss .= '#' . $carouselId . ' .impulse-carousel-track{height:' . $heightMobile . 'px!important}';
            if ($mwMobile !== $maxWidth) $rCss .= '#' . $carouselId . '{width:' . $mwMobile . '%!important}';
            $rCss .= '}';
        }
        $rCss .= $mobileFallbackCss;
        if ($rCss !== '') wp_add_inline_style('instinctor-page-inline', $rCss);
    }

    return $html;
}
