<?php
// pages/components/campaigns_layout_list.php
// Renders campaign modules as a full-width list (small cards/rows)
// Expects: $modulesByTouchpoint

use Components\Button;
use Components\CampaignFlow\FlowViz;
use Components\Form\Toggle;
use Components\ConfigStore;
use Components\Router;
use Components\Base;
use Components\Ui\ExpandControls;
use Components\Ui\GroupSection;
use Components\Ui\FilterPills;


if (!isset($modulesByTouchpoint) || !is_array($modulesByTouchpoint)) {
    $modulesByTouchpoint = [];
}

$filterLabelMap = \beez::groupLabels();


// Control whether to render grouped sections or a flat list
$__grouped = isset($grouped) ? (bool) $grouped : true;

// Collect all module keys to initialize Alpine openMap
$__allKeys = [];
foreach ($modulesByTouchpoint as $__grp => $__mods) {
    if (!is_array($__mods)) continue;
    foreach ($__mods as $__m) {
        if (isset($__m['key'])) $__allKeys[] = (string)$__m['key'];
    }
}
$__allKeys = array_values(array_unique($__allKeys));

// Precompute module status/configuration state once for all visible keys.
$__moduleStateMap = [];
foreach ($__allKeys as $__mKey) {
    if ($__mKey === '') {
        continue;
    }
    $__mOn = ConfigStore::isModuleOn($__mKey);
    $__mConfigured = ConfigStore::isConfigured($__mKey);
    $__moduleStateMap[$__mKey] = [
        'on' => (bool)$__mOn,
        'configured' => (bool)$__mConfigured,
        'inactive' => (!$__mOn && $__mConfigured),
    ];
}

$__openMap = ConfigStore::getUiOpenMap();
// Ensure all keys are present (default false) for Alpine
foreach ($__allKeys as $__k) {
    if (!isset($__openMap[$__k])) {
        $__openMap[$__k] = false;
    }
}

// Force expand newly installed module or module from open_module URL param
$installedModule = \Components\Common\Request::get('installed_module', '', 'key');
if ($installedModule !== '' && in_array($installedModule, $__allKeys)) {
    $__openMap[$installedModule] = true;
}
$openModule = \Components\Common\Request::get('open_module', '', 'key');
if ($openModule !== '' && in_array($openModule, $__allKeys)) {
    $__openMap[$openModule] = true;
}

// Limit to keys present on this page to avoid mixed states from other pages
$__openMap = array_intersect_key($__openMap, array_flip($__allKeys));
// Compute initial global state to avoid wrong button visibility before Alpine initializes
$__allOpenInit = !empty($__openMap) && !in_array(false, $__openMap, true);
$__allClosedInit = !empty($__openMap) && !in_array(true, $__openMap, true);

// Ensure required context variables exist when this partial is included independently
if (!isset($subtabParam)) { $subtabParam = \Components\Router::subtabParam(); }
if (!isset($hasFilter)) { $hasFilter = false; }
if (!isset($selectedGroup)) { $selectedGroup = ''; }
// For group/ungroup actions, we want to target the specified container or default to the trigger page main container
if (!isset($targetContainer)) {
    $targetContainer = \Components\Data\DataRegistry::navigation()->getTargetId('trigger');
}

// When grouped: provide an Ungroup action inside every section's layout dropdown menu
$__inactiveMenuItems = [
    [
        'label' => \mh_lng('UI_SHOW_INACTIVE', 'Show inactive'),
        'icon'  => \Components\Base::SVG_EYE,
        'attrs' => [
            'x-show' => '$store.trigger && !$store.trigger.showInactive',
            '@click.stop' => '$store.trigger.showInactive = true',
        ],
    ],
    [
        'label' => \mh_lng('UI_HIDE_INACTIVE', 'Hide inactive'),
        'icon'  => \Components\Base::SVG_EYE_SLASH,
        'attrs' => [
            'x-show' => '$store.trigger && $store.trigger.showInactive',
            '@click.stop' => '$store.trigger.showInactive = false',
        ],
    ],
];

