"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CUSTOM_HEADER_X_EVENT_SOURCE_ID = void 0;
const _1 = require("../../../../../Class/$");
const Holder_1 = require("../../../../../Class/Holder");
const intercept_1 = require("../../../../../client/platform/web/api/intercept");
const APINotImplementedError_1 = require("../../../../../exception/APINotImplementedError");
const id_1 = require("../../../../../util/id");
const _ids_1 = require("../../../../_ids");
exports.CUSTOM_HEADER_X_EVENT_SOURCE_ID = 'X-EventSource-Id';
class EventSource_ extends Holder_1.Holder {
    constructor(system) {
        super({
            fi: ['url', 'opt'],
            fo: ['emitter'],
            i: [],
            o: [],
        }, {
            output: {
                emitter: {
                    ref: true,
                },
            },
        }, system, _ids_1.ID_EVENT_SOURCE, 'close');
        this._eventSource = null;
    }
    async f({ url, opt }, done, fail) {
        const { api: { http: { EventSource, fetch }, window: { nextTick }, }, cache: { interceptors, eventSources }, } = this.__system;
        if (!EventSource) {
            fail((0, APINotImplementedError_1.apiNotSupportedError)('EventSource'));
            return;
        }
        const emitter = new (class EventEmitter__ extends _1.$ {
        })(this.__system);
        const willIntercept = interceptors.some((interceptor) => (0, intercept_1.intercept)(interceptor.opt, url));
        if (willIntercept) {
            const internalId = (0, id_1.uuidNotIn)(eventSources);
            const upgrade = async () => {
                return await fetch(url, {
                    method: 'GET',
                    headers: {
                        Accept: 'text/event-stream',
                        [exports.CUSTOM_HEADER_X_EVENT_SOURCE_ID]: internalId,
                    },
                }, interceptors);
            };
            const eventSource = {
                readyState: EventSource.CONNECTING,
                onopen: function () {
                    emitter.emit('open', {});
                },
                onmessage: function (event) {
                    const { data } = event;
                    emitter.emit('message', data);
                },
                onerror: function (event) {
                    if (eventSource.readyState === EventSource.CLOSED) {
                        emitter.emit('error', {});
                    }
                },
                close: function () {
                    //
                },
            };
            this._eventSource = eventSource;
            eventSources[internalId] = this._eventSource;
            let response;
            try {
                response = await upgrade();
            }
            catch (err) {
                fail('could not connect');
                return;
            }
            const redirectStatusCodes = [301, 302, 303, 307, 308];
            if (redirectStatusCodes.includes(response.status)) {
                nextTick(() => {
                    eventSource.readyState = EventSource.CLOSED;
                    eventSource.onerror(new Event('error'));
                });
                return;
            }
            if (response.ok) {
                if (response.headers['Content-Type'] === 'text/event-stream') {
                    nextTick(() => {
                        eventSource.readyState = EventSource.OPEN;
                        eventSource.onopen(new Event('open'));
                    });
                }
                else {
                    nextTick(() => {
                        eventSource.readyState = EventSource.CLOSED;
                        eventSource.onerror(new Event('error'));
                    });
                }
            }
            else {
                nextTick(() => {
                    eventSource.readyState = EventSource.CLOSED;
                    eventSource.onerror(new Event('error'));
                });
                return;
            }
        }
        else {
            try {
                const eventSource = new EventSource(url, opt);
                this._eventSource = eventSource;
                this._eventSource.onopen = () => {
                    emitter.emit('open', {});
                };
                this._eventSource.onmessage = (event) => {
                    const { data } = event;
                    emitter.emit('message', data);
                };
                this._eventSource.onerror = (event) => {
                    if (eventSource.readyState === EventSource.CONNECTING) {
                        emitter.emit('error', 'disconnected');
                        return;
                    }
                    emitter.emit('error', '');
                };
            }
            catch (err) {
                fail(err.message.toLowerCase());
                return;
            }
        }
        done({ emitter });
    }
    d() {
        if (this._eventSource) {
            this._eventSource.close();
            this._eventSource = null;
        }
    }
}
exports.default = EventSource_;
//# sourceMappingURL=index.js.map