import * as plugins from './smarttime.plugins.js';
import { CronManager } from './smarttime.classes.cronmanager.js';

import { CronParser } from './smarttime.classes.cronparser.js';

export type TJobFunction =
  | ((triggerTimeArg?: number) => void)
  | ((triggerTimeArg?: number) => Promise<any>);

export class CronJob {
  public cronParser: plugins.croner;
  public status: 'started' | 'stopped' | 'initial' = 'initial';
  public cronExpression: string;
  public jobFunction: TJobFunction;
  private nextExecutionUnix: number = 0;

  constructor(cronManager: CronManager, cronExpressionArg: string, jobFunction: TJobFunction) {
    this.cronExpression = cronExpressionArg;
    this.jobFunction = jobFunction;
    this.cronParser = plugins.croner(cronExpressionArg);
  }

  /**
   * checks wether the cronjob needs to be executed
   */
  public checkExecution(): number {
    if (this.nextExecutionUnix === 0) {
      this.getNextExecutionTime();
    }
    if (Date.now() > this.nextExecutionUnix) {
      const maybePromise = this.jobFunction(this.nextExecutionUnix);
      if (maybePromise instanceof Promise) {
        maybePromise.catch((e) => console.log(e));
      }
      this.nextExecutionUnix = this.getNextExecutionTime();
    }
    return this.nextExecutionUnix;
  }

  public getNextExecutionTime() {
    return (this.nextExecutionUnix = Date.now() + this.getTimeToNextExecution());
  }

  /**
   * gets the time to next execution
   */
  public getTimeToNextExecution() {
    return this.cronParser.msToNext();
  }

  public start() {
    this.status = 'started';
  }

  public stop() {
    this.status = 'stopped';
  }
}
