/* global libsignal, textsecure */

describe('SignalProtocolStore', () => {
  before(() => {
    localStorage.clear();
  });
  const store = textsecure.storage.protocol;
  const identifier = '+5558675309';
  const identityKey = {
    pubKey: libsignal.crypto.getRandomBytes(33),
    privKey: libsignal.crypto.getRandomBytes(32),
  };
  const testKey = {
    pubKey: libsignal.crypto.getRandomBytes(33),
    privKey: libsignal.crypto.getRandomBytes(32),
  };
  it('retrieves my registration id', async () => {
    store.put('registrationId', 1337);

    const reg = await store.getLocalRegistrationId();
    assert.strictEqual(reg, 1337);
  });
  it('retrieves my identity key', async () => {
    store.put('identityKey', identityKey);
    const key = await store.getIdentityKeyPair();
    assertEqualArrayBuffers(key.pubKey, identityKey.pubKey);
    assertEqualArrayBuffers(key.privKey, identityKey.privKey);
  });
  it('stores identity keys', async () => {
    await store.saveIdentity(identifier, testKey.pubKey);
    const key = await store.loadIdentityKey(identifier);
    assertEqualArrayBuffers(key, testKey.pubKey);
  });
  it('returns whether a key is trusted', async () => {
    const newIdentity = libsignal.crypto.getRandomBytes(33);
    await store.saveIdentity(identifier, testKey.pubKey);

    const trusted = await store.isTrustedIdentity(identifier, newIdentity);
    if (trusted) {
      throw new Error('Allowed to overwrite identity key');
    }
  });
  it('returns whether a key is untrusted', async () => {
    await store.saveIdentity(identifier, testKey.pubKey);
    const trusted = await store.isTrustedIdentity(identifier, testKey.pubKey);

    if (!trusted) {
      throw new Error('Allowed to overwrite identity key');
    }
  });
  it('stores prekeys', async () => {
    await store.storePreKey(1, testKey);

    const key = await store.loadPreKey(1);
    assertEqualArrayBuffers(key.pubKey, testKey.pubKey);
    assertEqualArrayBuffers(key.privKey, testKey.privKey);
  });
  it('deletes prekeys', async () => {
    await store.storePreKey(2, testKey);
    await store.removePreKey(2, testKey);

    const key = await store.loadPreKey(2);
    assert.isUndefined(key);
  });
  it('stores signed prekeys', async () => {
    await store.storeSignedPreKey(3, testKey);

    const key = await store.loadSignedPreKey(3);
    assertEqualArrayBuffers(key.pubKey, testKey.pubKey);
    assertEqualArrayBuffers(key.privKey, testKey.privKey);
  });
  it('deletes signed prekeys', async () => {
    await store.storeSignedPreKey(4, testKey);
    await store.removeSignedPreKey(4, testKey);

    const key = await store.loadSignedPreKey(4);
    assert.isUndefined(key);
  });
  it('stores sessions', async () => {
    const testRecord = 'an opaque string';
    const devices = [1, 2, 3].map(deviceId => [identifier, deviceId].join('.'));

    await Promise.all(
      devices.map(async encodedNumber => {
        await store.storeSession(encodedNumber, testRecord + encodedNumber);
      })
    );

    const records = await Promise.all(
      devices.map(store.loadSession.bind(store))
    );

    for (let i = 0, max = records.length; i < max; i += 1) {
      assert.strictEqual(records[i], testRecord + devices[i]);
    }
  });
  it('removes all sessions for a number', async () => {
    const testRecord = 'an opaque string';
    const devices = [1, 2, 3].map(deviceId => [identifier, deviceId].join('.'));

    await Promise.all(
      devices.map(async encodedNumber => {
        await store.storeSession(encodedNumber, testRecord + encodedNumber);
      })
    );

    await store.removeAllSessions(identifier);

    const records = await Promise.all(
      devices.map(store.loadSession.bind(store))
    );

    for (let i = 0, max = records.length; i < max; i += 1) {
      assert.isUndefined(records[i]);
    }
  });
  it('returns deviceIds for a number', async () => {
    const testRecord = 'an opaque string';
    const devices = [1, 2, 3].map(deviceId => [identifier, deviceId].join('.'));

    await Promise.all(
      devices.map(async encodedNumber => {
        await store.storeSession(encodedNumber, testRecord + encodedNumber);
      })
    );

    const deviceIds = await store.getDeviceIds(identifier);
    assert.sameMembers(deviceIds, [1, 2, 3]);
  });
  it('returns empty array for a number with no device ids', async () => {
    const deviceIds = await store.getDeviceIds('foo');
    assert.sameMembers(deviceIds, []);
  });
});