<?php

declare(strict_types=1);

require_once dirname(__DIR__, 3) . '/system/bootstrap.php';

$currentUser = myronRequireAdministrationAccess();
$repository = myronOnboardingStateRepository();
$selectionService = myronSiteSetupSelectionService();
$defaultReplacementService = myronSiteSetupDefaultReplacementService();
$templateRepository = myronTemplateDefinitionRepository();
$contentRepository = myronContentRepository();
$stageGate = myronSiteTypeStageGateService();
$entitlementPresentation = myronEntitlementPresentationPolicy();
$siteTypes = $entitlementPresentation->visibleSiteTypes($stageGate->visibleSiteTypes(myronSiteTypeRegistryRepository()->listSiteTypes()));
$bundleRepository = myronBundleActivationRepository();
$csrfToken = myronCsrfToken();
$bootstrapActiveBundle = static function (string $primaryBundleId, array $options = []): array {
    $result = myronBundleBootstrapService()->bootstrap($primaryBundleId, $options);
    $missingTemplates = array_values(array_map('strval', (array) ($result['missingTemplates'] ?? [])));
    if ($missingTemplates !== []) {
        throw new RuntimeException('Packaged template integrity check failed. Missing templates: ' . implode(', ', $missingTemplates));
    }

    $result['message'] = 'Synced ' . (string) ($result['bundleId'] ?? $primaryBundleId) . ': '
        . count((array) ($result['runtimeTemplates'] ?? [])) . ' templates, '
        . count((array) ($result['runtimePages'] ?? [])) . ' pages.';

    return $result;
};
$bootstrapOptionsForSiteSetup = static function (string $pageSyncMode): array {
    if ($pageSyncMode === 'replace') {
        return [];
    }

    return [
        'syncExistingTemplates' => false,
        'syncExistingPageIdentity' => false,
        'claimPathMatches' => false,
        'collisionPolicy' => 'skip',
        'syncMenus' => false,
        'writeSeedRecords' => false,
    ];
};
$jsonForScript = static function (array $payload): string {
    return json_encode(
        $payload,
        JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT
    );
};

if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
    try {
        myronRequireCsrf($_POST['csrf_token'] ?? null);
        $action = trim((string) ($_POST['action'] ?? ''));

        if ($action === 'save-site-setup') {
            $previousState = $repository->getState();
            $previousPrimaryBundleId = trim((string) ($previousState['primary_bundle_id'] ?? ''));
            $postedPrimaryBundleId = trim((string) ($_POST['primary_bundle_id'] ?? ''));
            if ($postedPrimaryBundleId !== '' && $previousPrimaryBundleId !== '' && $postedPrimaryBundleId !== $previousPrimaryBundleId && !myronUserHoldsScope($currentUser, MyronApiScopes::ADMINISTRATION_DESTRUCTIVE)) {
                throw new RuntimeException('Changing the primary site type requires destructive Administration access.');
            }
            $projectionPrimaryBundleId = trim((string) ($_POST['selection_projection_primary_id'] ?? ''));
            $shouldProjectDescendantDefaults = false;
            $pageSyncMode = trim((string) ($_POST['page_sync_mode'] ?? 'keep'));
            if (!in_array($pageSyncMode, ['replace', 'keep', 'choose'], true)) {
                $pageSyncMode = 'keep';
            }
            $templateReplacementChoices = is_array($_POST['template_replacement_choices'] ?? null) ? $_POST['template_replacement_choices'] : [];
            $pageReplacementChoices = is_array($_POST['page_replacement_choices'] ?? null) ? $_POST['page_replacement_choices'] : [];
            $replaceDefaultPages = $pageSyncMode === 'replace'
                || (string) ($_POST['replace_default_pages'] ?? '') === '1';
            if ($replaceDefaultPages) {
                $defaultReplacementService->assertConfirmed((string) ($_POST['confirm_default_page_replacement'] ?? ''));
            }

            $state = $repository->saveState([
                'primary_bundle_id' => trim((string) ($_POST['primary_bundle_id'] ?? '')),
                'archetype_theme_id' => trim((string) ($_POST['archetype_theme_id'] ?? '')),
                'active_bundle_ids' => array_values(array_merge(
                    is_array($_POST['included_bundle_ids'] ?? null) ? $_POST['included_bundle_ids'] : [],
                    is_array($_POST['included_subtype_ids'] ?? null) ? $_POST['included_subtype_ids'] : [],
                )),
                'selection_manifest' => [
                    'included_bundle_ids' => array_values(array_merge(
                        is_array($_POST['included_bundle_ids'] ?? null) ? $_POST['included_bundle_ids'] : [],
                        is_array($_POST['included_subtype_ids'] ?? null) ? $_POST['included_subtype_ids'] : [],
                    )),
                    'selected_template_ids' => is_array($_POST['selected_template_ids'] ?? null) ? $_POST['selected_template_ids'] : [],
                    'selected_template_keys' => is_array($_POST['selected_template_keys'] ?? null) ? $_POST['selected_template_keys'] : [],
                    'include_descendant_defaults' => $shouldProjectDescendantDefaults,
                ],
                'apply_theme' => (string) ($_POST['apply_theme'] ?? '') === '1',
            ], (string) $currentUser['id']);
            $selectionManifest = is_array($state['selection_manifest'] ?? null) ? $state['selection_manifest'] : [];
            $selectedSourceTemplateIds = array_values(array_map('strval', is_array($selectionManifest['selected_template_ids'] ?? null) ? $selectionManifest['selected_template_ids'] : []));
            $recommendedFooterVariant = $pageSyncMode === 'replace'
                ? $defaultReplacementService->seedFooterForPrimaryBundle(
                    (string) ($state['primary_bundle_id'] ?? ''),
                    (string) $currentUser['id']
                )
                : '';
            $replacementResult = $replaceDefaultPages
                ? $defaultReplacementService->replacePrimaryDefaults($previousPrimaryBundleId, (string) ($state['primary_bundle_id'] ?? ''))
                : null;
            $cleanupResult = $pageSyncMode === 'replace'
                ? $defaultReplacementService->pruneUnselectedSourceLinkedContent($selectedSourceTemplateIds)
                : ['deletedPages' => [], 'deletedTemplates' => [], 'retainedTemplates' => []];
            $bootstrapResult = $bootstrapActiveBundle(
                (string) ($state['primary_bundle_id'] ?? ''),
                $bootstrapOptionsForSiteSetup($pageSyncMode)
            );
            $message = (string) ($bootstrapResult['message'] ?? '');
            if (is_array($replacementResult)) {
                $message .= ' Replaced ' . count((array) ($replacementResult['deletedPages'] ?? [])) . ' existing default pages.';
            }
            $preservedPages = count((array) ($bootstrapResult['preservedPages'] ?? []));
            $skippedPages = count((array) ($bootstrapResult['skippedPages'] ?? []));
            if ($pageSyncMode !== 'replace') {
                $message .= ' Keep mode preserved existing pages, templates, menus, footer settings, route ownership, SEO, and publication state.';
                if ($preservedPages > 0) {
                    $message .= ' Preserved ' . $preservedPages . ' existing source-linked pages.';
                }
                if ($skippedPages > 0) {
                    $message .= ' Skipped ' . $skippedPages . ' route collision(s) without claiming or renaming existing pages.';
                }
            }
            $removedPages = count((array) ($cleanupResult['deletedPages'] ?? []));
            $removedTemplates = count((array) ($cleanupResult['deletedTemplates'] ?? []));
            if ($removedPages > 0 || $removedTemplates > 0) {
                $message .= ' Removed ' . $removedPages . ' unselected source-linked pages and ' . $removedTemplates . ' runtime templates.';
            }
            $retainedTemplates = count((array) ($cleanupResult['retainedTemplates'] ?? []));
            if ($retainedTemplates > 0) {
                $message .= ' Retained ' . $retainedTemplates . ' runtime templates still used by manual pages.';
            }
            if ($recommendedFooterVariant !== '') {
                $message .= ' Footer recommendation: ' . $recommendedFooterVariant . '.';
            }
            if ($pageSyncMode === 'choose') {
                $message .= ' Migration report: explicit replacement selections are recorded for review; unselected existing pages/templates are preserved unless Replace Default Pages is confirmed.';
            }

            myronRedirectWithFlash(myronBuildAdminUrl('administration.siteSetup'), 'Site setup saved. ' . $message, 'success');
        }

        if ($action === 'reset-site-baseline') {
            if (!myronUserHoldsScope($currentUser, MyronApiScopes::ADMINISTRATION_DESTRUCTIVE)) {
                throw new RuntimeException('Site reset requires destructive Administration access.');
            }
            if ((string) ($_POST['confirm_site_reset'] ?? '') !== '1') {
                throw new RuntimeException('Confirm the site reset before continuing.');
            }

            $resetService = myronSiteResetService();
            $resetService->assertConfirmed((string) ($_POST['confirm_site_reset_phrase'] ?? ''));
            $result = $resetService->resetToBaseline((string) $currentUser['id']);
            myronRefreshSiteSettingsCache();
            $removedDesignSystems = count((array) ($result['designSystems']['removed'] ?? []));
            $deletedFiles = (int) ($result['files']['recordsDeleted'] ?? 0);
            myronRedirectWithFlash(
                myronBuildAdminUrl('administration.siteSetup'),
                'Site reset to baseline. Restored Home and About, cleared configured site types, removed ' . $removedDesignSystems . ' stored design systems and ' . $deletedFiles . ' uploaded files.',
                'success'
            );
        }

        if ($action === 'disable-site-type-bundle') {
            if (!myronUserHoldsScope($currentUser, MyronApiScopes::ADMINISTRATION_WRITE)) {
                throw new RuntimeException('Disabling site type bundles requires Administration write access.');
            }
            $caller = new MyronActionCallerContext(
                'human-session',
                (string) $currentUser['id'],
                [MyronApiScopes::ADMINISTRATION_READ, MyronApiScopes::ADMINISTRATION_WRITE]
            );
            $result = myronBundleDisableService()->disable(
                (string) ($_POST['bundle_id'] ?? ''),
                ['default_fallback_url' => (string) ($_POST['default_fallback_url'] ?? '/')],
                $caller
            );
            myronRedirectWithFlash(
                myronBuildAdminUrl('administration.siteSetup') . '#site-type-bundles-title',
                'Bundle disabled. ' . (int) ($result['summary']['pages_disabled'] ?? 0) . ' pages disabled and ' . (int) ($result['summary']['redirects_created'] ?? 0) . ' redirects created.',
                'success'
            );
        }

        if ($action === 'enable-site-type-bundle') {
            if (!myronUserHoldsScope($currentUser, MyronApiScopes::ADMINISTRATION_WRITE)) {
                throw new RuntimeException('Re-enabling site type bundles requires Administration write access.');
            }
            $caller = new MyronActionCallerContext(
                'human-session',
                (string) $currentUser['id'],
                [MyronApiScopes::ADMINISTRATION_READ, MyronApiScopes::ADMINISTRATION_WRITE]
            );
            $result = myronBundleEnableService()->enable(
                (string) ($_POST['bundle_id'] ?? ''),
                (string) ($_POST['conflict_resolution'] ?? 'skip'),
                $caller
            );
            myronRedirectWithFlash(
                myronBuildAdminUrl('administration.siteSetup') . '#site-type-bundles-title',
                'Bundle re-enabled. ' . (int) ($result['summary']['pages_restored'] ?? 0) . ' pages restored.',
                'success'
            );
        }

        if ($action === 'apply-application-update') {
            if (!myronUserHoldsScope($currentUser, MyronApiScopes::ADMINISTRATION_DESTRUCTIVE)) {
                throw new RuntimeException('Applying application updates requires destructive Administration access.');
            }

            if ((string) ($_POST['confirm_application_update'] ?? '') !== '1') {
                throw new RuntimeException('Confirm the application update before continuing.');
            }

            $uploadedPackage = is_array($_FILES['update_package'] ?? null) ? $_FILES['update_package'] : [];
            $result = myronApplicationUpdateService()->applyUploadedPackage($uploadedPackage, $currentUser);
            myronRedirectWithFlash(
                myronBuildAdminUrl('administration.siteSetup'),
                'Application update applied. Package ' . (string) ($result['packageId'] ?? '') . ' targets ' . (string) ($result['targetVersion'] ?? '') . '. Applied ' . count((array) ($result['appliedOperations'] ?? [])) . ' file operation(s).',
                'success'
            );
        }

        if ($action === 'apply-remote-application-update') {
            if (!myronUserHoldsScope($currentUser, MyronApiScopes::ADMINISTRATION_DESTRUCTIVE)) {
                throw new RuntimeException('Applying remote application updates requires destructive Administration access.');
            }

            $result = myronRemoteUpdateApplyService()->applyAvailableUpdate($currentUser);
            myronRedirectWithFlash(
                myronBuildAdminUrl('administration.siteSetup') . '#application-update-title',
                'Remote application update applied. Package ' . (string) ($result['packageId'] ?? '') . ' targets ' . (string) ($result['targetVersion'] ?? '') . '. Applied ' . count((array) ($result['appliedOperations'] ?? [])) . ' file operation(s).',
                'success'
            );
        }

        if ($action === 'check-remote-application-update') {
            if (!myronUserHoldsScope($currentUser, MyronApiScopes::ADMINISTRATION_WRITE)) {
                throw new RuntimeException('Checking application updates requires Administration write access.');
            }

            $result = myronRemoteUpdateCheckService()->checkNow(true);
            $tone = in_array((string) ($result['status'] ?? ''), ['check_failed', 'manual_check_cooldown'], true) ? 'error' : 'success';
            myronRedirectWithFlash(
                myronBuildAdminUrl('administration.siteSetup') . '#application-update-title',
                (string) ($result['message'] ?? 'Remote update check completed.'),
                $tone
            );
        }

        if ($action === 'save-remote-update-manifest-url') {
            if (!myronUserHoldsScope($currentUser, MyronApiScopes::ADMINISTRATION_WRITE)) {
                throw new RuntimeException('Updating the remote update path requires Administration write access.');
            }

            $manifestUrl = trim((string) ($_POST['remote_manifest_url'] ?? ''));
            $manifestScheme = strtolower((string) parse_url($manifestUrl, PHP_URL_SCHEME));
            if (filter_var($manifestUrl, FILTER_VALIDATE_URL) === false || $manifestScheme !== 'https') {
                throw new RuntimeException('Remote manifest URL must be a valid HTTPS URL.');
            }

            $remoteUpdateSettings = myronRemoteUpdateSettingsRepository()->get();
            $remoteUpdateSettings['manifest_url'] = $manifestUrl;
            myronRemoteUpdateSettingsRepository()->save($remoteUpdateSettings);
            myronRedirectWithFlash(
                myronBuildAdminUrl('administration.siteSetup') . '#application-update-title',
                'Remote update manifest URL saved.',
                'success'
            );
        }

        if ($action === 'dismiss-remote-application-update') {
            if (!myronUserHoldsScope($currentUser, MyronApiScopes::ADMINISTRATION_WRITE)) {
                throw new RuntimeException('Dismissing application update notices requires Administration write access.');
            }

            myronRemoteUpdateStateRepository()->dismissVersion((string) ($_POST['update_version'] ?? ''));
            myronRedirectWithFlash(
                myronBuildAdminUrl('administration.siteSetup') . '#application-update-title',
                'Application update notice dismissed for this version.',
                'success'
            );
        }

        throw new RuntimeException('Unknown site setup action.');
    } catch (Throwable $exception) {
        myronRedirectWithFlash(myronBuildAdminUrl('administration.siteSetup'), $exception->getMessage(), 'error');
    }
}

