const test = require('tap').test;

// Mock `window` and `document.createElement` for twgl.js.
global.window = {};
global.document = {
    createElement: () => ({getContext: () => {}})
};

const Drawable = require('../../src/Drawable');
const MockSkin = require('../fixtures/MockSkin');
const Rectangle = require('../../src/Rectangle');

/**
 * Returns a Rectangle-like object, with dimensions rounded to the given number
 * of digits.
 * @param {Rectangle} rect The source rectangle.
 * @param {int} decimals The number of decimal points to snap to.
 * @returns {object} An object with left/right/top/bottom attributes.
 */
const snapToNearest = function (rect, decimals = 3) {
    return {
        left: rect.left.toFixed(decimals),
        right: rect.right.toFixed(decimals),
        bottom: rect.bottom.toFixed(decimals),
        top: rect.top.toFixed(decimals)
    };
};

test('translate by position', t => {
    const expected = new Rectangle();
    const drawable = new Drawable();
    drawable.skin = new MockSkin();
    drawable.skin.size = [200, 50];

    expected.initFromBounds(0, 200, -50, 0);
    t.same(snapToNearest(drawable.getAABB()), expected);

    drawable.updateProperties({position: [1, 2]});
    expected.initFromBounds(1, 201, -48, 2);
    t.same(snapToNearest(drawable.getAABB()), expected);

    t.end();
});

test('translate by costume center', t => {
    const expected = new Rectangle();
    const drawable = new Drawable();
    drawable.skin = new MockSkin();
    drawable.skin.size = [200, 50];

    drawable.skin.rotationCenter = [1, 0];
    expected.initFromBounds(-1, 199, -50, 0);
    t.same(snapToNearest(drawable.getAABB()), expected);

    drawable.skin.rotationCenter = [0, -2];
    expected.initFromBounds(0, 200, -52, -2);
    t.same(snapToNearest(drawable.getAABB()), expected);

    t.end();
});

test('translate and rotate', t => {
    const expected = new Rectangle();
    const drawable = new Drawable();
    drawable.skin = new MockSkin();
    drawable.skin.size = [200, 50];

    drawable.updateProperties({position: [1, 2], direction: 0});
    expected.initFromBounds(1, 51, 2, 202);
    t.same(snapToNearest(drawable.getAABB()), expected);

    drawable.updateProperties({direction: 180});
    expected.initFromBounds(-49, 1, -198, 2);
    t.same(snapToNearest(drawable.getAABB()), expected);

    drawable.skin.rotationCenter = [100, 25];
    drawable.updateProperties({direction: 270, position: [0, 0]});
    expected.initFromBounds(-100, 100, -25, 25);
    t.same(snapToNearest(drawable.getAABB()), expected);

    drawable.updateProperties({direction: 90});
    t.same(snapToNearest(drawable.getAABB()), expected);

    t.end();
});

test('rotate by non-right-angles', t => {
    const expected = new Rectangle();
    const drawable = new Drawable();
    drawable.skin = new MockSkin();
    drawable.skin.size = [10, 10];
    drawable.skin.rotationCenter = [5, 5];

    expected.initFromBounds(-5, 5, -5, 5);
    t.same(snapToNearest(drawable.getAABB()), expected);

    drawable.updateProperties({direction: 45});
    expected.initFromBounds(-7.071, 7.071, -7.071, 7.071);
    t.same(snapToNearest(drawable.getAABB()), expected);

    t.end();
});

test('scale', t => {
    const expected = new Rectangle();
    const drawable = new Drawable();
    drawable.skin = new MockSkin();
    drawable.skin.size = [200, 50];

    drawable.updateProperties({scale: [100, 50]});
    expected.initFromBounds(0, 200, -25, 0);
    t.same(snapToNearest(drawable.getAABB()), expected);

    drawable.skin.rotationCenter = [0, 25];
    expected.initFromBounds(0, 200, -12.5, 12.5);
    t.same(snapToNearest(drawable.getAABB()), expected);

    drawable.skin.rotationCenter = [150, 50];
    drawable.updateProperties({scale: [50, 50]});
    expected.initFromBounds(-75, 25, 0, 25);
    t.same(snapToNearest(drawable.getAABB()), expected);

    t.end();
});

test('rotate and scale', t => {
    const expected = new Rectangle();
    const drawable = new Drawable();
    drawable.skin = new MockSkin();
    drawable.skin.size = [100, 1000];

    drawable.skin.rotationCenter = [50, 50];
    expected.initFromBounds(-50, 50, -950, 50);
    t.same(snapToNearest(drawable.getAABB()), expected);

    drawable.updateProperties({scale: [40, 60]});
    drawable.skin.rotationCenter = [50, 50];
    expected.initFromBounds(-20, 20, -570, 30);
    t.same(snapToNearest(drawable.getAABB()), expected);

    t.end();
});