/*
 * Copyright (C) 2020 StApps
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
import {SMTP, Transport} from '@openstapps/logger';
import {expect} from 'chai';
import mockedEnv from 'mocked-env';
import {BackendTransport, isTransportWithVerification} from '../../src/notification/backend-transport.js';
import sinon from 'sinon';

describe('Backend transport', function () {
  describe('isTransportWithVerification', function () {
    it('should return false if transport is not verifiable', function () {
      expect(isTransportWithVerification({} as Transport)).to.be.false;
      expect(isTransportWithVerification({verify: 'foo'} as unknown as Transport)).to.be.false;
    });

    it('should return true if transport is verifiable', function () {
      // a transport which has verify function should be verifiable
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      expect(isTransportWithVerification({verify: () => {}} as unknown as Transport)).to.be.true;
    });
  });

  describe('BackendTransport', async function () {
    const sandbox = sinon.createSandbox();

    afterEach(function () {
      BackendTransport.destroy();
      sandbox.restore();
    });

    it('should provide only one instance of the transport', function () {
      // @ts-expect-error not assignable
      sandbox.stub(SMTP, 'getInstance').callsFake(() => {
        return {};
      });
      const transport1 = BackendTransport.getTransportInstance();
      const transport2 = BackendTransport.getTransportInstance();
      expect(transport1).to.be.equal(transport2);
    });

    it('should not throw in case of error getting SMTP instance when transport not allowed', function () {
      sandbox.stub(SMTP, 'getInstance').throws('Foo Error');
      // @ts-expect-error wrong type defs for some reason
      const restore = mockedEnv({
        ALLOW_NO_TRANSPORT: 'true',
      });

      expect(() => BackendTransport.getTransportInstance()).to.not.throw();

      // restore env variables
      restore();
    });

    it('should throw in case of error getting SMTP instance when transport is allowed', function () {
      sandbox.stub(SMTP, 'getInstance').throws('Foo Error');
      // @ts-expect-error wrong type defs for some reason
      const restore = mockedEnv({
        ALLOW_NO_TRANSPORT: undefined,
      });

      expect(() => BackendTransport.getTransportInstance()).to.throw();

      // restore env variables
      restore();
    });

    it('should provide information that the transport if waiting for its verification', function () {
      // @ts-expect-error not assignable
      sandbox.stub(SMTP, 'getInstance').callsFake(() => {
        return {verify: () => Promise.resolve(true)};
      });

      expect(BackendTransport.getInstance().isWaitingForVerification()).to.be.true;
    });

    it('should provide information that the transport if not waiting for its verification after the verification is over', function () {
      sinon.stub(SMTP.prototype, 'verify').resolves(true);

      expect(BackendTransport.getInstance().isWaitingForVerification()).to.be.false;
    });
  });
});
