<?php
// pages/components/save_ui_open_bulk.php
// Bulk endpoint to persist UI open/closed state for multiple modules in a single request
// Expects POST: open_map => JSON string of { key: 'on'|''|true|false|1|0 }
// Key validation:
// - legacy: a known module key (validated against ModuleLoader::all())
// - generic: a namespaced key containing ':' (e.g. "audience-list:123") used by ItemList; must match [A-Za-z0-9:_-]+

use Components\Base;
use Components\ModuleLoader;
use Components\ConfigStore;
use Components\Models\NewsletterItem;

// Parse incoming JSON map
$raw = mh_post('open_map', '', 'string');
if ($raw === '') {
    http_response_code(400);
    echo '<div class="text-sm text-red-600">Missing payload</div>';
    return;
}
$map = json_decode($raw, true);
if (!is_array($map)) {
    http_response_code(400);
    echo '<div class="text-sm text-red-600">Invalid payload</div>';
    return;
}

// Validate against known modules
try {
    $all = ModuleLoader::all();
} catch (\Throwable $e) {
    $all = [];
}

$updated = 0;
foreach ($map as $module => $state) {
    if (!is_string($module) || $module === '') {
        continue;
    }
    // allow legacy known modules or generic namespaced keys containing ':'
    $hasColon = strpos($module, ':') !== false;
    $isValidGeneric = $hasColon && preg_match('/^[A-Za-z0-9:_-]+$/', $module) === 1;
    $isValidLegacy = isset($all[$module]);
    if (!$isValidGeneric && !$isValidLegacy) {
        continue; // skip keys that are neither known modules nor valid namespaced keys
    }
    // Normalize truthy/falsey to boolean
    $on = ($state === 'on' || $state === '1' || $state === 1 || $state === true || $state === 'true');
    ConfigStore::setUiOpenState($module, $on);

    // If collapsing a newsletter/automation flow, update its last_modified timestamp
    // so it's no longer considered "newly created" for highlighting purposes.
    if (!$on && $hasColon) {
        list($prefix, $id) = explode(':', $module, 2);
        if ($prefix === 'newsletter-flow' || $prefix === 'automation-flow') {
            NewsletterItem::updateLastModifiedIfNull((int)$id);
        }
    }

    $updated++;
}

// Nothing to update is still a success (no-op)
if (\Components\Support\Htmx::isRequest()) {
    // For HTMX, we can return 204 to avoid any swap
    if ($updated >= 0) {
        http_response_code(204);
        return;
    }
}

// Non-HTMX fallback: simple confirmation message
$label = $updated === 1 ? 'module' : 'modules';
echo '<div class="text-sm text-green-600">Updated ' . Base::h((string)$updated) . ' ' . $label . '.</div>';
