"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.debounce = exports.debounce_ = void 0;
// ets_tracing: off
const C = __importStar(require("../../Cause"));
const CL = __importStar(require("../../Clock"));
const A = __importStar(require("../../Collections/Immutable/Chunk"));
const Ex = __importStar(require("../../Exit"));
const Function_1 = require("../../Function");
const O = __importStar(require("../../Option"));
const Scope = __importStar(require("../../Scope"));
const T = __importStar(require("../_internal/effect"));
const F = __importStar(require("../_internal/fiber"));
const M = __importStar(require("../_internal/managed"));
const Ref = __importStar(require("../_internal/ref"));
const Pull = __importStar(require("../Pull"));
const definitions_1 = require("./definitions");
function debounce_(self, d) {
    class NotStarted {
        constructor() {
            this._tag = "NotStarted";
        }
    }
    class Previous {
        constructor(fiber) {
            this.fiber = fiber;
            this._tag = "Previous";
        }
    }
    class Current {
        constructor(fiber) {
            this.fiber = fiber;
            this._tag = "Current";
        }
    }
    class Done {
        constructor() {
            this._tag = "Done";
        }
    }
    return new definitions_1.Stream((M.map_(M.let_(M.bind_(M.bind_(M.do, "chunks", () => self.proc), "ref", () => (T.toManagedRelease_(Ref.makeRef(new NotStarted()), (_) => T.chain_(_.get, (state) => {
        switch (state._tag) {
            case "Previous":
                return F.interrupt(state.fiber);
            case "Current":
                return F.interrupt(state.fiber);
            default:
                return T.unit;
        }
    })))), "pull", ({ chunks, ref }) => {
        const store = (chunk) => (T.as_(O.getOrElse_(O.map_(A.last(chunk), (last) => (T.chain_(T.forkDaemon(T.as_(CL.sleep(d), last)), (f) => ref.set(new Previous(f))))), () => ref.set(new NotStarted())), A.empty()));
        return T.chain_(ref.get, (state) => {
            switch (state._tag) {
                case "Previous":
                    return T.transplant((graft) => (T.raceWithScope_(F.join(state.fiber), graft(chunks), (ex, current) => {
                        if (Ex.succeeded(ex)) {
                            return T.as_(ref.set(new Current(current)), A.single(ex.value));
                        }
                        else {
                            return T.zipRight_(F.interrupt(current), Pull.halt(ex.cause));
                        }
                    }, (ex, previous) => {
                        if (Ex.succeeded(ex)) {
                            const chunk = ex.value;
                            if (A.isEmpty(chunk)) {
                                return Pull.empty();
                            }
                            else {
                                return T.zipRight_(F.interrupt(previous), store(chunk));
                            }
                        }
                        else {
                            return O.fold_(C.sequenceCauseOption(ex.cause), () => (T.zipLeft_(T.map_(F.join(previous), A.single), ref.set(new Done()))), (e) => T.zipRight_(F.interrupt(previous), Pull.halt(e)));
                        }
                    }, Scope.globalScope)));
                case "Current":
                    return T.chain_(F.join(state.fiber), store);
                case "NotStarted":
                    return T.chain_(chunks, store);
                case "Done":
                    return Pull.end;
            }
        });
    }), ({ pull }) => pull)));
}
exports.debounce_ = debounce_;
function debounce(d) {
    return (self) => debounce_(self, d);
}
exports.debounce = debounce;
//# sourceMappingURL=debounce.js.map