$state = $repository->getState();
$themeOptions = $repository->listThemeOptions();
$allBundleState = $bundleRepository->listBundleState();
$activeState = $bundleRepository->listActiveBundles();
$activeIds = array_fill_keys(array_map(static fn (array $state): string => (string) ($state['bundle_id'] ?? ''), $activeState), true);
$bundleStateById = [];
foreach ($allBundleState as $bundleState) {
    $bundleStateById[(string) ($bundleState['bundle_id'] ?? '')] = $bundleState;
}
$selectedPrimaryId = (string) ($state['primary_bundle_id'] ?: ($bundleRepository->getPrimaryBundleId() ?? ''));
$selectedThemeId = (string) ($state['archetype_theme_id'] ?? '');
$primarySiteTypes = array_values(array_filter($siteTypes, static fn (array $siteType): bool => (string) ($siteType['bundleType'] ?? '') === 'primary'));
$subtypeSiteTypes = array_values(array_filter($siteTypes, static fn (array $siteType): bool => (string) ($siteType['bundleType'] ?? '') === 'subtype'));
$visibleSiteTypeIds = array_fill_keys(array_values(array_filter(
    array_map(static fn (array $siteType): string => (string) ($siteType['id'] ?? ''), $siteTypes),
    static fn (string $bundleId): bool => $bundleId !== ''
)), true);
$activeIds = array_intersect_key($activeIds, $visibleSiteTypeIds);
$siteTypeNamesById = [];
foreach ($siteTypes as $siteType) {
    $bundleId = (string) ($siteType['id'] ?? '');
    if ($bundleId !== '') {
        $siteTypeNamesById[$bundleId] = (string) ($siteType['name'] ?? $bundleId);
    }
}
$visiblePrimaryIds = array_fill_keys(array_values(array_map(static fn (array $siteType): string => (string) ($siteType['id'] ?? ''), $primarySiteTypes)), true);
if (($selectedPrimaryId === '' || !isset($visiblePrimaryIds[$selectedPrimaryId])) && is_array($primarySiteTypes[0] ?? null)) {
    $selectedPrimaryId = (string) ($primarySiteTypes[0]['id'] ?? '');
}
$manifest = is_array($state['selection_manifest'] ?? null) ? $state['selection_manifest'] : null;
if ($manifest === null && $selectedPrimaryId !== '') {
    $manifest = $selectionService->defaultSelectionManifestForPrimary($selectedPrimaryId, array_keys($activeIds));
}
if (is_array($manifest) && $selectedPrimaryId !== '' && !is_array($manifest['selected_template_keys'] ?? null)) {
    try {
        $manifest['primary_bundle_id'] = $selectedPrimaryId;
        $manifest = $selectionService->normalizeSelectionManifest($manifest);
    } catch (Throwable) {
        // Keep the persisted manifest visible if legacy normalization cannot repair it.
    }
}
$manifestIncludedIds = array_fill_keys(array_values(array_map('strval', is_array($manifest['included_bundle_ids'] ?? null) ? $manifest['included_bundle_ids'] : [])), true);
$manifestSelectedTemplates = array_fill_keys(array_values(array_map('strval', is_array($manifest['selected_template_ids'] ?? null) ? $manifest['selected_template_ids'] : [])), true);
$manifestSelectedTemplateKeys = array_fill_keys(array_values(array_map(
    [$selectionService, 'normalizeSelectionKey'],
    is_array($manifest['selected_template_keys'] ?? null) ? $manifest['selected_template_keys'] : []
)), true);
$manifestSuppressedTemplateKeys = array_fill_keys(array_values(array_map(
    [$selectionService, 'normalizeSelectionKey'],
    is_array($manifest['suppressed_template_keys'] ?? null) ? $manifest['suppressed_template_keys'] : []
)), true);
$includedIds = $manifestIncludedIds !== [] ? $manifestIncludedIds : $activeIds;
if ($selectedPrimaryId !== '') {
    $includedIds[$selectedPrimaryId] = true;
}
$templatesById = [];
foreach ($templateRepository->listTemplates() as $template) {
    $templateId = (string) ($template['id'] ?? '');
    if ($templateId !== '') {
        $templatesById[$templateId] = $template;
    }
}
$roleLabels = [
    'home' => 'Home',
    'about' => 'About',
    'contact' => 'Contact',
    '404' => '404',
    'search' => 'Search',
    'legal' => 'Legal',
    'services' => 'Services',
    'team' => 'Team',
    'features' => 'Features',
    'pricing' => 'Pricing',
    'blog-index' => 'Blog index',
    'post-single' => 'Post single',
    'category-archive' => 'Category archive',
    'portfolio-index' => 'Portfolio index',
    'project-single' => 'Project single',
    'shop' => 'Shop',
    'product-single' => 'Product single',
    'cart' => 'Cart',
    'checkout' => 'Checkout',
    'account' => 'Account',
    'courses-index' => 'Courses index',
    'course-single' => 'Course single',
    'instructor-index' => 'Instructor index',
    'instructor-single' => 'Instructor single',
    'reservation' => 'Reservation',
    'location' => 'Location',
    'menu' => 'Menu',
    'studio-statement' => 'Studio statement',
    'resources' => 'Resources',
    'featured-offers' => 'Featured offers',
];
$roleOrder = array_fill_keys(array_keys($roleLabels), true);
$roleKeyForTemplate = static fn (array $template): string => $selectionService->roleKeyForTemplate($template);
$labelForRole = static function (string $roleKey) use ($roleLabels): string {
    if (isset($roleLabels[$roleKey])) {
        return $roleLabels[$roleKey];
    }

    return ucwords(str_replace('-', ' ', preg_replace('/^funnel-/', 'funnel ', $roleKey) ?? $roleKey));
};
$buildMatrix = static function (array $bundleRecords) use ($selectionService, $templatesById, $roleKeyForTemplate, $labelForRole, $roleOrder): array {
    $matrix = [];
    foreach ($bundleRecords as $siteType) {
        $bundleId = (string) ($siteType['id'] ?? '');
        foreach ($selectionService->templateIdsForBundle($siteType) as $templateId) {
            if (!isset($templatesById[$templateId])) {
                continue;
            }
            $roleKey = $roleKeyForTemplate($templatesById[$templateId]);
            if (!isset($matrix[$roleKey])) {
                $matrix[$roleKey] = [
                    'label' => $labelForRole($roleKey),
                    'roleKey' => $roleKey,
                    'order' => isset($roleOrder[$roleKey]) ? array_search($roleKey, array_keys($roleOrder), true) : 999,
                    'cells' => [],
                ];
            }
            $matrix[$roleKey]['cells'][$bundleId] = [
                'templateId' => $templateId,
                'template' => $templatesById[$templateId],
                'isDefault' => in_array($templateId, $selectionService->templateIdsForBundle($siteType, true), true),
            ];
        }
    }
    uasort($matrix, static fn (array $a, array $b): int => ((int) ($a['order'] ?? 999)) <=> ((int) ($b['order'] ?? 999)) ?: strcmp((string) ($a['label'] ?? ''), (string) ($b['label'] ?? '')));

    return $matrix;
};
$primaryMatrix = $buildMatrix($primarySiteTypes);
$subtypeMatrix = $buildMatrix($subtypeSiteTypes);
$isTemplateChecked = static function (string $bundleId, string $templateId, bool $isDefault) use ($selectionService, $manifest, $manifestSelectedTemplates, $manifestSelectedTemplateKeys, $includedIds): bool {
    if (is_array($manifest)) {
        $key = $selectionService->templateSelectionKey($bundleId, $templateId);
        if ($manifestSelectedTemplateKeys !== []) {
            return isset($manifestSelectedTemplateKeys[$key]);
        }

        return isset($manifestSelectedTemplates[$templateId]);
    }

    return $isDefault && isset($includedIds[$bundleId]);
};
$parentsForSubtype = static fn (array $siteType): array => $selectionService->parentBundleIds($siteType);
$parentNamesForSubtype = static function (array $siteType) use ($parentsForSubtype, $siteTypeNamesById): array {
    $names = [];
    foreach ($parentsForSubtype($siteType) as $parentId) {
        $names[] = $siteTypeNamesById[$parentId] ?? $parentId;
    }

    return $names;
};
$selectionDefaultsByPrimary = [];
foreach ($primarySiteTypes as $siteType) {
    $bundleId = (string) ($siteType['id'] ?? '');
    if ($bundleId !== '') {
        $selectionDefaultsByPrimary[$bundleId] = $selectionService->defaultSelectionManifestForPrimary($bundleId);
    }
}
$primaryBundleIds = array_values(array_map(static fn (array $siteType): string => (string) ($siteType['id'] ?? ''), $primarySiteTypes));
$primarySiteTypeLabelFor = static fn (array $siteType): string => MyronSiteTypeRegistryRepository::displayLabelForSiteType($siteType);
$runtimeTemplatesForSync = array_values(array_filter(
    $contentRepository->listTemplates(),
    static fn (array $template): bool => trim((string) ($template['source_template_id'] ?? '')) !== ''
));
$pagesForSync = array_values(array_filter(
    $contentRepository->listPagesForManager(),
    static fn (array $page): bool => trim((string) ($page['source_template_id'] ?? '')) !== ''
));
$updateHistory = myronApplicationUpdateAuditRepository()->listRecent(5);
$canApplyApplicationUpdates = myronUserMatchesRoleTerms($currentUser, ['administrator']);
$zipArchiveAvailable = class_exists(ZipArchive::class);
$remoteUpdateSettings = myronRemoteUpdateSettingsRepository()->get();
if ($canApplyApplicationUpdates && !empty($remoteUpdateSettings['auto_check_enabled'])) {
    myronRemoteUpdateCheckService()->checkIfStale();
}
$remoteUpdateState = myronRemoteUpdateStateRepository()->get();
$availableRemoteUpdate = is_array($remoteUpdateState['available_update'] ?? null) ? $remoteUpdateState['available_update'] : null;
$remoteUpdateVisible = $availableRemoteUpdate !== null
    && (string) ($availableRemoteUpdate['latestVersion'] ?? '') !== ''
    && trim((string) ($availableRemoteUpdate['package']['url'] ?? '')) !== ''
    && myronVersionComparator()->isNewer((string) ($availableRemoteUpdate['latestVersion'] ?? ''), MyronReleaseMetadata::VERSION)
    && (string) ($availableRemoteUpdate['latestVersion'] ?? '') !== (string) ($remoteUpdateState['dismissed_update_version'] ?? '');
