import * as assert from '../assert.js';
import * as utilities from '../utilities.js';

const version = 0x01;
const emptyModuleArray = Uint8Array.of(0x0, 0x61, 0x73, 0x6d, version, 0x00, 0x00, 0x00);
const invalidConstructorInputs = [undefined, null, "", 1, {}, []];
const invalidInstanceImports = [null, "", 1];

const checkOwnPropertyDescriptor = (obj, prop, expect) => {
    const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
    assert.eq(typeof descriptor.value, expect.typeofvalue);
    assert.eq(descriptor.writable, expect.writable);
    assert.eq(descriptor.configurable, expect.configurable);
    assert.eq(descriptor.enumerable, expect.enumerable);
};

const checkAccessorOwnPropertyDescriptor = (obj, prop, expect) => {
    const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
    assert.eq(typeof descriptor.value, "undefined");
    assert.eq(typeof descriptor.writable, "undefined");
    assert.eq(descriptor.configurable, expect.configurable);
    assert.eq(descriptor.enumerable, expect.enumerable);
};

const functionProperties = {
    "validate": { length: 1 },
    "compile":  { length: 1 },
};
const constructorProperties = {
    "Module":       { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
    "Instance":     { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
    "Memory":       { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
    "Table":        { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
    "CompileError": { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
    "LinkError":    { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
    "RuntimeError": { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
};


assert.isNotUndef(WebAssembly);
checkOwnPropertyDescriptor(utilities.global, "WebAssembly", { typeofvalue: "object", writable: true, configurable: true, enumerable: false });
assert.eq(String(WebAssembly), "[object WebAssembly]");
assert.isUndef(WebAssembly.length);
assert.eq(WebAssembly instanceof Object, true);
assert.throws(() => WebAssembly(), TypeError, `WebAssembly is not a function. (In 'WebAssembly()', 'WebAssembly' is an instance of WebAssembly)`);
assert.throws(() => new WebAssembly(), TypeError, `WebAssembly is not a constructor (evaluating 'new WebAssembly()')`);

for (const f in functionProperties) {
    assert.isNotUndef(WebAssembly[f]);
    assert.eq(WebAssembly[f].name, f);
    assert.eq(WebAssembly[f].length, functionProperties[f].length);
}

for (const c in constructorProperties) {
    assert.isNotUndef(WebAssembly[c]);
    assert.eq(WebAssembly[c].name, c);
    assert.eq(WebAssembly[c].length, constructorProperties[c].length);
    checkOwnPropertyDescriptor(WebAssembly, c, constructorProperties[c]);
    checkOwnPropertyDescriptor(WebAssembly[c], "prototype", { typeofvalue: "object", writable: false, configurable: false, enumerable: false });
    if (["CompileError", "LinkError", "RuntimeError"].indexOf(c) >= 0)
        WebAssembly[c](); // Per spec, the WebAssembly.*Error types match ye olden JavaScript NativeError behavior: they can be constructed without `new`.
    else
        assert.throws(() => WebAssembly[c](), TypeError, `calling WebAssembly.${c} constructor without new is invalid`);
    switch (c) {
    case "Module":
        for (const invalid of invalidConstructorInputs)
            assert.throws(() => new WebAssembly[c](invalid), TypeError, `first argument must be an ArrayBufferView or an ArrayBuffer (evaluating 'new WebAssembly[c](invalid)')`);
        for (const buffer of [new ArrayBuffer(), new DataView(new ArrayBuffer()), new Int8Array(), new Uint8Array(), new Uint8ClampedArray(), new Int16Array(), new Uint16Array(), new Int32Array(), new Uint32Array(), new Float32Array(), new Float64Array()])
            // FIXME the following should be WebAssembly.CompileError. https://bugs.webkit.org/show_bug.cgi?id=163768
            assert.throws(() => new WebAssembly[c](buffer), Error, `WebAssembly.Module doesn't parse at byte 0 / 0: expected a module of at least 8 bytes (evaluating 'new WebAssembly[c](buffer)')`);
        assert.instanceof(new WebAssembly[c](emptyModuleArray), WebAssembly.Module);
        break;
    case "Instance":
        for (const invalid of invalidConstructorInputs)
            assert.throws(() => new WebAssembly[c](invalid), TypeError, `first argument to WebAssembly.Instance must be a WebAssembly.Module (evaluating 'new WebAssembly[c](invalid)')`);
        const instance = new WebAssembly[c](new WebAssembly.Module(emptyModuleArray));
        assert.instanceof(instance, WebAssembly.Instance);
        for (const invalid of invalidInstanceImports)
            assert.throws(() => new WebAssembly[c](new WebAssembly.Module(emptyModuleArray), invalid), TypeError, `second argument to WebAssembly.Instance must be undefined or an Object (evaluating 'new WebAssembly[c](new WebAssembly.Module(emptyModuleArray), invalid)')`);
        assert.isNotUndef(instance.exports);
        checkAccessorOwnPropertyDescriptor(WebAssembly.Instance.prototype, "exports", { configurable: true, enumerable: false });
        assert.throws(() => WebAssembly.Instance.prototype.exports = undefined, TypeError, `Attempted to assign to readonly property.`);
        assert.throws(() => WebAssembly.Instance.prototype.exports, TypeError, `expected |this| value to be an instance of WebAssembly.Instance`);
        assert.isUndef(instance.exports.__proto__);
        assert.eq(Reflect.isExtensible(instance.exports), false);
        assert.eq(Symbol.iterator in instance.exports, false);
        assert.eq(Symbol.toStringTag in instance.exports, true);
        assert.eq(Object.getOwnPropertySymbols(instance.exports).length, 1);
        assert.eq(Object.getOwnPropertySymbols(instance.exports)[0], Symbol.toStringTag);
        assert.throws(() => instance.exports[Symbol.toStringTag] = 42, TypeError, `Attempted to assign to readonly property.`);
        break;
    case "Memory":
        new WebAssembly.Memory({initial: 20});
        break;
    case "Table":
        new WebAssembly.Table({initial: 20, element: "anyfunc"});
        new WebAssembly.Table({initial: 20, maximum: 20, element: "anyfunc"});
        new WebAssembly.Table({initial: 20, maximum: 25, element: "anyfunc"});
        break;
    case "CompileError":
    case "LinkError":
    case "RuntimeError": {
        {
            const e = new WebAssembly[c];
            assert.eq(e instanceof WebAssembly[c], true);
            assert.eq(e instanceof Error, true);
            assert.eq(e instanceof TypeError, false);
            assert.eq(e.message, "");
            assert.eq(typeof e.stack, "string");
            const sillyString = "uh-oh!";
            const e2 = new WebAssembly[c](sillyString);
            assert.eq(e2.message, sillyString + " (evaluating 'new WebAssembly[c](sillyString)')");
        }
        {
            const e = WebAssembly[c]();
            assert.eq(e instanceof WebAssembly[c], true);
            assert.eq(e instanceof Error, true);
            assert.eq(e instanceof TypeError, false);
            assert.eq(e.message, "");
            assert.eq(typeof e.stack, "string");
            const sillyString = "uh-oh!";
            const e2 = WebAssembly[c](sillyString);
            assert.eq(e2.message, sillyString);
        }
    } break;
    default: throw new Error(`Implementation error: unexpected constructor property "${c}"`);
    }
}
