import * as ReactNativeKeychain from 'react-native-keychain';
import sinon from 'sinon';

import { assert } from '~/test/utils';

import { save, load, reset } from './keychain';

const CREDENTIALS = {
  username: 'username',
  password: 'password',
};

describe('keychain', function () {
  const setInternetCredentials = sinon.stub(ReactNativeKeychain, 'setInternetCredentials');
  const setGenericPassword = sinon.stub(ReactNativeKeychain, 'setGenericPassword');
  const getInternetCredentials = sinon.stub(ReactNativeKeychain, 'getInternetCredentials');
  const getGenericPassword = sinon.stub(ReactNativeKeychain, 'getGenericPassword');
  const resetInternetCredentials = sinon.stub(ReactNativeKeychain, 'resetInternetCredentials');
  const resetGenericPassword = sinon.stub(ReactNativeKeychain, 'resetGenericPassword');

  beforeEach(function () {
    setInternetCredentials.reset();
    setGenericPassword.reset();
    setGenericPassword.returns(true as any);
    getInternetCredentials.reset();
    getInternetCredentials.returns(CREDENTIALS as any);
    getGenericPassword.reset();
    getGenericPassword.returns(CREDENTIALS as any);
    resetInternetCredentials.reset();
    resetGenericPassword.reset();
    resetGenericPassword.returns(true as any);
  });

  it('save with server', async function () {
    const response = await save('username', 'password', 'server1');
    expect(response).toBeTruthy();
    assert.calledOnceWithExactly(setInternetCredentials, 'server1', 'username', 'password');
  });

  it('save wihtout server', async function () {
    const response = await save('username', 'password');
    expect(response).toBeTruthy();
    assert.calledOnceWithExactly(setGenericPassword, 'username', 'password');
  });

  it('load with server', async function () {
    const response = await load('server1');
    expect(response.username).toBe('username');
    expect(response.password).toBe('password');
    expect(response.server).toBe('server1');
    assert.calledOnceWithExactly(getInternetCredentials, 'server1');
  });

  it('load with server and null credentials', async function () {
    getInternetCredentials.returns(null);
    const response = await load('server1');
    expect(response.username).toBeNull();
    expect(response.password).toBeNull();
    expect(response.server).toBe('server1');
    assert.calledOnceWithExactly(getInternetCredentials, 'server1');
  });

  it('load wihtout server', async function () {
    const response = await load();
    expect(response.username).toBe('username');
    expect(response.password).toBe('password');
    expect(response.server).toBeNull();
    assert.calledOnce(getGenericPassword);
  });

  it('load without credentials', async function () {
    getGenericPassword.returns('invalid' as any);
    const response = await load();
    expect(response.username).toBeNull();
    expect(response.password).toBeNull();
    expect(response.server).toBeNull();
    assert.calledOnce(getGenericPassword);
  });

  it('reset with server', async function () {
    const response = await reset('server1');
    expect(response).toBeTruthy();
    assert.calledOnceWithExactly(resetInternetCredentials, 'server1');
  });

  it('reset wihtout server', async function () {
    const response = await reset();
    expect(response).toBeTruthy();
    assert.calledOnce(resetGenericPassword);
  });
});