$remoteUpdateStatus = (string) ($remoteUpdateState['last_check_status'] ?? 'not_checked');
$remoteUpdateStatusCopy = match ($remoteUpdateStatus) {
    'up_to_date' => 'MyronCMS is up to date.',
    'update_available' => 'An installable update is available.',
    'incompatible_update' => 'An update exists, but this server does not meet its requirements.',
    'entitlement_denied' => 'This release is not available for installation on the current license.',
    'license_refresh_required' => 'Refresh the site license before checking for updates again.',
    'check_failed' => 'The update check could not be completed.',
    'manual_check_cooldown' => 'Please wait before checking for updates again.',
    '', 'not_checked' => 'Updates have not been checked yet.',
    default => $remoteUpdateStatus,
};

myronRenderAdminShellStart($currentUser, [
    'title' => 'Site Setup',
    'titleContext' => 'Administration',
    'activeItem' => 'site-setup',
]);
?>
<div class="mc-workspace__header">
  <?php myronRenderAdminBreadcrumbs([
      ['label' => 'Administration', 'href' => myronBuildAdminUrl('identity.users')],
      ['label' => 'System', 'href' => myronBuildAdminUrl('administration.siteSetup')],
      ['label' => 'Site Setup'],
  ]); ?>
  <div class="mc-workspace__title-row">
    <h1 class="mc-workspace__title">Site Setup</h1>
  </div>
  <p class="mc-workspace__subtitle">Choose a primary site type, add page packs, suppress duplicate core pages, and sync only the selected templates.</p>
</div>

