import { Piece, Store } from '@sapphire/pieces';
import { Awaitable } from '@sapphire/framework';
import { CronOptions, Cron } from 'croner';
import Sentry from '@sentry/node';

interface CronTaskHandlerOptions {
    /**
     * The default IANA timezone to use for all cron jobs.
     * You can override this per task, using the timezone option.
     */
    defaultTimezone?: string;
    /**
     * The ability to opt-out of instrumenting cron jobs with Sentry.
     * If you don't use Sentry, you can ignore this option.
     * @see https://docs.sentry.io/product/crons/
     * @default false
     */
    disableSentry: boolean;
}
interface CronJobOptions extends Pick<CronOptions, 'maxRuns' | 'unref' | 'timezone'> {
    pattern: string | Date;
    /**
     * If true, prevents the job from running if the previous execution is still in progress.
     * If the task has a protect method, it will be called if the job is blocked.
     * @default false
     */
    protect?: boolean;
}

/**
 * @example
 *
 * ```typescript
 * // ping.ts
 * import { CronTask } from '@kingsworld/plugin-cron';
 *
 * export class PingPong extends CronTask {
 * 	public constructor(context: CronTask.LoaderContext, options: CronTask.Options) {
 * 		super(context, {
 * 			...options,
 * 			pattern: '* * * * *'
 * 		});
 * 	}
 *
 * 	public run() {
 * 		this.info('Ping Pong! 🏓'); // CronTask[ping] Ping Pong! 🏓
 * 	}
 * }
 * ```
 */
declare abstract class CronTask<Options extends CronTask.Options = CronTask.Options> extends Piece<Options, 'cron-tasks'> {
    job: Cron;
    constructor(context: CronTask.LoaderContext, options: Options);
    abstract run(): Awaitable<unknown>;
    protect?(job: Cron): Awaitable<unknown>;
    catch?(error: unknown, job: Cron): Awaitable<unknown>;
    /**
     * A helper function to log messages with the `CronTask[${name}]` prefix.
     * @param message The message to include after the prefix
     * @param other Extra parameters to pass to the logger
     * @example
     * this.info('Hello world!'); // CronTask[my-task] Hello world!
     */
    info(message: string, ...other: unknown[]): void;
    /**
     * A helper function to log messages with the `CronTask[${name}]` prefix.
     * @param message The message to include after the prefix
     * @param other Extra parameters to pass to the logger
     * @example
     * this.error('Something went wrong!'); // CronTask[my-task] Something went wrong!
     */
    error(message: string, ...other: unknown[]): void;
    /**
     * A helper function to log messages with the `CronTask[${name}]` prefix.
     * @param message The message to include after the prefix
     * @param other Extra parameters to pass to the logger
     * @example
     * this.warn('Something is not right!'); // CronTask[my-task] Something is not right!
     */
    warn(message: string, ...other: unknown[]): void;
    /**
     * A helper function to log messages with the `CronTask[${name}]` prefix.
     * @param message The message to include after the prefix
     * @param other Extra parameters to pass to the logger
     * @example
     * this.debug('Something is happening!'); // CronTask[my-task] Something is happening!
     */
    debug(message: string, ...other: unknown[]): void;
    /**
     * A helper function to log messages with the `CronTask[${name}]` prefix.
     * @param message The message to include after the prefix
     * @param other Extra parameters to pass to the logger
     * @example
     * this.trace('Loaded the file.'); // CronTask[my-task] Loaded the file.
     */
    trace(message: string, ...other: unknown[]): void;
}
declare namespace CronTask {
    type Options = Piece.Options & CronJobOptions;
    /** @deprecated Use {@linkcode LoaderContext} instead. */
    type Context = LoaderContext;
    type LoaderContext = Piece.LoaderContext<'cron-tasks'>;
}

declare class CronTaskStore extends Store<CronTask, 'cron-tasks'> {
    constructor();
    /**
     * Loops over all tasks and pauses those that are running.
     *
     * @remarks
     * This method will only pause tasks that:
     * - Are enabled
     * - Are currently running
     * - Have not been permanently stopped
     *
     * @returns CronTaskStore
     */
    pauseAll(): this;
    /**
     * Loops over all tasks and resumes those that are paused.
     *
     * @remarks
     * This method will only resume tasks that:
     * - Are enabled
     * - Are not currently running
     * - Have not been permanently stopped
     *
     * @returns CronTaskStore
     */
    resumeAll(): this;
    /**
     * Loops over all tasks and stops those that are running.
     *
     * @remarks
     * This method will only stop tasks that:
     * - Are enabled
     * - Have not been permanently stopped
     *
     * ⚠️ Stopping jobs is **permanent** and cannot be resumed afterwards!
     *
     * @returns CronTaskStore
     */
    stopAll(): this;
    set(key: string, value: CronTask): this;
    /**
     * Deletes a task from the store and stops it if it's running.
     */
    delete(key: string): boolean;
    /**
     * Stops all running cron jobs and clears the store.
     */
    clear(): void;
}

declare class CronTaskHandler {
    /**
     * The default IANA/TZ timezone to use for all cron jobs.
     * You can override this per task, using the timezone option.
     * @see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
     */
    defaultTimezone?: CronTaskHandlerOptions['defaultTimezone'];
    /**
     * The ability to opt-out of instrumenting cron jobs with Sentry.
     * If you don't use Sentry, you can ignore this option.
     * @see https://docs.sentry.io/product/crons/
     * @default false
     */
    disableSentry: boolean;
    /**
     * The Sentry instance to use for instrumenting cron jobs.
     * This is only available when [`@sentry/node`](https://www.npmjs.com/package/@sentry/node)
     * is installed and the {@linkcode disableSentry} option is set to false.
     */
    sentry?: typeof Sentry;
    constructor(options?: Partial<CronTaskHandlerOptions>);
}

declare module '@sapphire/pieces' {
    interface Container {
        cronTasks: CronTaskHandler;
    }
    interface StoreRegistryEntries {
        'cron-tasks': CronTaskStore;
    }
}
declare module 'discord.js' {
    interface ClientOptions {
        cronTasks?: Partial<CronTaskHandlerOptions>;
    }
}
/**
 * The [@kingsworld/plugin-cron](https://github.com/Kings-World/sapphire-plugins/tree/main/packages/cron) version that you are currently using.
 * An example use of this is showing it of in a bot information command.
 *
 * Note to Sapphire developers: This needs to explicitly be `string` so it is not typed as the string that gets replaced by esbuild
 */
declare const version: string;

export { CronTask, CronTaskHandler, CronTaskStore, version };
export type { CronJobOptions, CronTaskHandlerOptions };
