<?php
declare(strict_types=1);

$root = dirname(__DIR__);
require_once $root . '/theme_assets_lib.php';
require_once $root . '/app_runtime.php';
require_once $root . '/ui_settings.php';

function theme_contract_read(string $path): string
{
    $value = @file_get_contents($path);
    if (!is_string($value)) throw new RuntimeException('Unable to read: ' . $path);
    return $value;
}

function theme_contract_assert(bool $condition, string $message): void
{
    if (!$condition) throw new RuntimeException($message);
}

$header = theme_contract_read($root . '/header.php');
$studio = theme_contract_read($root . '/template_page.php');
$guards = theme_contract_read($root . '/assets/css/ua_footer_guards.css');
$settings = theme_contract_read($root . '/ui_settings.php');

$pageCssPos = strpos($header, "if (!empty(\$UA_PAGE_CSS)");
$unifiedPos = strpos($header, 'assets/css/ua_program_unified.css');
$guardsPos = strpos($header, 'assets/css/ua_footer_guards.css');
theme_contract_assert($pageCssPos !== false && $unifiedPos !== false && $guardsPos !== false, 'Theme stylesheet pipeline is incomplete.');
theme_contract_assert($pageCssPos < $unifiedPos && $unifiedPos < $guardsPos, 'Page CSS must load before the canonical theme layers.');

theme_contract_assert(strpos($studio, "\$UA_PAGE_CSS = ['assets/css/ua_theme_studio.css']") !== false, 'Theme Studio CSS must be registered in the page head.');
theme_contract_assert(substr_count($studio, '<link rel="stylesheet" href="assets/css/ua_theme_studio.css') === 0, 'Theme Studio still emits a late body stylesheet.');
theme_contract_assert(strpos($studio, 'function applyThemeIdentity(themeId)') !== false, 'Live preview does not update the body theme identity.');
theme_contract_assert(strpos($studio, 'applyThemeIdentity(radio.value)') !== false, 'Theme radio changes do not apply the new identity.');

$requiredTokens = [
    'ui_accent', 'ui_text_color', 'ui_border_color', 'ui_body_bg',
    'ui_surface_color', 'ui_surface_alt_color', 'ui_sidebar_color',
    'ui_input_color', 'ui_input_text_color', 'ui_menu_color', 'ui_modal_color',
];
foreach (ua_theme_registry() as $themeId => $theme) {
    $tokens = $theme['tokens'] ?? [];
    foreach ($requiredTokens as $token) {
        theme_contract_assert(is_string($tokens[$token] ?? null) && $tokens[$token] !== '', $themeId . ' is missing ' . $token);
    }
}

theme_contract_assert(strpos($guards, ':is(option,optgroup)') !== false, 'Native select options are outside the theme contrast contract.');
theme_contract_assert(strpos($guards, 'color-scheme:light') !== false && strpos($guards, 'color-scheme:dark') !== false, 'Native controls do not distinguish light and dark themes.');
theme_contract_assert(strpos($settings, "glob(__DIR__ . '/cache/runtime/app_settings_*.json')") !== false, 'Settings writes do not invalidate the shared theme cache.');
theme_contract_assert(strpos($header, 'ua_get_ui_settings_map') !== false, 'Header does not load installation-scoped theme settings.');
theme_contract_assert(strpos($studio, 'ua_set_ui_setting') !== false && strpos($studio, 'ua_get_ui_setting') !== false, 'Theme Studio does not save and load its installation-scoped theme.');

$previousOverride = $GLOBALS['UA_INSTALL_CONFIG_OVERRIDE'] ?? null;
$GLOBALS['UA_INSTALL_CONFIG_OVERRIDE'] = [
    'install_type' => 'branch',
    'link' => ['instance_id' => 'theme-contract-branch'],
];
$branchThemeKey = ua_ui_setting_storage_key('ui_theme');
$GLOBALS['UA_INSTALL_CONFIG_OVERRIDE'] = [
    'install_type' => 'agent',
    'link' => ['instance_id' => 'theme-contract-agent'],
];
$agentThemeKey = ua_ui_setting_storage_key('ui_theme');
if ($previousOverride === null) unset($GLOBALS['UA_INSTALL_CONFIG_OVERRIDE']);
else $GLOBALS['UA_INSTALL_CONFIG_OVERRIDE'] = $previousOverride;

theme_contract_assert($branchThemeKey !== $agentThemeKey, 'Branch and agent themes resolve to the same storage key.');
theme_contract_assert(strlen($branchThemeKey) <= 100 && strlen($agentThemeKey) <= 100, 'Scoped theme key exceeds the app_settings schema limit.');

echo "theme_runtime_contract_test: OK\n";