<div class="mc-page-canvas mc-page-canvas--site">
  <div class="sg-main">
    <section class="sg-section mc-application-update" aria-labelledby="application-update-title">
      <div class="sg-section__header">
        <h2 class="sg-section__title" id="application-update-title">Application Update</h2>
        <p class="sg-section__subtitle">Check the configured MyronCMS update channel, then apply a signed-off local update ZIP containing a manifest and only the declared changed files.</p>
      </div>

      <?php if (!$zipArchiveAvailable): ?>
      <p class="sg-field__help">Application updates are unavailable because the PHP ZipArchive extension is not enabled on this server.</p>
      <?php elseif (!$canApplyApplicationUpdates): ?>
      <p class="sg-field__help">Application updates are restricted to administrator accounts.</p>
      <?php else: ?>
      <div class="mc-page-grid mc-page-grid--application-updates" role="table" aria-label="Remote application update status">
        <div class="mc-page-grid__row mc-page-grid__row--head" role="row">
          <span role="columnheader">Installed</span>
          <span role="columnheader">Channel</span>
          <span role="columnheader">Last Check</span>
          <span role="columnheader">Status</span>
          <span role="columnheader">Action</span>
        </div>
        <div class="mc-page-grid__row" role="row">
          <span class="mc-page-grid__cell" role="cell"><code><?= myronEscape(MyronReleaseMetadata::VERSION) ?></code></span>
          <span class="mc-page-grid__cell" role="cell"><code><?= myronEscape((string) ($remoteUpdateSettings['update_channel'] ?? 'stable')) ?></code></span>
          <span class="mc-page-grid__cell" role="cell"><?= myronEscape((string) ($remoteUpdateState['last_checked_at'] ?? 'Never')) ?></span>
          <span class="mc-page-grid__cell" role="cell">
            <?php if ($remoteUpdateVisible): ?>
            <span class="mc-page-grid__status-line"><strong>MyronCMS <?= myronEscape((string) ($availableRemoteUpdate['latestVersion'] ?? '')) ?> is available.</strong></span>
            <a href="<?= myronEscape((string) ($availableRemoteUpdate['releaseNotes']['url'] ?? '#')) ?>" rel="noopener" target="_blank">Release notes</a>
            <?php else: ?>
            <code><?= myronEscape($remoteUpdateStatus !== '' ? $remoteUpdateStatus : 'not_checked') ?></code>
            <span class="mc-page-grid__subtle"><?= myronEscape($remoteUpdateStatusCopy) ?></span>
            <?php if (in_array($remoteUpdateStatus, ['check_failed', 'incompatible_update', 'entitlement_denied', 'license_refresh_required'], true)): ?>
            <span class="mc-page-grid__subtle"><?= myronEscape((string) ($remoteUpdateState['last_check_error'] ?? 'Unknown error')) ?></span>
            <?php endif; ?>
            <?php endif; ?>
          </span>
          <span class="mc-page-grid__cell mc-page-grid__cell--actions" role="cell">
            <?php if ($remoteUpdateVisible): ?>
            <form class="mc-page-grid__action-form" method="post" action="<?= myronEscape(myronBuildAdminUrl('administration.siteSetup')) ?>#application-update-title">
              <input type="hidden" name="csrf_token" value="<?= myronEscape($csrfToken) ?>">
              <input type="hidden" name="action" value="apply-remote-application-update">
              <button class="sg-button sg-button--primary" type="submit">Update</button>
            </form>
            <form class="mc-page-grid__action-form" method="post" action="<?= myronEscape(myronBuildAdminUrl('administration.siteSetup')) ?>#application-update-title">
              <input type="hidden" name="csrf_token" value="<?= myronEscape($csrfToken) ?>">
              <input type="hidden" name="action" value="dismiss-remote-application-update">
              <input type="hidden" name="update_version" value="<?= myronEscape((string) ($availableRemoteUpdate['latestVersion'] ?? '')) ?>">
              <button class="sg-button" type="submit">Dismiss This Version</button>
            </form>
            <?php else: ?>
            <span class="mc-page-grid__muted">No action</span>
            <?php endif; ?>
          </span>
        </div>
      </div>

      <form method="post" action="<?= myronEscape(myronBuildAdminUrl('administration.siteSetup')) ?>#application-update-title">
        <input type="hidden" name="csrf_token" value="<?= myronEscape($csrfToken) ?>">
        <input type="hidden" name="action" value="check-remote-application-update">
        <div class="sg-card__actions">
          <button class="sg-button" type="submit">Check for Updates</button>
        </div>
      </form>

      <form class="sg-form-grid" method="post" action="<?= myronEscape(myronBuildAdminUrl('administration.siteSetup')) ?>" enctype="multipart/form-data">
        <input type="hidden" name="csrf_token" value="<?= myronEscape($csrfToken) ?>">
        <input type="hidden" name="action" value="apply-application-update">
        <label class="sg-field sg-field--full">
          <span class="sg-field__label">Update ZIP</span>
          <input class="sg-field__control" type="file" name="update_package" accept=".zip,application/zip" required>
          <span class="sg-field__help">Only manifest-based update packages are accepted. Full application ZIPs, private files, `.env`, uploads, tests, and runtime state are rejected before application.</span>
        </label>
        <label class="sg-checkbox sg-field--full">
          <input type="checkbox" name="confirm_application_update" value="1" required>
          <span>I understand this applies application code changes from the selected update package.</span>
        </label>
        <div class="sg-card__actions">
          <button class="sg-button sg-button--primary" type="submit">Apply Update Package</button>
        </div>
      </form>
      <?php endif; ?>

      <?php if ($updateHistory !== []): ?>
      <div class="mc-page-grid mc-page-grid--application-update-history" role="table" aria-label="Recent application updates">
        <div class="mc-page-grid__row mc-page-grid__row--head" role="row">
          <span role="columnheader">Package</span>
          <span role="columnheader">Version</span>
          <span role="columnheader">Status</span>
          <span role="columnheader">Updated</span>
        </div>
        <?php foreach ($updateHistory as $update): ?>
        <div class="mc-page-grid__row" role="row">
          <span class="mc-page-grid__cell mc-page-grid__cell--name" role="cell">
            <span class="mc-page-grid__name"><?= myronEscape((string) ($update['package_id'] ?? 'Unknown package')) ?></span>
            <span class="mc-page-grid__subtle"><code><?= myronEscape(substr((string) ($update['package_hash'] ?? ''), 0, 16)) ?></code></span>
          </span>
          <span class="mc-page-grid__cell" role="cell"><?= myronEscape((string) ($update['target_version'] ?? '')) ?></span>
          <span class="mc-page-grid__cell" role="cell"><code><?= myronEscape((string) ($update['status'] ?? '')) ?></code></span>
          <span class="mc-page-grid__cell" role="cell"><?= myronEscape((string) ($update['updated_at'] ?? '')) ?></span>
        </div>
        <?php endforeach; ?>
      </div>
      <?php endif; ?>
    </section>

    <section class="sg-section">
      <form class="sg-form-grid" id="site-setup-sync-form" method="post" action="<?= myronEscape(myronBuildAdminUrl('administration.siteSetup')) ?>">
        <input type="hidden" name="csrf_token" value="<?= myronEscape($csrfToken) ?>">
        <input type="hidden" name="action" value="save-site-setup">
        <input type="hidden" name="selection_projection_primary_id" value="<?= myronEscape($selectedPrimaryId) ?>">
        <input type="hidden" name="page_sync_mode" value="keep" data-page-sync-mode>
        <input type="hidden" name="replace_default_pages" value="0" data-default-replacement-armed>
        <input type="hidden" name="confirm_default_page_replacement" value="" data-default-replacement-phrase>
        <script type="application/json" id="site-setup-defaults-json"><?= $jsonForScript($selectionDefaultsByPrimary) ?></script>
        <script type="application/json" id="site-setup-primary-bundles-json"><?= $jsonForScript($primaryBundleIds) ?></script>

        <section class="sg-field sg-field--full mc-site-setup-matrix mc-site-setup-matrix--primary" aria-labelledby="site-setup-primary-matrix-title">
          <div class="sg-section__header">
            <h2 class="sg-section__title" id="site-setup-primary-matrix-title">Primary Site Types and Page Templates</h2>
            <p class="sg-section__subtitle">Select one primary site type. Additional site types can contribute page templates, while duplicate Home, About, Contact, Search, Legal, and 404 pages are suppressed outside the primary column.</p>
          </div>
          <ul class="mc-site-setup-matrix__legend" aria-label="Site setup matrix legend">
            <li>Checked boxes sync selected templates.</li>
            <li>Empty boxes are available but not selected.</li>
            <li>Disabled boxes are protected shared pages owned by the primary site type.</li>
            <li>Dashes mean the page is not offered by that site type.</li>
          </ul>
          <div class="mc-site-setup-matrix__scroller">
            <table class="mc-site-setup-matrix__table">
              <thead>
                <tr>
                  <th scope="col">Page</th>
                  <?php foreach ($primarySiteTypes as $siteType): ?>
                  <?php $bundleId = (string) ($siteType['id'] ?? ''); ?>
                  <th scope="col">
                    <span class="mc-site-setup-matrix__bundle"><?= myronEscape($primarySiteTypeLabelFor($siteType)) ?></span>
                    <span class="mc-site-setup-matrix__controls">
                      <label class="sg-checkbox">
                        <input type="radio" name="primary_bundle_id" value="<?= myronEscape($bundleId) ?>"<?= $selectedPrimaryId === $bundleId ? ' checked' : '' ?> required data-site-setup-primary>
                        <span>Primary</span>
                      </label>
                      <label class="sg-checkbox">
                        <input type="checkbox" name="included_bundle_ids[]" value="<?= myronEscape($bundleId) ?>"<?= isset($includedIds[$bundleId]) || $selectedPrimaryId === $bundleId ? ' checked' : '' ?> data-site-setup-include data-bundle-id="<?= myronEscape($bundleId) ?>">
                        <span>Include</span>
                      </label>
                    </span>
                  </th>
                  <?php endforeach; ?>
                </tr>
              </thead>
              <tbody>
                <?php foreach ($primaryMatrix as $row): ?>
                <?php $roleKey = (string) ($row['roleKey'] ?? ''); ?>
                <tr data-site-setup-row="<?= myronEscape($roleKey) ?>">
                  <th scope="row"><?= myronEscape((string) ($row['label'] ?? 'Page')) ?></th>
                  <?php foreach ($primarySiteTypes as $siteType): ?>
                  <?php
                    $bundleId = (string) ($siteType['id'] ?? '');
                    $cell = is_array($row['cells'][$bundleId] ?? null) ? $row['cells'][$bundleId] : null;
                  ?>
                  <td>
                    <?php if ($cell === null): ?>
                    <span class="mc-site-setup-matrix__empty" aria-label="Not applicable">-</span>
                    <?php else: ?>
                    <?php
                      $template = is_array($cell['template'] ?? null) ? $cell['template'] : [];
                      $templateId = (string) ($cell['templateId'] ?? '');
                      $isDefault = ($cell['isDefault'] ?? false) === true;
                      $selectionKey = $selectionService->templateSelectionKey($bundleId, $templateId);
                      $isSuppressed = isset($manifestSuppressedTemplateKeys[$selectionKey]);
                      $isChecked = !$isSuppressed && $isTemplateChecked($bundleId, $templateId, $isDefault);
                    ?>
                    <label class="mc-site-setup-matrix__cell<?= $isSuppressed ? ' mc-site-setup-matrix__cell--suppressed' : '' ?>">
                      <input type="checkbox" name="selected_template_keys[]" value="<?= myronEscape($selectionKey) ?>"<?= $isChecked ? ' checked' : '' ?><?= $isSuppressed ? ' disabled' : '' ?> data-site-setup-template data-template-id="<?= myronEscape($templateId) ?>" data-selection-key="<?= myronEscape($selectionKey) ?>" data-role-key="<?= myronEscape($roleKey) ?>" data-bundle-id="<?= myronEscape($bundleId) ?>" data-bundle-kind="primary" data-template-core="<?= $selectionService->isCoreTemplate($template) ? '1' : '0' ?>" data-template-singleton="<?= $selectionService->isSingletonTemplate($template) ? '1' : '0' ?>">
                    </label>
                    <?php endif; ?>
                  </td>
                  <?php endforeach; ?>
                </tr>
                <?php endforeach; ?>
              </tbody>
            </table>
          </div>
        </section>

        <section class="sg-field sg-field--full mc-site-setup-matrix mc-site-setup-matrix--subtype" aria-labelledby="site-setup-extension-matrix-title">
          <div class="sg-section__header">
            <h2 class="sg-section__title" id="site-setup-extension-matrix-title">Subtype Extension Grid</h2>
            <p class="sg-section__subtitle">Subtype bundles are enabled only when one of their parent site types is included.</p>
          </div>
          <div class="mc-site-setup-matrix__scroller">
            <table class="mc-site-setup-matrix__table">
              <thead>
                <tr>
                  <th scope="col">Template</th>
                  <?php foreach ($subtypeSiteTypes as $siteType): ?>
                  <?php
                    $bundleId = (string) ($siteType['id'] ?? '');
                    $parents = $parentsForSubtype($siteType);
                    $parentNames = $parentNamesForSubtype($siteType);
                    $hasParent = count(array_intersect_key(array_fill_keys($parents, true), $includedIds)) > 0;
                  ?>
                  <th scope="col">
                    <span class="mc-site-setup-matrix__bundle"><?= myronEscape((string) ($siteType['name'] ?? $bundleId)) ?></span>
                    <span class="mc-site-setup-matrix__requirement">Requires <?= myronEscape(implode(' or ', $parentNames)) ?></span>
                    <label class="sg-checkbox">
                      <input type="checkbox" name="included_subtype_ids[]" value="<?= myronEscape($bundleId) ?>"<?= isset($includedIds[$bundleId]) ? ' checked' : '' ?><?= $hasParent ? '' : ' disabled' ?> data-site-setup-include data-site-setup-subtype data-bundle-id="<?= myronEscape($bundleId) ?>" data-parent-ids="<?= myronEscape(implode(' ', $parents)) ?>">
                      <span>Include</span>
                    </label>
                  </th>
                  <?php endforeach; ?>
                </tr>
              </thead>
              <tbody>
                <?php foreach ($subtypeMatrix as $row): ?>
                <?php $roleKey = (string) ($row['roleKey'] ?? ''); ?>
                <tr data-site-setup-row="<?= myronEscape($roleKey) ?>">
                  <th scope="row"><?= myronEscape((string) ($row['label'] ?? 'Template')) ?></th>
                  <?php foreach ($subtypeSiteTypes as $siteType): ?>
                  <?php
                    $bundleId = (string) ($siteType['id'] ?? '');
                    $cell = is_array($row['cells'][$bundleId] ?? null) ? $row['cells'][$bundleId] : null;
                    $parents = $parentsForSubtype($siteType);
                    $hasParent = count(array_intersect_key(array_fill_keys($parents, true), $includedIds)) > 0;
                  ?>
                  <td>
                    <?php if ($cell === null): ?>
                    <span class="mc-site-setup-matrix__empty" aria-label="Not applicable">-</span>
                    <?php else: ?>
                    <?php
                      $templateId = (string) ($cell['templateId'] ?? '');
                      $template = is_array($cell['template'] ?? null) ? $cell['template'] : [];
                      $isDefault = ($cell['isDefault'] ?? false) === true;
                      $selectionKey = $selectionService->templateSelectionKey($bundleId, $templateId);
                      $isSuppressed = isset($manifestSuppressedTemplateKeys[$selectionKey]);
                      $isChecked = !$isSuppressed && $hasParent && $isTemplateChecked($bundleId, $templateId, $isDefault);
                    ?>
                    <label class="mc-site-setup-matrix__cell<?= $hasParent ? '' : ' mc-site-setup-matrix__cell--disabled' ?><?= $isSuppressed ? ' mc-site-setup-matrix__cell--suppressed' : '' ?>">
                      <input type="checkbox" name="selected_template_keys[]" value="<?= myronEscape($selectionKey) ?>"<?= $isChecked ? ' checked' : '' ?><?= ($hasParent && !$isSuppressed) ? '' : ' disabled' ?> data-site-setup-template data-template-id="<?= myronEscape($templateId) ?>" data-selection-key="<?= myronEscape($selectionKey) ?>" data-role-key="<?= myronEscape($roleKey) ?>" data-bundle-id="<?= myronEscape($bundleId) ?>" data-bundle-kind="subtype" data-parent-ids="<?= myronEscape(implode(' ', $parents)) ?>" data-template-core="0" data-template-singleton="<?= $selectionService->isSingletonTemplate($template) ? '1' : '0' ?>">
                    </label>
                    <?php endif; ?>
                  </td>
                  <?php endforeach; ?>
                </tr>
                <?php endforeach; ?>
              </tbody>
            </table>
          </div>
        </section>

        <label class="sg-field sg-field--full">
          <span class="sg-field__label">Site Design System</span>
          <select class="sg-field__control" name="archetype_theme_id"<?= $themeOptions === [] ? ' disabled' : '' ?>>
            <option value=""><?= $themeOptions === [] ? 'No Design System Manager records available' : 'Choose a registered design system' ?></option>
            <?php foreach ($themeOptions as $theme): ?>
            <option value="<?= myronEscape((string) $theme['id']) ?>"<?= $selectedThemeId === (string) $theme['id'] ? ' selected' : '' ?>>
              <?= myronEscape((string) $theme['name']) ?> · <?= myronEscape((string) $theme['id']) ?>
            </option>
            <?php endforeach; ?>
          </select>
        </label>

        <label class="sg-checkbox sg-field--full">
          <input type="checkbox" name="apply_theme" value="1"<?= $themeOptions === [] ? ' disabled' : '' ?>>
          <span>Apply selected JSONM design system during setup</span>
        </label>

        <div class="sg-card__actions">
          <button class="sg-button sg-button--primary" type="button" data-mc-sidesheet-open="site-setup-page-sync-sheet">Site Setup and Page Sync</button>
        </div>
      </form>
    </section>

    <section class="sg-section mc-site-setup__bundles" aria-labelledby="site-type-bundles-title" data-site-setup-bundles data-api-base="<?= myronEscape(myronBuildAdminUrl('/api/v1')) ?>">
      <div class="sg-section__header">
        <h2 class="sg-section__title" id="site-type-bundles-title">Site Type Bundles</h2>
        <p class="sg-section__subtitle">Disable non-primary bundles with an impact preview, redirect safety net, and audit-backed re-enable path.</p>
      </div>
      <div class="mc-site-setup__bundle-table" role="table" aria-label="Site type bundle state">
        <div class="mc-site-setup__bundle-row mc-site-setup__bundle-row--head" role="row">
          <span role="columnheader">Bundle</span>
          <span role="columnheader">State</span>
          <span role="columnheader">Actions</span>
        </div>
        <?php foreach ($siteTypes as $siteType): ?>
        <?php
          $bundleId = (string) ($siteType['id'] ?? '');
          if ($bundleId === '') {
              continue;
          }
          $bundleState = is_array($bundleStateById[$bundleId] ?? null) ? $bundleStateById[$bundleId] : null;
          $isEnabled = is_array($bundleState) && ($bundleState['is_enabled'] ?? false) === true;
          $isPrimary = is_array($bundleState) && ($bundleState['is_primary'] ?? false) === true;
          $label = MyronSiteTypeRegistryRepository::displayLabelForSiteType($siteType);
        ?>
        <div class="mc-site-setup__bundle-row" role="row" data-bundle-row data-bundle-id="<?= myronEscape($bundleId) ?>" data-bundle-label="<?= myronEscape($label) ?>" data-bundle-enabled="<?= $isEnabled ? '1' : '0' ?>">
          <span role="cell">
            <strong><?= myronEscape($label) ?></strong>
            <code><?= myronEscape($bundleId) ?></code>
          </span>
          <span role="cell">
            <?php if ($isPrimary): ?>
            <span class="sg-pill">Primary</span>
            <?php elseif ($isEnabled): ?>
            <span class="sg-pill">Enabled</span>
            <?php elseif ($bundleState !== null): ?>
            <span class="sg-pill">Disabled</span>
            <?php else: ?>
            <span class="sg-pill">Not configured</span>
            <?php endif; ?>
          </span>
          <span role="cell" class="mc-site-setup__bundle-actions">
            <?php if ($isPrimary): ?>
            <span class="mc-page-grid__subtle">Primary changes use the protected setup flow.</span>
            <?php elseif ($isEnabled): ?>
            <button class="sg-button sg-button--danger" type="button" data-bundle-disable-open>Disable</button>
            <?php elseif ($bundleState !== null): ?>
            <button class="sg-button sg-button--primary" type="button" data-bundle-enable-open>Re-enable</button>
            <button class="sg-button" type="button" data-bundle-events-open>View last disable event</button>
            <?php else: ?>
            <span class="mc-page-grid__subtle">Include this bundle through the setup matrix first.</span>
            <?php endif; ?>
          </span>
        </div>
        <?php endforeach; ?>
      </div>
    </section>

    <section class="sg-section">
      <h2 class="sg-section__title">Current Setup State</h2>
      <dl class="sg-definition-list">
        <div class="sg-definition-list__row">
          <dt>Status</dt>
          <dd><?= myronEscape((string) ($state['setup_status'] ?? 'pending')) ?></dd>
        </div>
        <div class="sg-definition-list__row">
          <dt>Primary bundle</dt>
          <dd><code><?= myronEscape((string) ($state['primary_bundle_id'] ?? '')) ?></code></dd>
        </div>
        <div class="sg-definition-list__row">
          <dt>Design system</dt>
          <dd><code><?= myronEscape((string) ($state['archetype_theme_id'] ?? '')) ?></code></dd>
        </div>
        <div class="sg-definition-list__row">
          <dt>Applied design system</dt>
          <dd><code><?= myronEscape((string) ($state['applied_design_system_id'] ?? '')) ?></code></dd>
        </div>
      </dl>
      <form method="post" action="<?= myronEscape(myronBuildAdminUrl('administration.siteSetup')) ?>" data-site-reset-form>
        <input type="hidden" name="csrf_token" value="<?= myronEscape($csrfToken) ?>">
        <input type="hidden" name="action" value="reset-site-baseline">
        <input type="hidden" name="confirm_site_reset" value="0" data-site-reset-armed>
        <input type="hidden" name="confirm_site_reset_phrase" value="" data-site-reset-phrase>
        <button type="submit" hidden data-site-reset-submit>Submit Confirmed Reset</button>
        <p class="sg-field__help" data-site-reset-status>Site reset is disabled until confirmed through the timed modal.</p>
        <div class="sg-card__actions">
          <button class="sg-button sg-button--danger" type="button" data-site-reset-open>Reset Site to Baseline</button>
        </div>
      </form>
    </section>

  </div>
