<?php
namespace Components\Ui;

use Components\Button;
use Components\Router;
use Components\Base;

/**
 * FlowHelpers: reusable UI elements for Flow visualization cards.
 */
class FlowHelpers
{
    /**
     * Returns the Alpine.js data object string for flow scroll containers.
     * Expects $refs.scroller to be the scrollable element.
     */
    public static function alpineData(string $behavior = 'smooth', string $defaultViewMode = 'journey'): string
    {
        return '{
            canScrollX: false,
            atStart: true,
            atEnd: false,
            refreshing: false,
            localViewMode: \'' . $defaultViewMode . '\',
            init() {
                this.update();
                if (window.IntersectionObserver) {
                    const observer = new IntersectionObserver(() => {
                        this.update();
                    }, { threshold: [0, 1] });
                    observer.observe(this.$el);
                }
            },
            update() {
                const el = this.$refs.scroller || this.$el;
                if (!el) return;
                this.canScrollX = el.scrollWidth > (el.clientWidth + 2);
                const max = Math.max(0, el.scrollWidth - el.clientWidth);
                this.atStart = el.scrollLeft <= 1;
                this.atEnd = el.scrollLeft >= (max - 1);
            },
            scrollBy(dx) {
                const el = this.$refs.scroller || this.$el;
                if (!el) return;
                el.scrollBy({ left: dx, behavior: \'' . $behavior . '\' });
            }
        }';
    }

    /**
     * Renders a single scroll button.
     */
    public static function renderScrollButton(string $direction, int $amount = 280, string $class = ''): string
    {
        $dx = ($direction === 'left' ? -$amount : $amount);
        $icon = ($direction === 'left'
            ? Base::SVG_CHEVRON_LEFT
            : Base::SVG_CHEVRON_RIGHT);

        ob_start();
        ?>
        <button type="button" @click.stop="scrollBy(<?= $dx ?>)"
                class="pointer-events-auto inline-flex items-center justify-center shrink-0 [&_svg]:stroke-2 <?= $class ?>"
                x-cloak x-show="canScrollX && <?= $direction === 'left' ? '!atStart' : '!atEnd' ?>" x-transition.opacity>
                <?= $icon ?>
        </button>
        <?php
        return ob_get_clean();
    }

    /**
     * Renders the "Refresh Flow" button that triggers invalidate_flow_cache.
     */
    public static function renderRefreshButton(string $type, int $id = 0, string $eventPrefix = ''): string
    {
        $refreshUrl = Router::url('invalidate_flow_cache', [
            'partial' => 1,
            'id' => $id,
            'type' => $type,
            'event_prefix' => $eventPrefix,
        ]);
        ob_start();
        ?>
        <div class="absolute top-0 right-1 z-30">
            <?php
            echo Button::render('', [
                'size' => 'xs',
                'variant' => 'ghost',
                'icon' => '<span class="when-idle p-0.5 [&_svg]:size-4">' . Base::SVG_REFRESH . '</span><span class="when-request hidden p-0.5 [&_svg]:size-4">' . Base::SVG_SPINNER . '</span>',
                'class' => 'opacity-30 text-secondary/30 hover:text-secondary [&.htmx-request_.when-idle]:hidden [&.htmx-request_.when-request]:inline-flex disabled:opacity-50 ',
                'attrs' => [
                    '@click.stop'        => '',
                    'hx-post' => $refreshUrl,
                    'hx-swap' => 'none',
                    'hx-indicator' => '#' . ('refresh-btn-' . substr(md5($type . '|' . (string)$id . '|' . $eventPrefix), 0, 8)),
                    'hx-disabled-elt' => '#' . ('refresh-btn-' . substr(md5($type . '|' . (string)$id . '|' . $eventPrefix), 0, 8)),
                    ':disabled' => 'refreshing',
                    'data-no-global-loader' => '1',
                    'title' => 'Refresh Flow',
                    'id' => 'refresh-btn-' . substr(md5($type . '|' . (string)$id . '|' . $eventPrefix), 0, 8),
                ],
            ]);
            ?>
        </div>
        <?php
        return ob_get_clean();
    }

    /**
     * Renders horizontal scroll hint overlays (chevrons).
     * Expects Alpine data from alpineData().
     */
    public static function renderScrollHints(): string
    {
        ob_start();
        ?>
        <!-- Horizontal scroll hint overlays (fixed within the area) -->
        <div x-cloak x-show="canScrollX && !atStart" x-transition.opacity
             class="pointer-events-none absolute inset-y-0 left-0 flex items-center z-20">
            <button type="button" @click.stop="scrollBy(-280)"
                    class="[&_svg]:stroke-2 pointer-events-auto inline-flex items-center justify-center w-6 h-full bg-linear-to-l from-transparent via-flow-scroll-bg/50 to-flow-scroll-bg text-secondary/70 hover:bg-divider/20 focus:outline-none">
                <!-- left chevron -->
                <?= Base::SVG_CHEVRON_LEFT ?>
            </button>
        </div>
        <div x-cloak x-show="canScrollX && !atEnd" x-transition.opacity
             class="pointer-events-none absolute inset-y-0 right-0 flex items-center z-20">
            <button type="button" @click.stop="scrollBy(280)"
                    class="[&_svg]:stroke-2 pointer-events-auto inline-flex items-center justify-center w-6 h-full bg-linear-to-r from-transparent via-flow-scroll-bg/50 to-flow-scroll-bg text-secondary/70 hover:bg-divider/20 focus:outline-none">
                <!-- right chevron -->
                <?= Base::SVG_CHEVRON_RIGHT ?>
            </button>
        </div>
        <?php
        return ob_get_clean();
    }

    /**
     * Returns the Alpine.js initialization string for syncing localViewMode with global stores.
     *
     * @param string $openKey The module key for syncing with openMap
     * @param string $context Optional context (trigger, newsletter, audience) to prioritize store
     * @return string
     */
    public static function viewModeInit(string $openKey, string $context = ''): string
    {
        $openKeyEsc = Base::h($openKey);
        
        // Prioritize store based on context
        $stores = ['trigger', 'newsletter', 'audience'];
        if ($context && in_array($context, $stores)) {
            // Move prioritized store to the front
            $stores = array_diff($stores, [$context]);
            array_unshift($stores, $context);
        }

        $initParts = [];
        foreach ($stores as $s) {
            $initParts[] = "(\$store.$s && \$store.$s.viewMode) ? \$store.$s.viewMode : ";
        }
        $initScript = "const initialVM = " . implode('', $initParts) . "(typeof viewMode !== 'undefined' ? viewMode : null); ";
        $initScript .= "if (initialVM) localViewMode = initialVM; ";

        foreach ($stores as $s) {
            $initScript .= "if (\$store.$s) \$watch('\$store.$s.viewMode', v => localViewMode = v); ";
        }

        $initScript .= "if (typeof viewMode !== 'undefined') \$watch('viewMode', v => localViewMode = v); " .
            "\$watch('localViewMode', v => { if (v === 'journey') { \$nextTick(() => update()); } }); " .
            "if (typeof openMap !== 'undefined' && openMap['$openKeyEsc']) { update(); \$nextTick(() => update()); setTimeout(() => update(), 60); }";
            
        return $initScript;
    }

    /**
     * Forces the underlying page into the "Flow" (journey) view for the given context.
     *
     * Unifies the behavior used after creating/installing a new item (trigger
     * module, custom automation, newsletter, or audience): the page should present
     * the Flow view rather than Performance.
     *
     * When $persist is true, the view mode is persisted server-side (best-effort)
     * via ConfigStore so the page defaults to Flow on its next load. Regardless of
     * $persist, an inline <script> is returned that syncs the matching Alpine store
     * so a currently open page switches to the Flow view immediately.
     *
     * @param string $context One of 'trigger', 'newsletter', 'audience'.
     * @param bool   $persist Whether to also persist the view mode server-side.
     * @return string Inline <script> tag (safe to echo), or '' for an unknown context.
     */
    public static function forceFlowView(string $context, bool $persist = true): string
    {
        if (!in_array($context, ['trigger', 'newsletter', 'audience'], true)) {
            return '';
        }

        if ($persist) {
            try {
                \Components\ConfigStore::setViewMode($context, 'journey');
            } catch (\Throwable $e) {
                // Persistence is best-effort; the page still defaults to the Flow view.
            }
        }

        $store = json_encode($context);
        return '<script>(function(){try{var s=' . $store . ';'
            . 'if(window.Alpine&&Alpine.store&&Alpine.store(s)){Alpine.store(s).viewMode="journey";}'
            . '}catch(e){}})();</script>';
    }

    /**
     * Renders the Journey/Performance toggle sub-header.
     */
    public static function renderViewModeToggle(array $options = []): string
    {
        $editUrl = $options['edit_url'] ?? '';
        $detailsUrl = $options['details_url'] ?? '';
        $compact = $options['compact'] ?? false;
        $openKey = $options['open_key'] ?? '';

        ob_start();
        ?>
        <div class="<?= $compact ? 'flex items-center' : 'px-3 py-2 flex items-center justify-between shrink-0' ?>" @click.stop="">
            <?= TabsGroup::render([
                ['value' => 'performance', 'label' => mh_lng('MAILBEEZ_VIEW_PERFORMANCE', 'Performance')],
                ['value' => 'journey', 'label' => mh_lng('MAILBEEZ_VIEW_JOURNEY', 'Journey')],
            ], [
                'model' => 'localViewMode',
                'size' => 'xs',
                'attrs' => $openKey ? ['x-effect' => "openMap['" . Base::h((string)$openKey) . "'] && \$nextTick(() => sync())"] : []
            ]); ?>
        </div>
        <?php
        return ob_get_clean();
    }

    /**
     * Renders the background patterns container.
     */
    public static function renderBackground(string $id, string $type = 'dots', string $currentViewMode = 'journey'): string
    {
        ob_start();
        ?>
        <div x-show="localViewMode === 'journey'" <?php if ($currentViewMode !== 'journey') echo 'style="display: none;"'; ?> class="absolute inset-0 pointer-events-none z-0">
            <div class="absolute inset-0 bg-divider/20 bg_dotted_pattern"></div>
            <?php if ($type === 'lines'): ?>
                <svg class="absolute inset-0 rounded-2xl size-full stroke-divider/90 dark:stroke-muted/10" fill="none"
                     aria-hidden="true">
                    <defs>
                        <pattern id="pattern-<?= Base::h($id) ?>" x="0" y="0" width="8" height="8"
                                 patternUnits="userSpaceOnUse">
                            <path d="M-1 5L5 -1M3 9L8.5 3.5" stroke-width="0.5"></path>
                        </pattern>
                    </defs>
                    <rect stroke="none" fill="url(#pattern-<?= Base::h($id) ?>)" width="100%" height="100%"></rect>
                </svg>
            <?php endif; ?>
        </div>
        <?php
        return ob_get_clean();
    }

    /**
     * Renders the global Journey/Performance toggle for page headers.
     */
    public static function renderGlobalToggle(string $page): string
    {
        $store = ($page === 'trigger' ? 'trigger' : ($page === 'audience' ? 'audience' : 'newsletter'));
        $saveUrl = Router::url('save_module_config', ['partial' => 1, 'module' => 'ui', 'context' => $page]);

        return TabsGroup::render([
            ['value' => 'performance', 'label' => mh_lng('MAILBEEZ_VIEW_PERFORMANCE', 'Performance'), 'icon' => Base::SVG_ROCKET],
            ['value' => 'journey', 'label' => mh_lng('MAILBEEZ_VIEW_JOURNEY', 'Flow'), 'icon' => Base::SVG_ROUTE],
        ], [
            'model' => '$store.' . $store . '.viewMode',
            'size' => 'sm',
            'class' => '',
            'attrs' => [
                '@click' => '$nextTick(() => htmx.ajax(\'POST\', \'' . $saveUrl . '\', { values: { view_mode: $store.' . $store . '.viewMode }, swap: \'none\' }))'
            ]
        ]);
    }

    /**
     * Renders an alternative global Journey/Performance toggle that includes a timeframe selector for Performance mode.
     */
    public static function renderGlobalPerformanceToggle(string $page): string
    {
        $store = ($page === 'trigger' ? 'trigger' : ($page === 'audience' ? 'audience' : 'newsletter'));
        $saveUrl = Router::url('save_module_config', ['partial' => 1, 'module' => 'ui', 'context' => $page]);
        $storePath = '$store.' . $store;

        $timeframes = [
            ['label' => '1d', 'value' => '1day'],
            ['label' => '7d', 'value' => '7days'],
            ['label' => '14d', 'value' => '14days'],
            ['label' => '30d', 'value' => '30days'],
            ['label' => 'MTD', 'value' => 'MTD'],
            ['label' => 'YTD', 'value' => 'YTD'],
            ['label' => 'All', 'value' => 'all'],
        ];
        $timeframesJson = json_encode($timeframes);

        $defaultTimeFrame = 'all'; //'30days';
        ob_start();
        ?>
        <div class="flex items-center" x-data="{
            open: false,
            timeframes: <?= Base::h($timeframesJson, false) ?>,
            get viewMode() { return <?= $storePath ?> ? <?= $storePath ?>.viewMode : 'journey' },
            get timeframe() { return <?= $storePath ?> ? <?= $storePath ?>.performanceTimeframe : '<?= $defaultTimeFrame ?>' },
            getTimeframeLabel(val) {
                const item = this.timeframes.find(t => t.value === val);
                return item ? item.label : val;
            },
            saveViewMode(val) {
                if (<?= $storePath ?>) <?= $storePath ?>.viewMode = val;
                $nextTick(() => htmx.ajax('POST', '<?= $saveUrl ?>', { values: { view_mode: val }, swap: 'none' }));
            },
            saveTimeframe(val) {
                if (<?= $storePath ?>) <?= $storePath ?>.performanceTimeframe = val;
                this.open = false;
                $nextTick(() => htmx.ajax('POST', '<?= $saveUrl ?>', { values: { performance_timeframe: val }, swap: 'none' }));
            }
        }">
            <div class="flex p-1 gap-0.5 rounded-lg bg-gray-100 dark:bg-gray-800/60 relative">
                <!-- Performance Tab -->
                <div class="relative flex items-center">
                    <button type="button"
                            @click="saveViewMode('performance')"
                            class="px-2.5 py-1 text-sm rounded-md font-medium transition-all flex items-center gap-1.5 focus:outline-none group"
                            :class="viewMode === 'performance' ? 'bg-white text-gray-900 dark:bg-gray-600 dark:text-white' : 'text-gray-500 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-200'"
                    >
                        <span class="shrink-0 [&_svg]:size-4 transition-colors" :class="viewMode === 'performance' ? 'text-gray-900' : 'text-gray-500 group-hover:text-gray-600 dark:text-gray-500 dark:group-hover:text-gray-300'"><?= Base::SVG_ROCKET ?></span>
                        <span><?= mh_lng('MAILBEEZ_VIEW_PERFORMANCE', 'Performance') ?></span>

                        <div x-show="viewMode === 'performance'"
                             x-cloak
                             @click.stop="open = !open"
                             class="flex items-center h-4 ml-2 pl-2 border-l border-gray-200 dark:border-gray-500 gap-1 group/tf"
                        >
                            <span class="flex items-center gap-1 px-1.5 py-1 rounded-md bg-brand/10 text-brand text-[11px] font-bold leading-none transition-colors group-hover/tf:bg-brand/20">
                                <span class="shrink-0 [&_svg]:size-3.5"><?= Base::SVG_OUTLINE_CALENDAR ?></span>
                                <span x-text="getTimeframeLabel(timeframe)"></span>
                            </span>
                            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-4 text-gray-500 transition-transform" :class="open ? 'rotate-180' : ''">
                                <path fill-rule="evenodd" d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
                            </svg>
                        </div>
                    </button>

                    <!-- Popover -->
                    <div x-show="open"
                         x-cloak
                         @click.away="open = false"
                         x-transition:enter="transition ease-out duration-100"
                         x-transition:enter-start="opacity-0 scale-95"
                         x-transition:enter-end="opacity-100 scale-100"
                         x-transition:leave="transition ease-in duration-75"
                         x-transition:leave-start="opacity-100 scale-100"
                         x-transition:leave-end="opacity-0 scale-95"
                         class="absolute top-full right-0 mt-2 p-1 bg-white dark:bg-zinc-800 border border-divider rounded-lg shadow-lg z-50 flex gap-0.5 min-w-max"
                    >
                        <template x-for="item in timeframes" :key="item.value">
                            <button type="button"
                                    @click.stop="saveTimeframe(item.value)"
                                    class="px-3 py-2 text-xs rounded-md font-medium transition-all focus:outline-none"
                                    :class="timeframe === item.value ? 'bg-brand/10 text-brand' : 'text-secondary hover:bg-gray-100 dark:hover:bg-white/5'"
                            >
                                <span x-text="item.label"></span>
                            </button>
                        </template>
                    </div>
                </div>

                <!-- Journey Tab -->
                <button type="button"
                        @click="saveViewMode('journey')"
                        class="px-2.5 py-1 text-sm rounded-md font-medium transition-all flex items-center gap-1.5 focus:outline-none group"
                        :class="viewMode === 'journey' ? 'bg-white text-gray-900  dark:bg-gray-600 dark:text-white' : 'text-gray-500 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-200'"
                >
                    <span class="shrink-0 [&_svg]:size-4 transition-colors" :class="viewMode === 'journey' ? 'text-gray-900' : 'text-gray-500 group-hover:text-gray-600 dark:text-gray-500 dark:group-hover:text-gray-300'"><?= Base::SVG_ROUTE ?></span>
                    <span><?= mh_lng('MAILBEEZ_VIEW_JOURNEY', 'Flow') ?></span>
                </button>
            </div>
        </div>
        <?php
        return ob_get_clean();
    }

    /**
     * Renders the Performance (KPI) panel wrapper for lazy loading via HTMX.
     */
    public static function renderPerformancePanel(string $url, string $loaderId, string $initialContent = '', string $id = '', string $currentViewMode = 'journey'): string
    {
        ob_start();
        ?>
        <div x-show="localViewMode === 'performance'" 
             x-cloak
             <?php if ($currentViewMode !== 'performance') echo 'style="display: none;"'; ?>
             <?= $id ? 'id="performance-panel-' . Base::h($id) . '"' : '' ?>
             class="min-h-[80px] rounded-lg relative z-10"
        >
            <?= $initialContent ?>
        </div>
        <?php
        return ob_get_clean();
    }
}
