"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.provideTestClock = exports.HasTestClock = exports.TestClock = exports.withClock = exports.withClockM = exports.sleep = exports.currentTime = exports.ProxyClock = exports.LiveClock = exports.HasClock = exports.Clock = exports.ClockSymbol = void 0;
// ets_tracing: off
/**
 * Ported from https://github.com/zio/zio/blob/master/core/shared/src/main/scala/zio/Clock.scala
 *
 * Copyright 2020 Michael Arnaldi and the Matechs Garage Contributors.
 */
require("../Operator");
const core_1 = require("../Effect/core");
const effectAsyncInterrupt_1 = require("../Effect/effectAsyncInterrupt");
const has_1 = require("../Effect/has");
const Has_1 = require("../Has");
exports.ClockSymbol = Symbol.for("@effect-ts/system/Clock");
//
// Clock Definition
//
class Clock {
    constructor() {
        this._tag = exports.ClockSymbol;
    }
}
exports.Clock = Clock;
//
// Has Clock
//
exports.HasClock = (0, Has_1.tag)(Clock).setKey(exports.ClockSymbol);
//
// Live Clock Implementation
//
class LiveClock extends Clock {
    constructor() {
        super(...arguments);
        this.currentTime = (0, core_1.succeedWith)(() => new Date().getTime());
        this.sleep = (ms, trace) => (0, effectAsyncInterrupt_1.effectAsyncInterrupt)((cb) => {
            const timeout = setTimeout(() => {
                cb(core_1.unit);
            }, ms);
            return (0, core_1.succeedWith)(() => {
                clearTimeout(timeout);
            });
        }, trace);
    }
}
exports.LiveClock = LiveClock;
//
// Proxy Clock Implementation
//
class ProxyClock extends Clock {
    constructor(currentTime, sleep) {
        super();
        this.currentTime = currentTime;
        this.sleep = sleep;
    }
}
exports.ProxyClock = ProxyClock;
/**
 * Get the current time in ms since epoch
 */
exports.currentTime = (0, has_1.accessServiceM)(exports.HasClock)((_) => _.currentTime);
/**
 * Sleeps for the provided amount of ms
 */
function sleep(ms, __trace) {
    return (0, has_1.accessServiceM)(exports.HasClock)((_) => _.sleep(ms, __trace));
}
exports.sleep = sleep;
/**
 * Access clock from environment
 */
exports.withClockM = (0, has_1.accessServiceM)(exports.HasClock);
/**
 * Access clock from environment
 */
exports.withClock = (0, has_1.accessService)(exports.HasClock);
//
// TestClock
//
class TestClock extends Clock {
    constructor() {
        super(...arguments);
        this.time = new Date().getTime();
        this.currentTime = (0, core_1.succeedWith)(() => this.time);
        this.sleep = () => core_1.unit;
        this.advance = (ms) => (0, core_1.succeedWith)(() => {
            this.time = this.time + ms;
        });
    }
}
exports.TestClock = TestClock;
TestClock.advance = (ms) => (0, has_1.accessServiceM)(exports.HasTestClock)((_) => _.advance(ms));
/**
 * Accesses the TestClock
 */
exports.HasTestClock = (0, Has_1.tag)().setKey(exports.HasClock.key);
// @ts-expect-error
exports.provideTestClock = (0, has_1.provideServiceM)(exports.HasTestClock)((0, core_1.succeedWith)(() => new TestClock()));
//# sourceMappingURL=index.js.map