</div>
<?php ob_start(); ?>
<div class="sg-form-grid" data-site-setup-page-sync-sheet>
  <fieldset class="sg-field">
    <legend class="sg-field__label">Page Sync Strategy</legend>
    <label class="sg-checkbox">
      <input type="radio" name="page_sync_mode_choice" value="replace" form="site-setup-sync-form" data-page-sync-choice>
      <span>Replace Default Pages</span>
    </label>
    <p class="sg-field__help">Replaces source-linked starter or previous primary default pages, then syncs pages from the selected site type.</p>
    <div class="sg-card__actions">
      <button class="sg-button sg-button--danger" type="button" data-default-replacement-open>Confirm Default Replacement</button>
      <button class="sg-button" type="button" data-default-replacement-clear hidden>Clear Replacement Confirmation</button>
    </div>
    <p class="sg-field__help" data-default-replacement-armed-status>Existing default pages will be preserved on save.</p>
    <label class="sg-checkbox">
      <input type="radio" name="page_sync_mode_choice" value="keep" form="site-setup-sync-form" checked data-page-sync-choice>
      <span>Keep Existing Pages</span>
    </label>
    <p class="sg-field__help">Adds missing selected templates only. Existing pages, templates, menus, footer settings, routes, SEO, and publication state are preserved; route collisions are reported instead of claimed or renamed.</p>
    <label class="sg-checkbox">
      <input type="radio" name="page_sync_mode_choice" value="choose" form="site-setup-sync-form" data-page-sync-choice>
      <span>Choose Page Replacements</span>
    </label>
    <p class="sg-field__help">Records explicit template/page replacement intent and reports section remap coverage without pruning unselected pages or templates.</p>
  </fieldset>

  <div class="mc-template-browser__tabs" role="tablist" aria-label="Choose replacement scope" data-page-sync-choose-panel hidden>
    <button class="sg-pill sg-pill--active" type="button" role="tab" aria-selected="true" data-page-sync-tab="templates">Templates</button>
    <button class="sg-pill" type="button" role="tab" aria-selected="false" data-page-sync-tab="pages">Pages</button>
  </div>

  <section data-page-sync-panel="templates" hidden>
    <h3 class="sg-section__title">Templates</h3>
    <div class="mc-page-grid" role="table" aria-label="Template replacement choices" data-mc-sortable-grid>
      <div class="mc-page-grid__row mc-page-grid__row--head" role="row">
        <span role="columnheader" data-mc-sort-key="template"><button class="mc-page-grid__sort" type="button">Template</button></span>
        <span role="columnheader">Keep</span>
        <span role="columnheader">Replace</span>
      </div>
      <?php foreach ($runtimeTemplatesForSync as $template): ?>
      <?php $templateId = (string) ($template['id'] ?? ''); ?>
      <div
        class="mc-page-grid__row"
        role="row"
        data-mc-filter-row
        data-sort-template="<?= myronEscape((string) ($template['name'] ?? $templateId) . ' ' . (string) ($template['source_template_id'] ?? '')) ?>"
      >
        <span class="mc-page-grid__cell mc-page-grid__cell--name" role="cell">
          <span class="mc-page-grid__name"><?= myronEscape((string) ($template['name'] ?? $templateId)) ?></span>
          <span class="mc-page-grid__subtle"><code><?= myronEscape((string) ($template['source_template_id'] ?? '')) ?></code></span>
        </span>
        <span class="mc-page-grid__cell" role="cell"><input type="radio" name="template_replacement_choices[<?= myronEscape($templateId) ?>]" value="keep" form="site-setup-sync-form" checked></span>
        <span class="mc-page-grid__cell" role="cell"><input type="radio" name="template_replacement_choices[<?= myronEscape($templateId) ?>]" value="replace" form="site-setup-sync-form"></span>
      </div>
      <?php endforeach; ?>
      <?php if ($runtimeTemplatesForSync === []): ?>
      <div class="mc-page-grid__row" role="row"><span class="mc-page-grid__cell" role="cell">No source-linked templates are currently in use.</span></div>
      <?php endif; ?>
    </div>
  </section>

  <section data-page-sync-panel="pages" hidden>
    <h3 class="sg-section__title">Pages</h3>
    <div class="mc-page-grid" role="table" aria-label="Page replacement choices" data-mc-sortable-grid>
      <div class="mc-page-grid__row mc-page-grid__row--head" role="row">
        <span role="columnheader" data-mc-sort-key="page"><button class="mc-page-grid__sort" type="button">Page</button></span>
        <span role="columnheader">Keep</span>
        <span role="columnheader">Replace</span>
      </div>
      <?php foreach ($pagesForSync as $page): ?>
      <?php $pageId = (string) ($page['id'] ?? ''); ?>
      <div
        class="mc-page-grid__row"
        role="row"
        data-mc-filter-row
        data-sort-page="<?= myronEscape((string) ($page['title'] ?? $pageId) . ' ' . (string) ($page['path'] ?? '')) ?>"
      >
        <span class="mc-page-grid__cell mc-page-grid__cell--name" role="cell">
          <span class="mc-page-grid__name"><?= myronEscape((string) ($page['title'] ?? $pageId)) ?></span>
          <span class="mc-page-grid__subtle"><code><?= myronEscape((string) ($page['path'] ?? '')) ?></code></span>
        </span>
        <span class="mc-page-grid__cell" role="cell"><input type="radio" name="page_replacement_choices[<?= myronEscape($pageId) ?>]" value="keep" form="site-setup-sync-form" checked></span>
        <span class="mc-page-grid__cell" role="cell"><input type="radio" name="page_replacement_choices[<?= myronEscape($pageId) ?>]" value="replace" form="site-setup-sync-form"></span>
      </div>
      <?php endforeach; ?>
      <?php if ($pagesForSync === []): ?>
      <div class="mc-page-grid__row" role="row"><span class="mc-page-grid__cell" role="cell">No source-linked pages are currently in use.</span></div>
      <?php endif; ?>
    </div>
  </section>

  <section class="sg-section" data-page-sync-report-intent>
    <h3 class="sg-section__title">Migration Report</h3>
    <p class="sg-field__help">After replacement, the report distinguishes 1:1 section remaps from unmatched source sections, unmatched destination sections, and removed unselected setup-linked pages/templates for templates and pages.</p>
  </section>

  <div class="sg-card__actions">
    <button class="sg-button sg-button--secondary" type="button" data-mc-sidesheet-close>Cancel</button>
    <button class="sg-button sg-button--primary" type="submit" form="site-setup-sync-form">Run Site Setup and Page Sync</button>
  </div>
