<?php
declare(strict_types=1);

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

/**
 * Google Maps embed element renderer (shared).
 *
 * Phase 1, step 18.
 *
 * Pre-extraction the two renderers used genuinely different layout
 * approaches:
 *
 *   - Frontend: aspect-ratio sizing (16/9 default, 1/1 for circle).
 *     Supports `none`, `circle`, `soft` (rounded-corner) shapes.
 *     Adds `impulse-map-reveal` class + `impulse_needs_map_reveal`
 *     global for scroll-trigger reveal animation.
 *   - Editor: fixed `map_height` (pixel value) + `position_align`
 *     (left/center/right). Shapes are just `circle` / `rectangle`.
 *     Adds an `impulse-map-overlay` div that swallows clicks (so the
 *     iframe doesn't grab focus in the builder).
 *
 * Forward-unify to the frontend's modern aspect-ratio approach as
 * canonical, but bring in editor's:
 *   - position_align (was a real feature that frontend ignored)
 *   - map_overlay swallow div (editor-only gating)
 *   - explicit map_height as an OPT-IN override (when set, breaks
 *     out of aspect-ratio mode and uses a fixed pixel height)
 *
 * Shape vocabulary unified: `none`, `circle`, `soft`. The editor's
 * `rectangle` value treated as alias of `none`. Frontend default was
 * `none` (which meant 16:9 rectangle); editor default was
 * `rectangle` (same thing). Unified default: `none`.
 *
 * Map type (frontend used m/k/h/p shorthand for roadmap/satellite/
 * hybrid/terrain via &t= param; editor hardcoded `t=m`). Unified to
 * frontend's mapped types.
 *
 * @sideeffect Primes $GLOBALS['impulse_needs_map_reveal'] on frontend
 *             so the scroll-reveal asset enqueues. Emits responsive
 *             @media CSS for width overrides.
 */
/**
 * Mobile rule: line an address/hours block up with the map's left edge.
 *
 * In a Visit-style row the map shares a grid with an address/hours block. On
 * mobile the row stacks (address above map) and each is centered independently
 * by its grid cell's align-items:center, leaving them on different left edges.
 * Left-align both cells of a map-bearing grid so they share one left edge.
 * Scoped via :has() to grids that actually contain a map. Returned as an inline
 * <style> because the two map render paths (this file + templates/impulse-page.php)
 * both emit in <body>, where wp_add_inline_style (head) prints too late.
 */
function impulse_map_row_align_css(): string {
    // The address/hours block otherwise shrinks to its text and is centered by its
    // grid cell, so it sits narrow and off the map's edge. Stretch both cells so the
    // block fills the full cell width (= the map width) and its left edge lines up
    // with the map. (The block's own side padding is a per-section id-!important
    // rule that a class selector can't override, so that is zeroed on the template
    // section instead: padding_left_mobile/padding_right_mobile = 0.)
    return '<style>@media(max-width:600px){'
        . '.impulse-grid:has(.impulse-google-map)>.impulse-grid-cell{align-items:stretch!important}'
        . '.impulse-grid:has(.impulse-google-map)>.impulse-grid-cell>:not(.impulse-google-map){width:100%!important;max-width:100%!important;margin-left:0!important;margin-right:0!important}'
        . '}</style>';
}

