import { existsSync, readFileSync } from 'node:fs';
import { dirname, join, normalize, resolve, win32 } from 'node:path';
import { spawnSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';

const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const packageJson = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
const command = packageJson?.scripts?.['verify:installer-shell'] || '';
const isWindowsHost = process.platform === 'win32' || process.env.VENDOO_TEST_WINDOWS_SHELL === '1';

function fail(message) {
  console.error(`Installer-Shell-Portabilitätsgate fehlgeschlagen: ${message}`);
  process.exit(1);
}

if (/^\s*sh\s+/i.test(command)) {
  fail('package.json darf den POSIX-Befehl sh nicht direkt voraussetzen.');
}
if (command !== 'node tools/verify-installer-shell.mjs') {
  fail(`Unerwarteter npm-Vertrag: ${command}`);
}

const shellContract = readFileSync(join(root, 'tools', 'verify-installer-shell.sh'), 'utf8');
for (const marker of [
  'VENDOO_INSTALLER_SHELL_HOST',
  'MINGW*|MSYS*|CYGWIN*',
  'POSIX-Modus 0600',
  'show_file',
  'assert_env_permissions',
  '--exclude=.git',
]) {
  if (!shellContract.includes(marker)) fail(`Shell-Testvertrag fehlt: ${marker}`);
}

function run(file, args, options = {}) {
  return spawnSync(file, args, {
    cwd: root,
    encoding: 'utf8',
    windowsHide: true,
    maxBuffer: 16 * 1024 * 1024,
    ...options,
  });
}

function addCandidate(set, value) {
  if (!value) return;
  const candidate = normalize(value.replace(/^"|"$/g, '').trim());
  if (candidate) set.add(candidate);
}

function addGitRootCandidates(set, gitRoot) {
  if (!gitRoot) return;
  addCandidate(set, join(gitRoot, 'bin', 'sh.exe'));
  addCandidate(set, join(gitRoot, 'usr', 'bin', 'sh.exe'));
}

function pathApiFor(value) {
  return /^[a-zA-Z]:[\\/]/.test(value) ? win32 : { normalize, dirname };
}

function deriveGitRootFromExecutable(executable) {
  const raw = executable.replace(/^"|"$/g, '').trim();
  const api = pathApiFor(raw);
  const clean = api.normalize(raw);
  const parent = api.dirname(clean);
  const leaf = parent.toLowerCase().split(/[\\/]/).pop();
  if (['cmd', 'bin', 'usr'].includes(leaf)) {
    return api.dirname(parent);
  }
  return api.dirname(clean);
}

function deriveGitRootFromExecPath(execPath) {
  const raw = execPath.replace(/^"|"$/g, '').trim();
  const api = pathApiFor(raw);
  const clean = api.normalize(raw);
  const lowered = clean.toLowerCase().replace(/\\/g, '/');
  for (const marker of ['/mingw64/', '/mingw32/', '/usr/libexec/', '/libexec/']) {
    const index = lowered.indexOf(marker);
    if (index > 0) return clean.slice(0, index);
  }
  return null;
}

function findWindowsGitBash() {
  const candidates = new Set();
  addCandidate(candidates, process.env.VENDOO_SH);
  addCandidate(candidates, process.env.SHELL);

  for (const base of [process.env.ProgramFiles, process.env['ProgramFiles(x86)'], process.env.LOCALAPPDATA]) {
    if (!base) continue;
    addGitRootCandidates(candidates, join(base, base === process.env.LOCALAPPDATA ? 'Programs' : '', 'Git'));
  }

  const whereGit = run('where.exe', ['git.exe']);
  if (whereGit.status === 0) {
    for (const line of whereGit.stdout.split(/\r?\n/).map((entry) => entry.trim()).filter(Boolean)) {
      addGitRootCandidates(candidates, deriveGitRootFromExecutable(line));
    }
  }

  const execPath = run('git.exe', ['--exec-path']);
  if (execPath.status === 0) {
    const gitRoot = deriveGitRootFromExecPath(execPath.stdout);
    if (gitRoot) addGitRootCandidates(candidates, gitRoot);
  }

  const whereSh = run('where.exe', ['sh.exe']);
  if (whereSh.status === 0) {
    for (const line of whereSh.stdout.split(/\r?\n/).map((entry) => entry.trim()).filter(Boolean)) {
      addCandidate(candidates, line);
    }
  }

  return [...candidates].find((candidate) => existsSync(candidate)) || null;
}

// Regression contracts for common Git-for-Windows layouts.
const standardRoot = deriveGitRootFromExecutable('C:\\Program Files\\Git\\cmd\\git.exe');
if (standardRoot.toLowerCase() !== win32.normalize('C:\\Program Files\\Git').toLowerCase()) {
  fail(`Git-Root aus cmd\\git.exe falsch abgeleitet: ${standardRoot}`);
}
const execRoot = deriveGitRootFromExecPath('C:\\Program Files\\Git\\mingw64\\libexec\\git-core');
if (!execRoot || execRoot.toLowerCase() !== win32.normalize('C:\\Program Files\\Git').toLowerCase()) {
  fail(`Git-Root aus git --exec-path falsch abgeleitet: ${execRoot}`);
}

let shell;
if (isWindowsHost) {
  shell = process.platform === 'win32' ? findWindowsGitBash() : 'sh';
  if (!shell) {
    fail('Git Bash wurde trotz installiertem Git nicht gefunden. Erwartet wird bin\\sh.exe oder usr\\bin\\sh.exe innerhalb der Git-for-Windows-Installation.');
  }
} else {
  const probe = run('sh', ['-c', 'printf vendoo-shell-ok']);
  if (probe.status !== 0 || probe.stdout !== 'vendoo-shell-ok') {
    fail('Eine funktionsfähige POSIX-Shell wurde nicht gefunden.');
  }
  shell = 'sh';
}

if (isWindowsHost) {
  for (const script of ['setup.sh', 'tools/verify-installer-shell.sh']) {
    const syntax = run(shell, ['-n', script], {
      env: {
        ...process.env,
        NO_COLOR: '1',
        FORCE_COLOR: '0',
        MSYS2_ARG_CONV_EXCL: '*',
      },
      timeout: 60_000,
    });
    if (syntax.stdout) process.stdout.write(syntax.stdout);
    if (syntax.stderr) process.stderr.write(syntax.stderr);
    if (syntax.error) fail(`Shell-Syntaxprüfung konnte nicht gestartet werden (${script}): ${syntax.error.message}`);
    if (syntax.signal) fail(`Shell-Syntaxprüfung wurde durch Signal ${syntax.signal} beendet (${script}).`);
    if (syntax.status !== 0) {
      fail(`Shell-Syntaxprüfung fehlgeschlagen (${script}, Exit-Code ${syntax.status}). Verwendete Shell: ${shell}`);
    }
  }
  console.log('Installer-Shell-Portabilitätsgate erfolgreich: Git Bash hat setup.sh und den Linux-Funktionstest syntaktisch geprüft; die funktionale Docker-/NAS-/VPS-Simulation läuft im verpflichtenden Linux-CI-Gate.');
  process.exit(0);
}

const result = run(shell, ['tools/verify-installer-shell.sh'], {
  env: {
    ...process.env,
    NO_COLOR: '1',
    FORCE_COLOR: '0',
    VENDOO_INSTALLER_SHELL_HOST: 'posix',
  },
  timeout: 180_000,
});

if (result.stdout) process.stdout.write(result.stdout);
if (result.stderr) process.stderr.write(result.stderr);
if (result.error) fail(`Shell-Gate konnte nicht gestartet werden: ${result.error.message}`);
if (result.signal) fail(`Shell-Gate wurde durch Signal ${result.signal} beendet.`);
if (result.status !== 0) {
  const stdout = String(result.stdout || '').trim();
  const stderr = String(result.stderr || '').trim();
  const diagnostics = [
    stderr ? `Shell-Fehlerausgabe:\n${stderr}` : '',
    stdout ? `Shell-Standardausgabe:\n${stdout}` : '',
  ].filter(Boolean).join('\n\n');
  fail(`Shell-Gate endete mit Exit-Code ${result.status}. Verwendete Shell: ${shell}${diagnostics ? `\n${diagnostics}` : ''}`);
}

console.log(`Installer-Shell-Portabilitätsgate erfolgreich: ${shell} führte die vollständige Linux-/NAS-/VPS-Simulation mit strikter POSIX-Rechteprüfung aus.`);
