const wasm = require('wasm-bindgen-test.js');
const assert = require('assert');

exports.js_simple = () => {
    const r = new wasm.ClassesSimple();
    assert.strictEqual(r.add(0), 0);
    assert.strictEqual(r.add(1), 1);
    assert.strictEqual(r.add(1), 2);
    r.add(2);
    assert.strictEqual(r.consume(), 4);
    assert.throws(() => r.free(), /null pointer passed to rust/);

    const r2 = wasm.ClassesSimple.with_contents(10);
    assert.strictEqual(r2.add(1), 11);
    assert.strictEqual(r2.add(2), 13);
    assert.strictEqual(r2.add(3), 16);
    r2.free();

    const r3 = new wasm.ClassesSimple();
    assert.strictEqual(r3.add(42), 42);
    r3.free();
};

exports.js_strings = () => {
    const r = wasm.ClassesStrings1.new();
    r.set(3);
    let bar = r.bar('baz');
    r.free();
    assert.strictEqual(bar.name(), 'foo-baz-3');
    bar.free();
};

exports.js_exceptions = () => {
    // this test only works when `--debug` is passed to `wasm-bindgen` (or the
    // equivalent thereof)
    if (require('process').env.WASM_BINDGEN_NO_DEBUG)
        return;
    assert.throws(() => new wasm.ClassesExceptions1(), /cannot invoke `new` directly/);
    let a = wasm.ClassesExceptions1.new();
    a.free();
    assert.throws(() => a.free(), /null pointer passed to rust/);

    let b = wasm.ClassesExceptions1.new();
    b.foo(b);
    assert.throws(() => b.bar(b), /recursive use of an object/);

    let c = wasm.ClassesExceptions1.new();
    let d = wasm.ClassesExceptions2.new();
    assert.throws(() => c.foo(d), /expected instance of ClassesExceptions1/);
    d.free();
    c.free();
};

exports.js_pass_one_to_another = () => {
    let a = wasm.ClassesPassA.new();
    let b = wasm.ClassesPassB.new();
    a.foo(b);
    a.bar(b);
    a.free();
};

exports.take_class = foo => {
    assert.strictEqual(foo.inner(), 13);
    foo.free();
    assert.throws(() => foo.free(), /null pointer passed to rust/);
};

exports.js_constructors = () => {
    const foo = new wasm.ConstructorsFoo(1);
    assert.strictEqual(foo.get_number(), 1);
    foo.free();

    assert.strictEqual(wasm.ConstructorsBar.new, undefined);
    const foo2 = new wasm.ConstructorsFoo(2);
    assert.strictEqual(foo2.get_number(), 2);
    foo2.free();

    const bar = new wasm.ConstructorsBar(3, 4);
    assert.strictEqual(bar.get_sum(), 7);
    bar.free();

    assert.strictEqual(wasm.ConstructorsBar.other_name, undefined);
    const bar2 = new wasm.ConstructorsBar(5, 6);
    assert.strictEqual(bar2.get_sum(), 11);
    bar2.free();

    assert.strictEqual(wasm.cross_item_construction().get_sum(), 15);
};

exports.js_empty_structs = () => {
    wasm.OtherEmpty.return_a_value();
};

exports.js_public_fields = () => {
    const a = wasm.PublicFields.new();
    assert.strictEqual(a.a, 0);
    a.a = 3;
    assert.strictEqual(a.a, 3);

    assert.strictEqual(a.b, 0);
    a.b = 7;
    assert.strictEqual(a.b, 7);

    assert.strictEqual(a.c, 0);
    a.c = 8;
    assert.strictEqual(a.c, 8);

    assert.strictEqual(a.d, 0);
    a.d = 3.3;
    assert.strictEqual(a.d, 3);

    assert.strictEqual(a.skipped, undefined);
};

exports.js_getter_with_clone = () => {
    const a = wasm.GetterWithCloneStruct.new();
    assert.strictEqual(a.a, '');
    a.a = 'foo';
    assert.strictEqual(a.a, 'foo');

    const b = wasm.GetterWithCloneStructField.new();
    assert.strictEqual(b.a, '');
    b.a = 'foo';
    assert.strictEqual(b.a, 'foo');
};