$__argsUngroup = ['partial' => 1, 'section' => 'prebuild', 'layout' => ($layout ?? 'list'), $subtabParam => 'prebuild', 'grouped' => 0];
if ($hasFilter && $selectedGroup !== '') { $__argsUngroup['group'] = $selectedGroup; }
$__extraMenuUngroup = array_merge($__inactiveMenuItems, [['divider' => true], [
    'label' => \mh_lng('UI_UNGROUP', 'Ungroup'),
    'icon'  => \Components\Base::SVG_UNDO,
    'attrs' => [
        '@click.stop' => '',
        'hx-get'   => \Components\Router::url('trigger', $__argsUngroup),
        'hx-target'=> $targetContainer,
        'hx-swap'  => 'innerHTML',
    ],
]]);
?>
<?php
ob_start();
?>
{
        openMap: <?= json_encode($__openMap, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); ?>,
        overswingMap: {},
        overswingExpandingMap: {},
        init() {
            if (typeof this.active !== 'undefined' && this.active === 'trigger' && this.openKey) {
                if (this.openMap.hasOwnProperty(this.openKey)) {
                    if (window.Alpine && window.Alpine.store('trigger')) window.Alpine.store('trigger').showInactive = true;
                    this.filterActive = 'ALL';
                    this.expandSome([this.openKey]);
                }
            }
        },
        triggerOverswing(id) { <?php echo Base::overswingAlpineTrigger('this.overswingMap[id]'); ?> },
        triggerOverswingExpanding(id) { <?php echo Base::overswingAlpineTrigger('this.overswingExpandingMap[id]'); ?> },
        // Filter state for ungrouped view
        filterActive: 'ALL',
        setFilter(v) { this.filterActive = v; },
        isFilter(v) { return this.filterActive === v; },
        toggle(id) {
            const wasOpen = this.openMap[id];
            this.openMap[id] = !wasOpen;
            if (wasOpen) {
                this.triggerOverswing(id);
            } else {
                this.triggerOverswingExpanding(id);
            }
        },
        persistAllOpen() {
            // Single bulk save of all open states via HTMX
            const saver = (this.$refs && this.$refs.bulkSaver) ? this.$refs.bulkSaver : document.getElementById('bulk-open-saver');
            if (saver) {
                saver.dispatchEvent(new CustomEvent('save-open-bulk', { bubbles: true }));
            }
        },
        expandAll() {
            Object.keys(this.openMap).forEach(k => {
                const wasOpen = this.openMap[k];
                this.openMap[k] = true;
                if (!wasOpen) this.triggerOverswingExpanding(k);
            });
            this.$nextTick(() => this.persistAllOpen());
        },
        collapseAll() {
            Object.keys(this.openMap).forEach(k => {
                const wasOpen = this.openMap[k];
                this.openMap[k] = false;
                if (wasOpen) this.triggerOverswing(k);
            });
            this.$nextTick(() => this.persistAllOpen());
        },
        allOpen() { return Object.values(this.openMap).every(v => v === true); },
        allClosed() { return Object.values(this.openMap).every(v => v === false); },
        // Group-scoped helpers used by GroupSection ExpandControls
        expandSome(keys) {
            if (!Array.isArray(keys)) return;
            keys.forEach(k => {
                if (k in this.openMap) {
                    const wasOpen = this.openMap[k];
                    this.openMap[k] = true;
                    if (!wasOpen) this.triggerOverswingExpanding(k);
                }
            });
            this.$nextTick(() => this.persistAllOpen());
        },
        collapseSome(keys) {
            if (!Array.isArray(keys)) return;
            keys.forEach(k => {
                if (k in this.openMap) {
                    const wasOpen = this.openMap[k];
                    this.openMap[k] = false;
                    if (wasOpen) this.triggerOverswing(k);
                }
            });
            this.$nextTick(() => this.persistAllOpen());
        },
        allOpenSome(keys) {
            if (!Array.isArray(keys) || keys.length === 0) return false;
            return keys.every(k => this.openMap[k] === true);
        },
        allClosedSome(keys) {
            if (!Array.isArray(keys) || keys.length === 0) return false;
            return keys.every(k => this.openMap[k] === false);
        }
    }
