import { readFileSync } from 'fs';
import { dirname, join, resolve } from 'path';
import { fileURLToPath } from 'url';
import { spawnSync } from 'child_process';
import {
  evaluateThemeAccessibility, getThemeContract, validateThemeDefinition, validateThemePreference,
} from '../app/core/themes/theme-contract.mjs';

const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const read = rel => readFileSync(join(root, rel), 'utf8');
const failures = [];
const assert = (condition, message) => { if (!condition) failures.push(message); };
const expectThrow = (fn, code, message) => {
  try { fn(); failures.push(message); }
  catch (error) { if (error.code !== code) failures.push(`${message} (erhalten ${error.code || error.message})`); }
};

const pkg = JSON.parse(read('package.json'));
assert(pkg.version === '1.38.0', `Paketversion ist ${pkg.version}`);
const source = JSON.parse(read('public/design-system/tokens/source.json'));
assert(source.contractVersion === '1.1.0', `Tokenvertrag ist ${source.contractVersion}`);
assert(Object.keys(source.tokens).length >= 42, `Zu wenige Tokens: ${Object.keys(source.tokens).length}`);
for (const token of ['component.buttonHeight','component.inputHeight','component.cardRadius','component.focusWidth','component.touchTarget']) {
  assert(Boolean(source.tokens[token]), `Komponenten-Token fehlt: ${token}`);
}

const contract = getThemeContract();
assert(contract.tokens['color.brand'].label === 'Akzentfarbe', 'Token-Label fehlt');
assert(contract.tokens['component.buttonHeight'].group === 'Komponenten', 'Token-Gruppe fehlt');
const valid = validateThemeDefinition({ id: 'custom-markus-pro', name: 'Markus Pro', base_theme: 'dark', values: { 'color.brand': '#ff6600', 'component.buttonHeight': '44px' } });
assert(valid.id === 'custom-markus-pro', 'Gültiges Theme wurde nicht akzeptiert');
expectThrow(() => validateThemeDefinition({ id: 'unsafe', name: 'Unsafe', values: {} }), 'THEME_ID_PREFIX', 'Theme ohne custom-Präfix wurde akzeptiert');
expectThrow(() => validateThemeDefinition({ id: 'custom-unsafe', name: 'Unsafe', values: { 'color.brand': 'url(javascript:alert(1))' } }), 'THEME_VALUE_INVALID', 'CSS-Injektion wurde akzeptiert');
expectThrow(() => validateThemeDefinition({ id: 'custom-unsafe', name: 'Unsafe', values: { 'shadow.float': '0 0 1px red' } }), 'THEME_TOKEN_FORBIDDEN', 'Nicht anpassbarer Token wurde akzeptiert');
expectThrow(() => validateThemePreference({ theme_id: 'missing', density: 'comfortable', reduced_motion: 'system' }), 'THEME_NOT_FOUND', 'Unbekanntes Theme wurde akzeptiert');
const poorContrast = evaluateThemeAccessibility({ baseTheme: 'light', values: { 'color.ink': '#ffffff', 'color.canvas': '#ffffff', 'color.surface': '#ffffff' } });
assert(!poorContrast.ok && poorContrast.failures.length >= 2, 'Kontrastfehler wurde nicht erkannt');

const before = read('public/design-system/tokens.css');
const generated = spawnSync(process.execPath, [join(root, 'tools/generate-design-tokens.mjs')], { cwd: root, encoding: 'utf8' });
assert(generated.status === 0, `Token-Generator fehlgeschlagen: ${generated.stderr || generated.stdout}`);
assert(before === read('public/design-system/tokens.css'), 'Token-Generator ist nicht deterministisch');

const manifest = JSON.parse(read('app/modules/themes/module.json'));
assert(manifest.status === 'native', 'Theme-Modul ist nicht nativ');
assert(manifest.provides.includes('themes.accessibility'), 'Accessibility-Capability fehlt');
for (const file of [
  'app/modules/themes/index.mjs','app/modules/themes/service.mjs','app/modules/themes/repository.mjs',
  'app/modules/themes/migrations/001_theme_profiles.sql','public/modules/theme-manager/theme-manager.js',
  'public/modules/theme-manager/theme-manager.css',
]) assert(read(file).length > 50, `Theme-Pflichtdatei fehlt oder ist leer: ${file}`);

const server = read('server.mjs');
for (const marker of [
  "id: 'themes.catalog.read'", "id: 'themes.preference.update'", "id: 'themes.profile.create'",
  "id: 'themes.profile.update'", "id: 'themes.profile.delete'", "id: 'themes.system-default.update'",
  "policy: 'themes.manage'", "policy: 'themes.use'",
]) assert(server.includes(marker), `Theme-Route fehlt: ${marker}`);
assert(server.indexOf("path: '/api/themes/system-default'") < server.indexOf("path: '/api/themes/:id'"), 'Systemstandard-Route wird von :id überschattet');

const html = read('public/index.html');
for (const marker of ['id="theme-manager-root"','id="theme-choice-grid"','id="theme-token-groups"','id="theme-contrast-list"','theme-manager.js?v=1.38.0']) assert(html.includes(marker), `Theme-Manager UI fehlt: ${marker}`);
const manager = read('public/modules/theme-manager/theme-manager.js');
assert(!manager.includes('.innerHTML ='), 'Theme Manager verwendet unsicheres innerHTML');
for (const marker of ['/api/themes/validate','/api/themes/preference','/api/themes/system-default','window.VendooTheme?.previewTheme']) assert(manager.includes(marker), `Theme Manager Logik fehlt: ${marker}`);
const runtime = read('public/design-system/theme-runtime.js');
for (const marker of ['vendoo-theme-state-v2','dataset.reducedMotion','clearCustomProperties','previewTheme']) assert(runtime.includes(marker), `Theme Runtime fehlt: ${marker}`);
const schema = read('db/schema.sql');
for (const marker of ['CREATE TABLE IF NOT EXISTS theme_profiles','CREATE TABLE IF NOT EXISTS user_theme_preferences']) assert(schema.includes(marker), `Theme-Schema fehlt: ${marker}`);

if (failures.length) {
  console.error(`Theme-Manager-Gate 1.38.0 fehlgeschlagen (${failures.length}):`);
  failures.forEach(item => console.error(`- ${item}`));
  process.exit(1);
}
console.log(`Theme-Manager-Gate 1.38.0 erfolgreich: ${Object.keys(source.tokens).length} Tokens, natives Theme-Modul, sichere Profile, Benutzerpräferenzen, Kontrastprüfung und tokenisierte Komponenten geprüft.`);