exports.js_using_self = () => {
    wasm.UseSelf.new().free();
};

exports.js_readonly_fields = () => {
    const a = wasm.Readonly.new();
    assert.strictEqual(a.a, 0);
    a.a = 3;
    assert.strictEqual(a.a, 0);
    a.free();
};

exports.js_double_consume = () => {
    const r = new wasm.DoubleConsume();
    assert.throws(() => r.consume(r));
};


exports.js_js_rename = () => {
    (new wasm.JsRename()).bar();
    wasm.classes_foo();
};

exports.js_access_fields = () => {
    assert.ok((new wasm.AccessFieldFoo()).bar instanceof wasm.AccessFieldBar);
    assert.ok((new wasm.AccessField0())[0] instanceof wasm.AccessFieldBar);
};

exports.js_renamed_export = () => {
    const x = new wasm.JsRenamedExport();
    assert.ok(x.x === 3);
    x.foo();
    x.bar(x);
};

exports.js_renamed_field = () => {
    const x = new wasm.RenamedField();
    assert.ok(x.bar === 3);

    x.foo();
}

exports.js_conditional_bindings = () => {
    const x = new wasm.ConditionalBindings();
    x.free();
};

exports.js_assert_none = x => {
  assert.strictEqual(x, undefined);
};
exports.js_assert_some = x => {
  assert.ok(x instanceof wasm.OptionClass);
};
exports.js_return_none1 = () => null;
exports.js_return_none2 = () => undefined;
exports.js_return_some = x => x;

exports.js_test_option_classes = () => {
  assert.strictEqual(wasm.option_class_none(), undefined);
  wasm.option_class_assert_none(undefined);
  wasm.option_class_assert_none(null);
  const c = wasm.option_class_some();
  assert.ok(c instanceof wasm.OptionClass);
  wasm.option_class_assert_some(c);
};

/**
 * Invokes `console.log`, but logs to a string rather than stdout
 * @param {any} data Data to pass to `console.log`
 * @returns {string} Output from `console.log`, without color or trailing newlines
 */
const console_log_to_string = data => {
    // Store the original stdout.write and create a console that logs without color
    const original_write = process.stdout.write;
    const colorless_console = new console.Console({
      stdout: process.stdout,
      colorMode: false
    });
    let output = '';

    // Change stdout.write to append to our string, then restore the original function
    process.stdout.write = chunk => output += chunk.trim();
    colorless_console.log(data);
    process.stdout.write = original_write;

    return output;
};

exports.js_test_inspectable_classes = () => {
    const inspectable = wasm.Inspectable.new();
    const not_inspectable = wasm.NotInspectable.new();
    // Inspectable classes have a toJSON and toString implementation generated
    assert.deepStrictEqual(inspectable.toJSON(), { a: inspectable.a });
    assert.strictEqual(inspectable.toString(), `{"a":${inspectable.a}}`);
    // Inspectable classes in Node.js have improved console.log formatting as well
    assert(console_log_to_string(inspectable).endsWith(`{ a: ${inspectable.a} }`));
    // Non-inspectable classes do not have a toJSON or toString generated
    assert.strictEqual(not_inspectable.toJSON, undefined);
    assert.strictEqual(not_inspectable.toString(), '[object Object]');
    // Non-inspectable classes in Node.js have no special console.log formatting
    assert.strictEqual(console_log_to_string(not_inspectable), `NotInspectable { ptr: ${not_inspectable.ptr} }`);
    inspectable.free();
    not_inspectable.free();
};

exports.js_test_inspectable_classes_can_override_generated_methods = () => {
    const overridden_inspectable = wasm.OverriddenInspectable.new();
    // Inspectable classes can have the generated toJSON and toString overwritten
    assert.strictEqual(overridden_inspectable.a, 0);
    assert.deepStrictEqual(overridden_inspectable.toJSON(), 'JSON was overwritten');
    assert.strictEqual(overridden_inspectable.toString(), 'string was overwritten');
    overridden_inspectable.free();
};