</div>
<?php $pageSyncSheetBody = (string) ob_get_clean(); ?>
<?php myronRenderAdminSidesheet('site-setup-page-sync-sheet', 'Site Setup and Page Sync', $pageSyncSheetBody, [
    'description' => 'Choose how existing source-linked pages are handled before syncing selected site-type templates.',
    'size' => 'lg',
]); ?>
<div class="myron-dialog-backdrop" hidden aria-hidden="true" data-default-replacement-backdrop></div>
<div class="myron-dialog myron-dialog--confirmation" id="site-setup-default-replacement-dialog" role="dialog" aria-modal="true" aria-hidden="true" hidden tabindex="-1" data-default-replacement-dialog>
  <div class="myron-dialog__header">
    <div>
      <h2 class="sg-section__title">Replace Default Pages</h2>
      <p class="sg-section__subtitle">This will delete source-linked starter or previous primary default pages, then recreate default pages for the selected primary site type. Manual pages are preserved.</p>
    </div>
    <button class="myron-dialog__close" type="button" aria-label="Close default replacement confirmation" data-default-replacement-close>&times;</button>
  </div>
  <div class="myron-dialog__body">
    <p class="sg-field__help" data-default-replacement-modal-status>Confirmation unlocks after the countdown.</p>
    <label class="sg-field">
      <span class="sg-field__label">Type <?= myronEscape(MyronSiteSetupDefaultReplacementService::CONFIRMATION_PHRASE) ?></span>
      <input class="sg-field__control" type="text" autocomplete="off" spellcheck="false" disabled data-default-replacement-confirmation>
    </label>
  </div>
  <div class="myron-dialog__actions">
    <button class="sg-button sg-button--secondary" type="button" data-default-replacement-close>Cancel</button>
    <button class="sg-button sg-button--danger" type="button" disabled data-default-replacement-confirm>Confirm Replacement</button>
  </div>
</div>
<div class="myron-dialog-backdrop" hidden aria-hidden="true" data-site-reset-backdrop></div>
<div class="myron-dialog myron-dialog--confirmation" id="site-setup-reset-dialog" role="dialog" aria-modal="true" aria-hidden="true" hidden tabindex="-1" data-site-reset-dialog>
  <div class="myron-dialog__header">
    <div>
      <h2 class="sg-section__title">Reset Site to Baseline</h2>
      <p class="sg-section__subtitle">This deletes site content, uploaded files, active site types, stored design systems, and runtime setup state. Users are preserved.</p>
    </div>
    <button class="myron-dialog__close" type="button" aria-label="Close site reset confirmation" data-site-reset-close>&times;</button>
  </div>
  <div class="myron-dialog__body">
    <p class="sg-field__help" data-site-reset-modal-status>Confirmation unlocks after the countdown.</p>
    <label class="sg-field">
      <span class="sg-field__label">Type <code><?= myronEscape(MyronSiteResetService::CONFIRMATION_PHRASE) ?></code></span>
      <input class="sg-field__control" type="text" autocomplete="off" spellcheck="false" disabled data-site-reset-confirmation>
    </label>
  </div>
  <div class="myron-dialog__actions">
    <button class="sg-button sg-button--secondary" type="button" data-site-reset-close>Cancel</button>
    <button class="sg-button sg-button--danger" type="button" disabled data-site-reset-confirm>Confirm Reset</button>
  </div>
</div>
<div class="myron-dialog-backdrop" hidden aria-hidden="true" data-bundle-modal-backdrop></div>
<div class="myron-dialog myron-dialog--confirmation mc-site-setup__bundle-modal" id="site-setup-bundle-disable-dialog" role="dialog" aria-modal="true" aria-hidden="true" hidden tabindex="-1" data-bundle-disable-dialog>
  <form method="post" action="<?= myronEscape(myronBuildAdminUrl('administration.siteSetup')) ?>" data-bundle-disable-form>
    <input type="hidden" name="csrf_token" value="<?= myronEscape($csrfToken) ?>">
    <input type="hidden" name="action" value="disable-site-type-bundle">
    <input type="hidden" name="bundle_id" value="" data-bundle-disable-id>
    <div class="myron-dialog__header">
      <div>
        <h2 class="sg-section__title" data-bundle-disable-title>Disable Bundle</h2>
        <p class="sg-section__subtitle">Review impact and choose the fallback URL for visitors to disabled pages.</p>
      </div>
      <button class="myron-dialog__close" type="button" aria-label="Close bundle disable dialog" data-bundle-modal-close>&times;</button>
    </div>
    <div class="myron-dialog__body">
      <div class="mc-site-setup__impact" data-bundle-impact>Loading impact preview...</div>
      <label class="sg-field">
        <span class="sg-field__label">Default redirect URL</span>
        <input class="sg-field__control" type="text" name="default_fallback_url" value="/" placeholder="/" data-bundle-disable-fallback>
      </label>
    </div>
    <div class="myron-dialog__actions">
      <button class="sg-button sg-button--secondary" type="button" data-bundle-modal-close>Cancel</button>
      <button class="sg-button sg-button--danger" type="submit" data-bundle-disable-submit>Disable bundle</button>
    </div>
  </form>
</div>
<div class="myron-dialog myron-dialog--confirmation mc-site-setup__bundle-modal" id="site-setup-bundle-enable-dialog" role="dialog" aria-modal="true" aria-hidden="true" hidden tabindex="-1" data-bundle-enable-dialog>
  <form method="post" action="<?= myronEscape(myronBuildAdminUrl('administration.siteSetup')) ?>" data-bundle-enable-form>
    <input type="hidden" name="csrf_token" value="<?= myronEscape($csrfToken) ?>">
    <input type="hidden" name="action" value="enable-site-type-bundle">
    <input type="hidden" name="bundle_id" value="" data-bundle-enable-id>
    <div class="myron-dialog__header">
      <div>
        <h2 class="sg-section__title" data-bundle-enable-title>Re-enable Bundle</h2>
        <p class="sg-section__subtitle">Restore disabled pages, menu items, and remove redirect rows.</p>
      </div>
      <button class="myron-dialog__close" type="button" aria-label="Close bundle enable dialog" data-bundle-modal-close>&times;</button>
    </div>
    <div class="myron-dialog__body">
      <div class="mc-site-setup__impact" data-bundle-enable-impact>Choose how path collisions should be handled.</div>
      <label class="sg-field">
        <span class="sg-field__label">Conflict resolution</span>
        <select class="sg-field__control" name="conflict_resolution" data-bundle-enable-resolution>
          <option value="skip" selected>Skip conflicting pages</option>
          <option value="rename">Rename conflicting pages</option>
          <option value="abort">Cancel if conflicts exist</option>
        </select>
      </label>
    </div>
    <div class="myron-dialog__actions">
      <button class="sg-button sg-button--secondary" type="button" data-bundle-modal-close>Cancel</button>
      <button class="sg-button sg-button--primary" type="submit" data-bundle-enable-submit>Re-enable bundle</button>
    </div>
  </form>
</div>
<div class="myron-dialog myron-dialog--confirmation mc-site-setup__bundle-modal" id="site-setup-bundle-events-dialog" role="dialog" aria-modal="true" aria-hidden="true" hidden tabindex="-1" data-bundle-events-dialog>
  <div class="myron-dialog__header">
    <div>
      <h2 class="sg-section__title" data-bundle-events-title>Bundle Events</h2>
      <p class="sg-section__subtitle">Recent disable and enable audit payloads.</p>
    </div>
    <button class="myron-dialog__close" type="button" aria-label="Close bundle events dialog" data-bundle-modal-close>&times;</button>
  </div>
  <div class="myron-dialog__body">
    <pre class="mc-site-setup__event-json" data-bundle-events-output>Loading events...</pre>
  </div>
  <div class="myron-dialog__actions">
    <button class="sg-button sg-button--secondary" type="button" data-bundle-modal-close>Close</button>
  </div>