function impulse_element_render_map($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');

    $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;
    };

    $address       = (string) ($settings['address']  ?? '1600 Amphitheatre Parkway, Mountain View, CA');
    $latitude      = (string) ($settings['latitude'] ?? '');
    $longitude     = (string) ($settings['longitude'] ?? '');
    $zoom          = intval($read('zoom', 14));
    $mapType       = (string) ($settings['map_type']  ?? 'roadmap');
    $mapShape      = (string) ($settings['map_shape'] ?? 'none');
    if ($mapShape === 'rectangle') $mapShape = 'none'; // legacy alias
    $mapStyle      = (string) ($settings['map_style'] ?? 'normal');
    $width         = intval($read('width',  100));
    $borderRadius  = intval($read('border_radius', 0));
    $positionAlign = (string) ($settings['position_align'] ?? 'center');
    $mapHeight     = intval($read('map_height', 0)); // 0 = use aspect-ratio, >0 = fixed px height

    $parentId = intval($el['parent_id'] ?? 0);

    // Query string: lat/lng if present, else address.
    $query = ($latitude !== '' && $longitude !== '') ? ($latitude . ',' . $longitude) : $address;

    // Map type → embed `t=` param.
    $typeMap = ['roadmap' => 'm', 'satellite' => 'k', 'hybrid' => 'h', 'terrain' => 'p'];
    $mapTypeParam = $typeMap[$mapType] ?? 'm';
    $embedUrl = 'https://maps.google.com/maps?q=' . urlencode($query) . '&z=' . $zoom . '&t=' . $mapTypeParam . '&output=embed';

    // ── Alignment margin ────────────────────────────────────────
    if ($positionAlign === 'left') {
        $alignMargin = 'margin-left:0;margin-right:auto;';
    } elseif ($positionAlign === 'right') {
        $alignMargin = 'margin-left:auto;margin-right:0;';
    } else {
        $alignMargin = empty($parentId) ? 'margin:0 auto;' : 'margin-left:auto;margin-right:auto;';
    }

    // ── Container style ─────────────────────────────────────────
    $widthVar = $isEditor ? 'var(--impulse-width,' . $width . '%)' : ($width . '%');

    $containerStyle = 'position:relative;overflow:hidden;width:' . $widthVar . ';' . $alignMargin;

    if ($mapShape === 'circle') {
        // Circle: aspect-ratio 1/1 to keep it perfectly round at any width.
        $containerStyle .= 'aspect-ratio:1/1;border-radius:50%;transition:border-radius 0.5s cubic-bezier(0.4,0,0.2,1);';
    } elseif ($mapShape === 'soft') {
        $containerStyle .= 'aspect-ratio:16/9;border-radius:24px;';
    } else {
        // Default rectangle.
        if ($mapHeight > 0) {
            $containerStyle .= 'height:' . $mapHeight . 'px;';
        } else {
            $containerStyle .= 'aspect-ratio:16/9;';
        }
        if ($borderRadius > 0) $containerStyle .= 'border-radius:' . $borderRadius . 'px;';
    }

    $iframeFilter = ($mapStyle === 'grey') ? 'filter:grayscale(100%);' : '';

    $mapClass = 'impulse-google-map';
    if (!$isEditor) {
        $mapClass .= ' impulse-map-reveal';
        $GLOBALS['impulse_needs_map_reveal'] = true;
        if (function_exists('impulse_get_visibility_classes')) {
            $vc = impulse_get_visibility_classes($settings);
            if ($vc !== '') $mapClass .= ' ' . $vc;
        }
    }
    if ($mapShape === 'circle') $mapClass .= ' impulse-map-circle';

    $mapElId = 'impulse-map-' . ($elId ?: (function_exists('wp_rand') ? wp_rand(1000, 9999) : random_int(1000, 9999)));

    // ── Compose HTML ────────────────────────────────────────────
    ob_start();
    echo '<div id="' . esc_attr($mapElId) . '" class="' . esc_attr($mapClass) . '" style="' . esc_attr($containerStyle) . '">';
    echo '<iframe src="' . esc_url($embedUrl) . '" width="100%" height="100%" style="' . esc_attr('border:0;position:absolute;inset:0;' . $iframeFilter) . '" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>';

    // Shine overlay (reveal animation target).
    echo '<div class="impulse-map-shine" style="position:absolute;inset:0;pointer-events:none;z-index:1;overflow:hidden"></div>';

    // Editor: click-swallow overlay so the iframe doesn't grab focus while editing.
    if ($isEditor) {
        echo '<div class="impulse-map-overlay" style="position:absolute;inset:0;cursor:pointer;z-index:3"></div>';
    }

    echo '</div>';

    // ── Responsive @media (frontend only) ───────────────────────
    if (!$isEditor && function_exists('wp_add_inline_style')) {
        $resp = '';
        foreach (['tablet' => '1024', 'mobile' => '767'] as $dv => $bp) {
            $w = $settings['width_' . $dv] ?? null;
            if ($w !== null) $resp .= '@media(max-width:' . $bp . 'px){#' . $mapElId . '{width:' . intval($w) . '%!important}}';
        }
        if ($resp !== '') wp_add_inline_style('instinctor-page-inline', $resp);
    }

    // ── Mobile: line the address/hours block up with the map's left edge ──
    // In a Visit-style row the map shares a grid with an address/hours block.
    // On mobile the row stacks (address above map). Each of them is centered
    // independently: the map by its own margin:0 auto AND the grid cell's
    // align-items:center, the address by its cell's align-items:center. That
    // leaves the address text and the map on different left edges. Left-align
    // BOTH cells and cancel the map's auto margin so they share one left edge.
    // Scoped to grids that actually contain a map; emitted once per page.
    // Emit as an inline <style> in the map's own output (not wp_add_inline_style,
    // which prints in <head> and so is too late for a body-rendered element on
    // the standalone/demo path). Once per page via a per-REQUEST global guard
    // (a function-static would leak true across requests in a php-fpm worker).
    if (!$isEditor && empty($GLOBALS['impulse_map_row_align_done'])) {
        $GLOBALS['impulse_map_row_align_done'] = true;
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- impulse_map_row_align_css() returns a static literal CSS string.
        echo impulse_map_row_align_css();
    }

    return ob_get_clean();
}
