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_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_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.strictEqual(console_log_to_string(inspectable), `Inspectable { 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();
};