<?php
$xDataTrigger = ob_get_clean();
?>
<div x-data="<?= Base::h($xDataTrigger, false); ?>" x-ref="root"
    @mb:open-module.window="if ($event.detail.module && openMap.hasOwnProperty($event.detail.module)) { if ($store.trigger) $store.trigger.showInactive = true; filterActive = 'ALL'; expandSome([$event.detail.module]); }"
>

    <input type="hidden" id="bulk-open-json" name="open_map" :value="JSON.stringify(openMap)" />
    <div id="bulk-open-saver" x-ref="bulkSaver" class="hidden" data-no-global-loader="1"
         hx-post="<?= Router::url('save_ui_open_bulk', ['partial' => 1]); ?>"
         hx-trigger="save-open-bulk"
         hx-include="#bulk-open-json"
         hx-swap="none"></div>

    <?php if ($__grouped): ?>
        <?php foreach ($modulesByTouchpoint as $group => $modules):
            $groupKey = (string)$group;
            $groupLabel = $filterLabelMap[$groupKey] ?? $groupKey;
            ob_start();
            foreach ($modules as $m) {
                $__mKey = (string)($m['key'] ?? '');
                $__state = $__moduleStateMap[$__mKey] ?? ['on' => false, 'configured' => false, 'inactive' => false];
                // Optional filter: hide inactive (configured but turned off) when requested
                if (isset($showInactive) && !$showInactive && $__state['inactive']) {
                    continue;
                }
                $__precomputedIsOn = (bool)$__state['on'];
                $__precomputedIsConfigured = (bool)$__state['configured'];
                echo '<div :class="{
                               \'animate-overswing-itemlist\': (typeof layout === \'undefined\' || layout === \'stack\') && overswingMap[\'' . Base::h($__mKey) . '\'],
                               \'animate-overswing-expanding-itemlist\': (typeof layout === \'undefined\' || layout === \'stack\') && overswingExpandingMap[\'' . Base::h($__mKey) . '\']
                           }">';
                include __DIR__ . '/trigger_module.php';
                unset($__precomputedIsOn, $__precomputedIsConfigured);
                echo '</div>';
            }
            $groupContent = ob_get_clean();

            // Prepare group-scoped expand/collapse initial state hints and keys
            $__groupKeys = [];
            foreach ($modules as $__m) { if (isset($__m['key'])) { $__groupKeys[] = (string)$__m['key']; } }
            $__groupKeys = array_values(array_unique($__groupKeys));
            $__groupOpenMap = array_intersect_key($__openMap, array_flip($__groupKeys));
            $__grpAllOpenInit = !empty($__groupOpenMap) && !in_array(false, $__groupOpenMap, true);
            $__grpAllClosedInit = !empty($__groupOpenMap) && !in_array(true, $__groupOpenMap, true);

            echo GroupSection::render($groupLabel, $groupContent, [
                'section_class' => 'mb-8 mt-4',
                'expand_controls' => true,
                'expand_group_keys' => $__groupKeys,
                'expand_all_open_init' => $__grpAllOpenInit,
                'expand_all_closed_init' => $__grpAllClosedInit,
                'layout_controls_options' => [
                    'extra_items' => $__extraMenuUngroup,
                    'divider_before_extra' => true,
                ],
            ]);
        endforeach; ?>
    <?php else: ?>
        <?php
        // Ungrouped view: render all modules within a single GroupSection so
        // we can reuse expand/collapse controls across the full list
        ob_start();
        foreach ($modulesByTouchpoint as $group => $modules) {
            if (!is_array($modules)) continue;
            // Use a data attribute to avoid quote-escaping issues in Alpine expressions
            $groupAttr = Base::h((string)$group, false);
            foreach ($modules as $m) {
                $__mKey = (string)($m['key'] ?? '');
                $__state = $__moduleStateMap[$__mKey] ?? ['on' => false, 'configured' => false, 'inactive' => false];
                // Optional filter: hide inactive (configured but turned off) when requested
                if (isset($showInactive) && !$showInactive && $__state['inactive']) {
                    continue;
                }
                // Compute data-inactive for the wrapper so x-show can hide the whole grid cell
                // (avoids empty cells in multi-column layouts when inactive modules are toggled off)
                $__mInactiveCfg = $__state['inactive'] ? '1' : '0';
                $__mInactiveAttr = Base::h($__mInactiveCfg, false);
                $__precomputedIsOn = (bool)$__state['on'];
                $__precomputedIsConfigured = (bool)$__state['configured'];
                echo '<div x-show="(filterActive===\'ALL\' || filterActive===$el.dataset.group) && ($store.trigger ? ($store.trigger.showInactive || $el.dataset.inactive !== \'1\') : true)" 
                           data-group="' . $groupAttr . '" 
                           data-inactive="' . $__mInactiveAttr . '"
                           :class="{
                               \'animate-overswing-itemlist\': (typeof layout === \'undefined\' || layout === \'stack\') && overswingMap[\'' . Base::h($__mKey) . '\'],
                               \'animate-overswing-expanding-itemlist\': (typeof layout === \'undefined\' || layout === \'stack\') && overswingExpandingMap[\'' . Base::h($__mKey) . '\']
                           }">';
                include __DIR__ . '/trigger_module.php';
                unset($__precomputedIsOn, $__precomputedIsConfigured);
                echo '</div>';
            }
        }
        $groupContent = ob_get_clean();

        // Keys for the whole (flat) list reuse the already prepared $__allKeys
        $__flatKeys = array_values(array_unique($__allKeys));

        // Build filter pills for header using Button UI
        $__filters = [];
        foreach ($modulesByTouchpoint as $grp => $mods) {
            if (!is_array($mods)) continue;
            $__filters[] = (string)$grp;
        }
        $__filters = array_values(array_unique($__filters));

        $headerFilters = FilterPills::render($__filters, ['labels_map' => $filterLabelMap]);

        // Provide a stable list_id for ungrouped view so layout can be saved/applied
        // When viewing the flat (ungrouped) list, move the "Group by touchpoint" action
        // into the ListLayout (ellipsis) menu as an extra item.
        $argsPartial = ['partial' => 1, 'section' => 'prebuild', 'layout' => ($layout ?? 'list'), $subtabParam => 'prebuild', 'grouped' => 1];
        if ($hasFilter && $selectedGroup !== '') { $argsPartial['group'] = $selectedGroup; }
        $extraMenuItems = array_merge($__inactiveMenuItems, [['divider' => true], [
            'label' => \mh_lng('UI_GROUP_BY_TOUCHPOINT', 'Group by touchpoint'),
            'icon'  => \Components\Base::SVG_BARS_4,
            'attrs' => [
                '@click.stop' => '',
                'hx-get'   => \Components\Router::url('trigger', $argsPartial),
                'hx-target'=> $targetContainer,
                'hx-swap'  => 'innerHTML',
            ],
        ]]);

        echo GroupSection::render('', $groupContent, [
            'section_class' => 'mb-8 mt-4',
            'expand_controls' => true,
            'expand_group_keys' => $__flatKeys,
            // Use global initial state hints computed above for proper button visibility
            'expand_all_open_init' => $__allOpenInit,
            'expand_all_closed_init' => $__allClosedInit,
            // Inject filter pills into header (left side)
            'header_left' => $headerFilters,
            // Persist list layout for the ungrouped list under a dedicated id
            'list_id' => 'trigger_list_ungrouped',
            // Add extra action to the layout dropdown menu
            'layout_controls_options' => [
                'extra_items' => $extraMenuItems,
                'divider_before_extra' => true,
            ],
        ]);
        ?>
    <?php endif; ?>
</div>
