import dayjs, { type Dayjs } from "dayjs";
import { SimpleIntervalJob, Task, ToadScheduler } from "toad-scheduler";

export const RT_TICK_DEFAULT = 500;
let RT_TICK = 500;

export const setRtTick = (tick: number) => {
    RT_TICK = tick;
}

export abstract class RealtimePlayer {

    //logger: Logger;
    scheduler: ToadScheduler = new ToadScheduler();

    protected position: number = 0;
    private clockTS: Dayjs = dayjs();

    protected constructor(/* logger: Logger */) {
        this.position = 0;
        const job = new SimpleIntervalJob({
            milliseconds: RT_TICK,
            runImmediately: true
        }, new Task('updatePos', () => {
            // in production RT_TICK and the diff between now and clockTS should always be the same
            // but in order to mock for testing (where we manipulate Date now()) the source of truth
            // needs to come from TS rather than simple TICK increase
            this.setPosition()
            //this.position += Math.abs(dayjs().diff(this.clockTS, 'ms')); // RT_TICK

        }), { id: 'rt' });
        this.scheduler.addSimpleIntervalJob(job);
        this.scheduler.stop();
    }

    [Symbol.dispose]() {
        this.scheduler.stop();
        for(const job of this.scheduler.getAllJobs()) {
            this.scheduler.removeById(job.id);
        }
    }

    public play(position?: number) {
        if (position !== undefined) {
            this.position = position;
        }
        this.clockTS = dayjs();
        this.scheduler.startById('rt');
    }

    public pause() {
        this.scheduler.stop();
    }

    public stop() {
        this.pause();
        this.position = 0;
    }

    public seek(position: number) {
        this.position = position;
    }

    public getPosition(asSeconds: boolean = false) {
        if(this.position === 0 || this.position === undefined) {
            return 0;
        }
        return !asSeconds ? this.position : this.position / 1000;
    }

    public setPosition(time?: number) {
        if(time === undefined) {
            this.position += Math.abs(dayjs().diff(this.clockTS, 'ms'));
        } else {
            this.position = time;
        }
        this.clockTS = dayjs();
    }
}

export class GenericRealtimePlayer extends RealtimePlayer {
    constructor(/* logger: Logger */) {
        super();
    }
}