/* eslint-disable @typescript-eslint/no-explicit-any */
/*
 * 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 {Client} from '@elastic/elasticsearch';
import {SearchResponse} from '@elastic/elasticsearch/lib/api/types.js';
import {
  SCMonitoringConfiguration,
  SCMonitoringLogAction,
  SCMonitoringMailAction,
  SCMonitoringWatcher,
  SCThings,
} from '@openstapps/core';
import {Logger} from '@openstapps/logger';
import {MailQueue} from '../../../src/notification/mail-queue.js';
import {setUp} from '../../../src/storage/elasticsearch/monitoring.js';

import {getTransport} from '../../common.js';
import {expect} from 'chai';
import sinon from 'sinon';
import cron from 'node-cron';

describe('Monitoring', async function () {
  const sandbox = sinon.createSandbox();
  const logAction: SCMonitoringLogAction = {
    message: 'Foo monitoring message',
    prefix: 'Backend Monitoring',
    type: 'log',
  };
  const mailAction: SCMonitoringMailAction = {
    message: 'Bar monitoring message',
    recipients: ['xyz@xyz.com'],
    subject: 'Backend Monitoring',
    type: 'mail',
  };
  let transport: any;
  let mailQueue: any;
  beforeEach(async function () {
    transport = getTransport(true);
    mailQueue = new MailQueue(transport);
    cronScheduleStub = sandbox.stub(cron, 'schedule');
  });
  afterEach(async function () {
    sandbox.restore();
  });
  // const sandbox = sinon.createSandbox();
  let cronScheduleStub: sinon.SinonStub;
  const minLengthWatcher: SCMonitoringWatcher = {
    actions: [logAction, mailAction],
    conditions: [
      {
        length: 10,
        type: 'MinimumLength',
      },
    ],
    name: 'foo watcher',
    query: {foo: 'bar'},
    triggers: [
      {
        executionTime: 'monthly',
        name: 'beginning of month',
      },
      {
        executionTime: 'daily',
        name: 'every night',
      },
    ],
  };
  const maxLengthWatcher: SCMonitoringWatcher = {
    actions: [logAction, mailAction],
    conditions: [
      {
        length: 30,
        type: 'MaximumLength',
      },
    ],
    name: 'foo watcher',
    query: {bar: 'foo'},
    triggers: [
      {
        executionTime: 'hourly',
        name: 'every hour',
      },
      {
        executionTime: 'weekly',
        name: 'every week',
      },
    ],
  };
  const monitoringConfig: SCMonitoringConfiguration = {
    actions: [logAction, mailAction],
    watchers: [minLengthWatcher, maxLengthWatcher],
  };

  it('should create a schedule for each trigger', async function () {
    await setUp(monitoringConfig, new Client({node: 'http://foohost:9200'}), mailQueue);

    expect(cronScheduleStub.callCount).to.be.equal(4);
  });

  it('should log errors where conditions failed', async function () {
    const fakeSearchResponse: SearchResponse<SCThings> = {
      took: 12,
      timed_out: false,
      // @ts-expect-error not assignable
      _shards: {},
      // @ts-expect-error not assignable
      hits: {
        total: 123,
      },
    };
    const fakeClient = new Client({node: 'http://foohost:9200'});
    const loggerErrorStub = sandbox.stub(Logger, 'error');
    const mailQueueSpy = sinon.spy(mailQueue, 'push');
    cronScheduleStub.yields();
    sandbox.stub(fakeClient, 'search').resolves(fakeSearchResponse);
    await setUp(monitoringConfig, fakeClient, mailQueue);

    expect(loggerErrorStub.callCount).to.be.equal(2);
    expect(mailQueueSpy.callCount).to.be.equal(2);
  });
});
