/**
 * Cross-protocol browser.execute() wrapper.
 *
 * WebDriverIO's devtools protocol (CDP via puppeteer-core) breaks when
 * browser.execute() receives a function argument because:
 *   1. WebDriverIO prepends a polyfill before `return (fn).apply(null, arguments)`
 *   2. The devtools executeScript trims the script, finds no leading `return`,
 *      and passes it directly to eval()
 *   3. eval() fails with "Illegal return statement" because `return` is outside
 *      a function body (the polyfill lines precede it)
 *
 * Fix: always pass a string expression to browser.execute(). Arguments are
 * JSON-serialized and inlined into the script — no reliance on the `arguments`
 * object which is protocol-dependent.
 *
 * Works identically with:
 *   - WebDriver protocol (Tauri via tauri-driver)
 *   - devtools/CDP protocol (Electrobun via CEF)
 */

import { browser } from '@wdio/globals';

/**
 * Execute a function in the browser, cross-protocol safe.
 *
 * Usage mirrors browser.execute():
 *   exec(() => document.title)
 *   exec((sel) => document.querySelector(sel) !== null, '.my-class')
 *   exec((a, b) => a + b, 1, 2)
 */
export async function exec<R>(fn: (...args: any[]) => R, ...args: any[]): Promise<R> {
  const fnStr = fn.toString();
  const serializedArgs = args.map(a => JSON.stringify(a)).join(', ');
  // Wrap as an IIFE expression — no `return` at the top level
  const script = `return (${fnStr})(${serializedArgs})`;
  return browser.execute(script) as Promise<R>;
}

/**
 * Skip a test programmatically — works with both protocols.
 *
 * Mocha's this.skip() requires a non-arrow `function()` context. In
 * WebDriverIO hooks (beforeTest), `this` may not carry the Mocha context
 * with devtools protocol. This helper uses the same mechanism but is
 * callable from any context that has the Mocha `this`.
 *
 * Usage inside `it('...', async function () { ... })`:
 *   if (condition) { skipTest(this); return; }
 */
export function skipTest(ctx: Mocha.Context): void {
  ctx.skip();
}