</div>
<script>
(() => {
  const defaultsNode = document.getElementById('site-setup-defaults-json');
  const primaryBundlesNode = document.getElementById('site-setup-primary-bundles-json');
  const projectionInput = document.querySelector('input[name="selection_projection_primary_id"]');
  const parseSetupJson = (node, fallback) => {
    if (!node) {
      return fallback;
    }
    try {
      return JSON.parse(node.textContent || '');
    } catch (error) {
      return fallback;
    }
  };

  const defaultsByPrimary = parseSetupJson(defaultsNode, {});
  const primaryBundles = new Set(parseSetupJson(primaryBundlesNode, []));
  const includeInputs = Array.from(document.querySelectorAll('[data-site-setup-include]'));
  const templateInputs = Array.from(document.querySelectorAll('[data-site-setup-template]'));
  const bundleSurface = document.querySelector('[data-site-setup-bundles]');
  const bundleBackdrop = document.querySelector('[data-bundle-modal-backdrop]');
  const bundleDisableDialog = document.querySelector('[data-bundle-disable-dialog]');
  const bundleEnableDialog = document.querySelector('[data-bundle-enable-dialog]');
  const bundleEventsDialog = document.querySelector('[data-bundle-events-dialog]');
  const bundleApiBase = bundleSurface ? String(bundleSurface.dataset.apiBase || '').replace(/\/$/, '') : '';

  const openBundleDialog = (dialog) => {
    if (!dialog) return;
    if (bundleBackdrop) bundleBackdrop.hidden = false;
    dialog.hidden = false;
    dialog.setAttribute('aria-hidden', 'false');
    dialog.focus();
  };
  const closeBundleDialogs = () => {
    [bundleDisableDialog, bundleEnableDialog, bundleEventsDialog].forEach((dialog) => {
      if (!dialog) return;
      dialog.hidden = true;
      dialog.setAttribute('aria-hidden', 'true');
    });
    if (bundleBackdrop) bundleBackdrop.hidden = true;
  };
  const bundleFetchJson = async (path) => {
    const response = await fetch(bundleApiBase + path, {
      headers: { 'Accept': 'application/json' },
      credentials: 'same-origin'
    });
    return response.json();
  };
  const renderImpact = (payload) => {
    const result = payload && payload.ok ? payload.result : payload;
    if (!result || !result.bundle_id) {
      return '<p class="sg-field__help">Impact preview is unavailable.</p>';
    }
    const pages = Array.isArray(result.pages_owned) ? result.pages_owned : [];
    const menus = Array.isArray(result.menu_items_affected) ? result.menu_items_affected : [];
    const links = Array.isArray(result.internal_links_warning) ? result.internal_links_warning : [];
    const mics = Array.isArray(result.mic_references_warning) ? result.mic_references_warning : [];
    const pageRows = pages.slice(0, 12).map((page) => '<li><code>' + escapeHtml(String(page.slug || '')) + '</code> ' + escapeHtml(String(page.title || 'Untitled')) + ' · ' + escapeHtml(String(page.publish_state || '')) + '</li>').join('');
    return '<p>Disabling affects <strong>' + pages.length + '</strong> page(s), <strong>' + menus.length + '</strong> menu item(s), <strong>' + links.length + '</strong> internal link warning(s), and <strong>' + mics.length + '</strong> mic reference warning(s).</p>'
      + '<details open><summary>Pages owned</summary><ul>' + (pageRows || '<li>No pages owned by this bundle.</li>') + '</ul></details>'
      + '<p class="sg-field__help">Internal link and mic-code matches are best-effort warnings and may include false positives.</p>';
  };
  const escapeHtml = (value) => value.replace(/[&<>"']/g, (char) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;' }[char]));

  if (bundleSurface) {
    bundleSurface.addEventListener('click', async (event) => {
      const row = event.target.closest('[data-bundle-row]');
      if (!row) return;
      const bundleId = row.dataset.bundleId || '';
      const label = row.dataset.bundleLabel || bundleId;
      if (event.target.closest('[data-bundle-disable-open]')) {
        const idInput = document.querySelector('[data-bundle-disable-id]');
        const title = document.querySelector('[data-bundle-disable-title]');
        const impact = document.querySelector('[data-bundle-impact]');
        if (idInput) idInput.value = bundleId;
        if (title) title.textContent = 'Disable ' + label;
        if (impact) impact.textContent = 'Loading impact preview...';
        openBundleDialog(bundleDisableDialog);
        try {
          const payload = await bundleFetchJson('/administration/bundles/' + encodeURIComponent(bundleId) + '/impact-preview');
          if (impact) impact.innerHTML = renderImpact(payload);
        } catch (error) {
          if (impact) impact.textContent = 'Impact preview failed: ' + error.message;
        }
      }
      if (event.target.closest('[data-bundle-enable-open]')) {
        const idInput = document.querySelector('[data-bundle-enable-id]');
        const title = document.querySelector('[data-bundle-enable-title]');
        const impact = document.querySelector('[data-bundle-enable-impact]');
        if (idInput) idInput.value = bundleId;
        if (title) title.textContent = 'Re-enable ' + label;
        if (impact) impact.textContent = 'Restores disabled pages, skips or renames path conflicts according to the selected resolution, and removes redirects for this bundle.';
        openBundleDialog(bundleEnableDialog);
      }
      if (event.target.closest('[data-bundle-events-open]')) {
        const title = document.querySelector('[data-bundle-events-title]');
        const output = document.querySelector('[data-bundle-events-output]');
        if (title) title.textContent = label + ' Events';
        if (output) output.textContent = 'Loading events...';
        openBundleDialog(bundleEventsDialog);
        try {
          const payload = await bundleFetchJson('/administration/bundles/' + encodeURIComponent(bundleId) + '/events?limit=10');
          if (output) output.textContent = JSON.stringify(payload && payload.ok ? payload.result.events : payload, null, 2);
        } catch (error) {
          if (output) output.textContent = 'Event load failed: ' + error.message;
        }
      }
    });
    document.addEventListener('click', (event) => {
      if (event.target.closest('[data-bundle-modal-close]') || event.target === bundleBackdrop) {
        closeBundleDialogs();
      }
    });
    document.addEventListener('keydown', (event) => {
      if (event.key === 'Escape') closeBundleDialogs();
    });
  }

  const parentIdsFor = (input) => String(input.dataset.parentIds || '').split(/\s+/).filter(Boolean);
  const includeInputForBundle = (bundleId) => includeInputs.find((input) => input.dataset.bundleId === bundleId || input.value === bundleId);
  const templatesForBundle = (bundleId) => templateInputs.filter((input) => input.dataset.bundleId === bundleId);
  const templatesForRole = (roleKey) => templateInputs.filter((input) => input.dataset.roleKey === roleKey);
  const selectedPrimaryInput = () => document.querySelector('[data-site-setup-primary]:checked');
  const baseEnabled = (input) => input.dataset.baseDisabled !== '1';
  const validTemplatesForBundle = (bundleId) => templatesForBundle(bundleId).filter((input) => !input.disabled);
  const rowOwnerFor = (roleKey, exceptInput = null) => templatesForRole(roleKey).find((input) => input !== exceptInput && baseEnabled(input) && input.checked);
  const syncIncludeStateForBundle = (bundleId) => {
    const includeInput = includeInputForBundle(bundleId);
    if (!includeInput) {
      return;
    }
    const validTemplates = validTemplatesForBundle(bundleId);
    const selectedCount = validTemplates.filter((input) => input.checked).length;
    includeInput.indeterminate = selectedCount > 0 && selectedCount < validTemplates.length;
    includeInput.checked = selectedCount > 0;
    if (validTemplates.length > 0 && selectedCount === validTemplates.length) {
      includeInput.indeterminate = false;
    }
    if (validTemplates.length === 0) {
      includeInput.indeterminate = false;
      includeInput.checked = false;
    }
  };
  const syncAllIncludeStates = () => {
    includeInputs.forEach((input) => syncIncludeStateForBundle(input.value));
  };
  const setBundleTemplates = (bundleId, checked) => {
    const selectedPrimary = selectedPrimaryInput();
    if (!selectedPrimary) {
      return;
    }
    updateDependentAvailability(selectedPrimary.value);
    if (!checked) {
      templatesForBundle(bundleId).forEach((input) => {
        input.checked = false;
      });
      updateDependentAvailability(selectedPrimary.value);
      syncIncludeStateForBundle(bundleId);
      return;
    }

    templatesForBundle(bundleId).forEach((input) => {
      const roleKey = String(input.dataset.roleKey || '');
      if (input.disabled || roleKey === '' || rowOwnerFor(roleKey, input)) {
        return;
      }
      input.checked = true;
    });
    updateDependentAvailability(selectedPrimary.value);
    syncIncludeStateForBundle(bundleId);
  };
  const checkedBundleIds = () => {
    const ids = new Set();
    includeInputs.forEach((input) => {
      if (input.checked) {
        ids.add(input.value);
      }
    });
    return ids;
  };

  const applyRowExclusivity = (primaryBundleId) => {
    const roleKeys = new Set(templateInputs.map((input) => String(input.dataset.roleKey || '')).filter(Boolean));
    roleKeys.forEach((roleKey) => {
      const rowInputs = templatesForRole(roleKey);
      const eligible = rowInputs.filter(baseEnabled);
      const primaryInput = eligible.find((input) => input.dataset.bundleId === primaryBundleId);
      const checked = eligible.filter((input) => input.checked);
      const owner = primaryInput && primaryInput.checked ? primaryInput : (checked[0] || null);
      checked.forEach((input) => {
        if (owner && input !== owner) {
          input.checked = false;
        }
      });
      eligible.forEach((input) => {
        if (!owner) {
          input.disabled = false;
          return;
        }
        const isPrimaryInput = input === primaryInput;
        input.disabled = owner === primaryInput
          ? input !== owner
          : input !== owner && !isPrimaryInput;
      });
    });
  };

  const updateDependentAvailability = (primaryBundleId) => {
    const included = checkedBundleIds();
    included.add(primaryBundleId);
    includeInputs.forEach((input) => {
      if (!input.matches('[data-site-setup-subtype]')) {
        return;
      }
      const hasParent = parentIdsFor(input).some((parentId) => included.has(parentId));
      input.disabled = !hasParent;
      if (!hasParent) {
        input.checked = false;
      }
    });

    const refreshedIncluded = checkedBundleIds();
    refreshedIncluded.add(primaryBundleId);
    templateInputs.forEach((input) => {
      const parentBlocked = input.dataset.bundleKind === 'subtype'
        && !parentIdsFor(input).some((parentId) => refreshedIncluded.has(parentId));
      input.dataset.baseDisabled = parentBlocked ? '1' : '0';
      input.disabled = parentBlocked;
      if (input.disabled) {
        input.checked = false;
      }
    });
    applyRowExclusivity(primaryBundleId);
  };

  const applyPrimaryDefaults = (primaryBundleId) => {
    const defaults = defaultsByPrimary[primaryBundleId] || {};
    const defaultBundles = new Set((defaults.included_bundle_ids || []).map(String));
    const defaultTemplateKeys = new Set((defaults.selected_template_keys || []).map(String));
    const defaultTemplates = new Set((defaults.selected_template_ids || []).map(String));

    includeInputs.forEach((input) => {
      input.checked = false;
      input.indeterminate = false;
    });
    templateInputs.forEach((input) => {
      input.checked = false;
    });
    includeInputs.forEach((input) => {
      if (input.value === primaryBundleId || defaultBundles.has(input.value)) {
        input.checked = true;
      }
    });
    updateDependentAvailability(primaryBundleId);
    templateInputs.forEach((input) => {
      const selectionKey = String(input.dataset.selectionKey || '');
      const templateId = String(input.dataset.templateId || input.value || '');
      if (!input.disabled && (defaultTemplateKeys.has(selectionKey) || (defaultTemplateKeys.size === 0 && defaultTemplates.has(templateId)))) {
        input.checked = true;
      }
    });
    projectionInput.value = primaryBundleId;
    syncAllIncludeStates();
  };

  if (projectionInput) {
    document.querySelectorAll('[data-site-setup-primary]').forEach((input) => {
      input.addEventListener('change', () => {
        if (input.checked) {
          applyPrimaryDefaults(input.value);
        }
      });
    });
    includeInputs.forEach((input) => {
      input.addEventListener('change', () => {
        const selectedPrimary = selectedPrimaryInput();
        if (selectedPrimary) {
          setBundleTemplates(input.value, input.checked);
          syncAllIncludeStates();
        }
      });
    });
    templateInputs.forEach((input) => {
      input.addEventListener('change', () => {
        const selectedPrimary = selectedPrimaryInput();
        const bundleId = String(input.dataset.bundleId || '');
        if (bundleId !== '') {
          syncIncludeStateForBundle(bundleId);
        }
        if (selectedPrimary) {
          updateDependentAvailability(selectedPrimary.value);
          syncAllIncludeStates();
        }
      });
    });
    const selectedPrimary = selectedPrimaryInput();
    if (selectedPrimary) {
      updateDependentAvailability(selectedPrimary.value);
      syncAllIncludeStates();
    }
  }

  const replacementOpen = document.querySelector('[data-default-replacement-open]');
  const replacementClear = document.querySelector('[data-default-replacement-clear]');
  const replacementArmedInput = document.querySelector('[data-default-replacement-armed]');
  const replacementPhraseInput = document.querySelector('[data-default-replacement-phrase]');
  const replacementArmedStatus = document.querySelector('[data-default-replacement-armed-status]');
  const replacementDialog = document.querySelector('[data-default-replacement-dialog]');
  const replacementBackdrop = document.querySelector('[data-default-replacement-backdrop]');
  const replacementConfirm = document.querySelector('[data-default-replacement-confirm]');
  const replacementConfirmation = document.querySelector('[data-default-replacement-confirmation]');
  const replacementModalStatus = document.querySelector('[data-default-replacement-modal-status]');
  const replacementDelaySeconds = 5;
  let replacementCountdown = null;

  const pageSyncModeInput = document.querySelector('[data-page-sync-mode]');
  const pageSyncChoices = Array.from(document.querySelectorAll('[data-page-sync-choice]'));
  const pageSyncChoosePanel = document.querySelector('[data-page-sync-choose-panel]');
  const pageSyncTabs = Array.from(document.querySelectorAll('[data-page-sync-tab]'));
  const pageSyncPanels = Array.from(document.querySelectorAll('[data-page-sync-panel]'));
  const syncPageSyncMode = () => {
    const selected = pageSyncChoices.find((input) => input.checked);
    const mode = selected ? selected.value : 'keep';
    if (pageSyncModeInput) {
      pageSyncModeInput.value = mode;
    }
    if (replacementArmedInput) {
      replacementArmedInput.value = mode === 'replace' ? replacementArmedInput.value : '0';
    }
    if (replacementPhraseInput) {
      replacementPhraseInput.value = mode === 'replace' ? replacementPhraseInput.value : '';
    }
    const choosing = mode === 'choose';
    if (pageSyncChoosePanel) {
      pageSyncChoosePanel.hidden = !choosing;
    }
    pageSyncPanels.forEach((panel, index) => {
      panel.hidden = !choosing || index !== 0;
    });
    pageSyncTabs.forEach((tab, index) => {
      tab.classList.toggle('sg-pill--active', index === 0);
      tab.setAttribute('aria-selected', index === 0 ? 'true' : 'false');
    });
  };
  pageSyncChoices.forEach((choice) => {
    choice.addEventListener('change', syncPageSyncMode);
  });
  pageSyncTabs.forEach((tab) => {
    tab.addEventListener('click', () => {
      const target = tab.getAttribute('data-page-sync-tab') || '';
      pageSyncTabs.forEach((nextTab) => {
        const active = nextTab === tab;
        nextTab.classList.toggle('sg-pill--active', active);
        nextTab.setAttribute('aria-selected', active ? 'true' : 'false');
      });
      pageSyncPanels.forEach((panel) => {
        panel.hidden = panel.getAttribute('data-page-sync-panel') !== target;
      });
    });
  });
  syncPageSyncMode();

  const setReplacementArmed = (armed) => {
    if (!replacementArmedInput || !replacementPhraseInput || !replacementArmedStatus || !replacementClear) {
      return;
    }
    replacementArmedInput.value = armed ? '1' : '0';
    replacementPhraseInput.value = armed ? '<?= myronEscape(MyronSiteSetupDefaultReplacementService::CONFIRMATION_PHRASE) ?>' : '';
    replacementArmedStatus.textContent = armed
      ? 'Default pages will be replaced when you save setup.'
      : 'Existing default pages will be preserved on save.';
    replacementClear.hidden = !armed;
  };

  const closeReplacementDialog = () => {
    window.clearInterval(replacementCountdown);
    if (replacementDialog) {
      replacementDialog.hidden = true;
      replacementDialog.setAttribute('aria-hidden', 'true');
    }
    if (replacementBackdrop) {
      replacementBackdrop.hidden = true;
      replacementBackdrop.setAttribute('aria-hidden', 'true');
    }
  };

  const updateReplacementConfirm = () => {
    if (!replacementConfirmation || !replacementConfirm) {
      return;
    }
    replacementConfirm.disabled = replacementConfirmation.disabled
      || replacementConfirmation.value.trim() !== '<?= myronEscape(MyronSiteSetupDefaultReplacementService::CONFIRMATION_PHRASE) ?>';
  };

  const openReplacementDialog = () => {
    if (!replacementDialog || !replacementBackdrop || !replacementConfirmation || !replacementConfirm || !replacementModalStatus) {
      return;
    }
    window.clearInterval(replacementCountdown);
    let remaining = replacementDelaySeconds;
    replacementDialog.hidden = false;
    replacementDialog.setAttribute('aria-hidden', 'false');
    replacementBackdrop.hidden = false;
    replacementBackdrop.setAttribute('aria-hidden', 'false');
    replacementConfirmation.value = '';
    replacementConfirmation.disabled = true;
    replacementConfirm.disabled = true;
    replacementModalStatus.textContent = 'Confirmation unlocks in ' + String(remaining) + ' seconds.';
    replacementDialog.focus();
    replacementCountdown = window.setInterval(() => {
      remaining -= 1;
      if (remaining > 0) {
        replacementModalStatus.textContent = 'Confirmation unlocks in ' + String(remaining) + ' seconds.';
        return;
      }
      window.clearInterval(replacementCountdown);
      replacementConfirmation.disabled = false;
      replacementConfirmation.value = '';
      replacementModalStatus.textContent = 'Type the exact phrase to enable replacement.';
      replacementConfirmation.focus();
      updateReplacementConfirm();
    }, 1000);
  };

  if (replacementOpen) {
    replacementOpen.addEventListener('click', openReplacementDialog);
  }
  if (replacementClear) {
    replacementClear.addEventListener('click', () => setReplacementArmed(false));
  }
  document.querySelectorAll('[data-default-replacement-close]').forEach((button) => {
    button.addEventListener('click', closeReplacementDialog);
  });
  if (replacementBackdrop) {
    replacementBackdrop.addEventListener('click', closeReplacementDialog);
  }
  if (replacementConfirmation) {
    replacementConfirmation.addEventListener('input', updateReplacementConfirm);
  }
  if (replacementConfirm) {
    replacementConfirm.addEventListener('click', () => {
      if (replacementConfirm.disabled) {
        return;
      }
      setReplacementArmed(true);
      closeReplacementDialog();
    });
  }
  syncPageSyncMode();

  const siteResetForm = document.querySelector('[data-site-reset-form]');
  const siteResetSubmit = document.querySelector('[data-site-reset-submit]');
  const siteResetOpen = document.querySelector('[data-site-reset-open]');
  const siteResetArmedInput = document.querySelector('[data-site-reset-armed]');
  const siteResetPhraseInput = document.querySelector('[data-site-reset-phrase]');
  const siteResetStatus = document.querySelector('[data-site-reset-status]');
  const siteResetDialog = document.querySelector('[data-site-reset-dialog]');
  const siteResetBackdrop = document.querySelector('[data-site-reset-backdrop]');
  const siteResetConfirm = document.querySelector('[data-site-reset-confirm]');
  const siteResetConfirmation = document.querySelector('[data-site-reset-confirmation]');
  const siteResetModalStatus = document.querySelector('[data-site-reset-modal-status]');
  const siteResetDelaySeconds = 5;
  let siteResetCountdown = null;

  const setSiteResetArmed = (armed) => {
    if (!siteResetArmedInput || !siteResetPhraseInput || !siteResetStatus) {
      return;
    }
    siteResetArmedInput.value = armed ? '1' : '0';
    siteResetPhraseInput.value = armed ? '<?= myronEscape(MyronSiteResetService::CONFIRMATION_PHRASE) ?>' : '';
    siteResetStatus.textContent = armed
      ? 'Site reset confirmed. Submitting reset request.'
      : 'Site reset is disabled until confirmed through the timed modal.';
  };

  const closeSiteResetDialog = () => {
    window.clearInterval(siteResetCountdown);
    if (siteResetDialog) {
      siteResetDialog.hidden = true;
      siteResetDialog.setAttribute('aria-hidden', 'true');
    }
    if (siteResetBackdrop) {
      siteResetBackdrop.hidden = true;
      siteResetBackdrop.setAttribute('aria-hidden', 'true');
    }
  };

  const updateSiteResetConfirm = () => {
    if (!siteResetConfirmation || !siteResetConfirm) {
      return;
    }
    siteResetConfirm.disabled = siteResetConfirmation.disabled
      || siteResetConfirmation.value.trim() !== '<?= myronEscape(MyronSiteResetService::CONFIRMATION_PHRASE) ?>';
  };

  const openSiteResetDialog = () => {
    if (!siteResetDialog || !siteResetBackdrop || !siteResetConfirmation || !siteResetConfirm || !siteResetModalStatus) {
      return;
    }
    window.clearInterval(siteResetCountdown);
    let remaining = siteResetDelaySeconds;
    siteResetDialog.hidden = false;
    siteResetDialog.setAttribute('aria-hidden', 'false');
    siteResetBackdrop.hidden = false;
    siteResetBackdrop.setAttribute('aria-hidden', 'false');
    siteResetConfirmation.value = '';
    siteResetConfirmation.disabled = true;
    siteResetConfirm.disabled = true;
    siteResetModalStatus.textContent = 'Confirmation unlocks in ' + String(remaining) + ' seconds.';
    siteResetDialog.focus();
    siteResetCountdown = window.setInterval(() => {
      remaining -= 1;
      if (remaining > 0) {
        siteResetModalStatus.textContent = 'Confirmation unlocks in ' + String(remaining) + ' seconds.';
        return;
      }
      window.clearInterval(siteResetCountdown);
      siteResetConfirmation.disabled = false;
      siteResetConfirmation.value = '';
      siteResetModalStatus.textContent = 'Type the exact phrase to enable reset.';
      siteResetConfirmation.focus();
      updateSiteResetConfirm();
    }, 1000);
  };

  if (siteResetOpen) {
    siteResetOpen.addEventListener('click', openSiteResetDialog);
  }
  document.querySelectorAll('[data-site-reset-close]').forEach((button) => {
    button.addEventListener('click', closeSiteResetDialog);
  });
  if (siteResetBackdrop) {
    siteResetBackdrop.addEventListener('click', closeSiteResetDialog);
  }
  if (siteResetConfirmation) {
    siteResetConfirmation.addEventListener('input', updateSiteResetConfirm);
  }
  if (siteResetConfirm) {
    siteResetConfirm.addEventListener('click', () => {
      if (siteResetConfirm.disabled || !siteResetForm) {
        return;
      }
      setSiteResetArmed(true);
      closeSiteResetDialog();
      if (typeof siteResetForm.requestSubmit === 'function' && siteResetSubmit) {
        siteResetForm.requestSubmit(siteResetSubmit);
        return;
      }
      if (siteResetSubmit) {
        siteResetSubmit.click();
        return;
      }
      siteResetForm.submit();
    });
  }
  setSiteResetArmed(false);
})();
</script>
<?php myronRenderAdminShellEnd(); ?>
