import { __awaiter } from "tslib";
import { generateTimestampFilename } from './utils';
import { StorageMediaCapture } from '../screen/storage';
import { sendWebRTCFrame } from '../screen/utils';
/**
 * Статуси звітності виклику
 * @enum {string}
 */
export var CallReportingStatus;
(function (CallReportingStatus) {
    CallReportingStatus["Abandoned"] = "abandoned";
    CallReportingStatus["Cancel"] = "cancel";
    CallReportingStatus["Success"] = "success";
    CallReportingStatus["Failed"] = "failed";
    CallReportingStatus["Missed"] = "missed";
    CallReportingStatus["Timeout"] = "timeout";
    CallReportingStatus["Endless"] = "endless";
    CallReportingStatus["Transferred"] = "transferred";
})(CallReportingStatus || (CallReportingStatus = {}));
/**
 * Стани прослуховування
 * @enum {string}
 */
export var EavesdropState;
(function (EavesdropState) {
    EavesdropState["Muted"] = "muted";
    EavesdropState["Conference"] = "conference";
    EavesdropState["Prompt"] = "prompt";
})(EavesdropState || (EavesdropState = {}));
/**
 * Типи прослуховування
 * @enum {string}
 */
export var EavesdropType;
(function (EavesdropType) {
    EavesdropType["Joined"] = "joined";
    EavesdropType["Leave"] = "leave";
    EavesdropType["Hide"] = "hide";
})(EavesdropType || (EavesdropType = {}));
/**
 * Перерахування для дій дзвінка.
 * @enum {string}
 */
export var CallActions;
(function (CallActions) {
    /**
     * Дзвінок у режимі дзвінка (ringing).
     */
    CallActions["Ringing"] = "ringing";
    /**
     * Дзвінок у активному стані (active).
     */
    CallActions["Active"] = "active";
    /**
     * Дзвінок у режимі мосту (bridge).
     */
    CallActions["Bridge"] = "bridge";
    CallActions["Progress"] = "progress";
    /**
     * Дзвінок у режимі утримання (hold).
     */
    CallActions["Hold"] = "hold";
    /**
     * Дзвінок з DTMF (Dual-tone multi-frequency) сигналами.
     */
    CallActions["DTMF"] = "dtmf";
    /**
     * Голосовий дзвінок (voice).
     */
    CallActions["Voice"] = "voice";
    /**
     * Дзвінок у режимі тиші (silence).
     */
    CallActions["Silence"] = "silence";
    /**
     * Виконання програми або дії (execute).
     */
    CallActions["Execute"] = "execute";
    /**
     * Оновлення інформації про дзвінок (update).
     */
    CallActions["Update"] = "update";
    /**
     * Завершення дзвінка (hangup).
     */
    CallActions["Hangup"] = "hangup";
    /**
     * Перевірка стану дзвінка (heartbeat).
     */
    CallActions["Heartbeat"] = "heartbeat";
    /**
     * Надсилання звітності про дзвінок (reporting).
     */
    CallActions["Reporting"] = "reporting";
    /**
     * Надсилання потоків для співрозмовників (peerStream).
     */
    CallActions["PeerStream"] = "peerStream";
    /**
     * Надсилання локальних потоків (localStream).
     */
    CallActions["LocalStream"] = "localStream";
    /**
     * Знищення дзвінка (destroy).
     */
    CallActions["Destroy"] = "destroy";
    /**
     * Прослуховування дзвінка (eavesdrop).
     */
    CallActions["Eavesdrop"] = "eavesdrop";
    CallActions["Info"] = "info";
    CallActions["Stats"] = "stats";
})(CallActions || (CallActions = {}));
/**
 * Перерахування для напрямку дзвінка.
 * @enum {string}
 */
export var CallDirection;
(function (CallDirection) {
    /**
     * Вхідний дзвінок.
     */
    CallDirection["Inbound"] = "inbound";
    /**
     * Вихідний дзвінок.
     */
    CallDirection["Outbound"] = "outbound";
})(CallDirection || (CallDirection = {}));
export var VideoMediaFlow;
(function (VideoMediaFlow) {
    VideoMediaFlow["SendRecv"] = "sendrecv";
    VideoMediaFlow["SendOnly"] = "sendonly";
    VideoMediaFlow["RecvOnly"] = "recvonly";
    VideoMediaFlow["Inactive"] = "inactive";
    VideoMediaFlow["Disabled"] = "disabled";
})(VideoMediaFlow || (VideoMediaFlow = {}));
/**
 * Клас Call: Описує властивості і методи для роботи з дзвінком,
 * включаючи інформацію про його стан, учасників, медіа потоки, та інші атрибути.
 *
 * Конструктор Call:
 *  client: Клієнт, що керує дзвінком.
 *  e: Дані події дзвінка, які використовуються для ініціалізації властивостей класу.
 * В конструкторі здійснюється ініціалізація всіх властивостей класу на основі переданих даних
 * події дзвінка (e). Значення за замовчуванням задаються для необов'язкових полів,
 * якщо вони не присутні в об'єкті e.
 */
export class Call {
    /**
     * Конструктор класу Call.
     * @param client - Клієнт, що керує дзвінком.
     * @param e - Дані події дзвінка.
     */
    constructor(client, e) {
        this.client = client;
        // FIXME перевірити _muted з каналу
        const callInfo = e.data;
        this._muted = false;
        this._mutedVideo = false;
        this.voice = true;
        this.createdAt = +e.timestamp;
        this.task = null;
        this.data = null;
        this._eavesdrop = null;
        this._autoAnswerTimerId = null;
        this._activeCounter = 0;
        this.contact = null;
        this.notificationHangup = false;
        this._recordFile = null;
        this._recordCapture = null;
        this._userId = client.sessionInfo().user_id; // todo
        this.answeredAt = 0;
        this.hangupAt = 0;
        this.bridgedAt = 0;
        this.reportingAt = 0;
        this.autoAnswered = false;
        this.meetingId = null;
        this.hideNumber = callInfo.hide_number === true;
        this.peerStreams = [];
        this.localStreams = [];
        if (callInfo.eavesdrop) {
            this._eavesdrop = callInfo.eavesdrop;
        }
        this.originate = callInfo.originate || false;
        // fixme
        if (client.phone) {
            if (callInfo.sip_id) {
                this.setSip(client.phone.sipSessionBySipId(callInfo.sip_id));
            }
            else {
                this.setSip(client.phone.sipSessionByCallId(e.id));
            }
        }
        this.conversation = null;
        if (callInfo.meeting_id) {
            this.meetingId = callInfo.meeting_id;
        }
        this.params = {};
        this.id = e.id;
        this.digits = [];
        this.applications = [];
        this.appId = e.app_id;
        this.video = null;
        this.remoteVideo = null;
        this.setState(e);
        this.setInfo(callInfo);
        this.setVideo(callInfo);
        if (this.queue && this.client.agent) {
            this.task = this.client.agent.task.get(+this.queue.attempt_id) || null;
        }
    }
    /**
     * Встановлює стан дзвінка.
     * @param s - Дані події дзвінка.
     */
    setState(s) {
        this.state = s.event;
    }
    /**
     * Встановлює SIP-сесію.
     * @param sip - SIP-сесія.
     */
    setSip(sip) {
        if (sip && !this.sip) {
            this.sip = sip;
            this.localStreams = sip.getLocalMedia();
            this.peerStreams = sip.getPeerMedia();
        }
    }
    /**
     * Перевіряє, чи є ручний розподіл.
     * @returns Чи є ручний розподіл.
     */
    get manualDistribution() {
        return this.queue && this.queue.manual_distribution === 'true';
    }
    /**
     * Отримує тривалість дзвінка.
     * @returns Тривалість дзвінка в секундах.
     */
    get duration() {
        if (this.hangupAt === 0) {
            return Math.round((Date.now() - this.createdAt) / 1000); // tslint:disable-line
        }
        else {
            return Math.round((this.hangupAt - this.createdAt) / 1000); // tslint:disable-line
        }
    }
    /**
     * Перевіряє, чи дозволено DTMF.
     * @returns Чи дозволено DTMF.
     */
    get allowDtmf() {
        return this.answeredAt > 0 && this.allowHangup;
    }
    /**
     * Перевіряє, чи дозволено Transfer.
     * @returns Чи дозволено Transfer.
     */
    get allowTransfer() {
        return !(this.answeredAt === 0 && this.queue) && this.allowHangup;
    }
    /**
     * Перевіряє, чи дозволено завершення дзвінка.
     * @returns Чи дозволено завершення дзвінка.
     */
    get allowHangup() {
        return this.hangupAt === 0;
    }
    /**
     * Перевіряє, чи дозволено утримання дзвінка.
     * @returns Чи дозволено утримання дзвінка.
     */
    get allowHold() {
        return (this.hangupAt === 0 &&
            (this.state === 'active' || this.state === 'bridge'));
    }
    /**
     * Перевіряє, чи дозволено відповісти на дзвінок.
     * @returns Чи дозволено відповісти на дзвінок.
     */
    get allowAnswer() {
        return (this.client.phone &&
            this.hangupAt === 0 &&
            this.answeredAt === 0 &&
            !!(this.queue || this.direction === CallDirection.Inbound || this.params));
    }
    /**
     * Перевіряє, чи дозволено зняти утримання.
     * @returns Чи дозволено зняти утримання.
     */
    get allowUnHold() {
        return this.hangupAt === 0 && this.state === 'hold';
    }
    /**
     * Отримує комунікацію учасника.
     * @returns Комунікація учасника або null.
     */
    get memberCommunication() {
        if (!this.task) {
            return null;
        }
        else {
            return this.task.communication;
        }
    }
    /**
     * Перевіряє, чи є прослуховування.
     * @returns Чи є прослуховування.
     */
    get isEavesdrop() {
        return !!this._eavesdrop;
    }
    /**
     * Отримує ім'я прослуховування.
     * @returns Ім'я прослуховування.
     */
    get eavesdropName() {
        return this.isEavesdrop ? this._eavesdrop.name : '';
    }
    /**
     * Отримує номер прослуховування.
     * @returns Номер прослуховування.
     */
    get eavesdropNumber() {
        return this.isEavesdrop ? this._eavesdrop.number : '';
    }
    /**
     * Отримує тривалість прослуховування.
     * @returns Тривалість прослуховування.
     */
    get eavesdropDuration() {
        return this.isEavesdrop ? this._eavesdrop.duration : 0;
    }
    /**
     * Отримує стан прослуховування.
     * @returns Стан прослуховування або null.
     */
    get eavesdropState() {
        return this.isEavesdrop ? this._eavesdrop.state : null;
    }
    /**
     * Перевіряє, чи прослуховування в режимі мовчання.
     * @returns Чи прослуховування в режимі мовчання.
     */
    get eavesdropIsMuted() {
        return this.eavesdropState === EavesdropState.Muted;
    }
    /**
     * Перевіряє, чи прослуховування є конференцією.
     * @returns Чи прослуховування є конференцією.
     */
    get eavesdropIsConference() {
        return this.eavesdropState === EavesdropState.Conference;
    }
    /**
     * Перевіряє, чи прослуховування є запитом.
     * @returns Чи прослуховування є запитом.
     */
    get eavesdropIsPrompt() {
        return this.eavesdropState === EavesdropState.Prompt;
    }
    /**
     * Отримує ідентифікатор контакту.
     * @returns Ідентифікатор контакту або null.
     */
    get contactId() {
        return (this.contact && this.contact.id) || null;
    }
    /**
     * Перевіряє, чи контакт потрібно приховати.
     * @returns Чи контакт потрібно приховати.
     */
    get hideContact() {
        return this.contact && this.contact.hide;
    }
    /**
     * Отримує інформацію про учасника.
     * @param req - Запит інформації про учасника.
     * @returns Інформація про учасника.
     * @throws Помилка, якщо дзвінок не з виходу черги.
     */
    // todo
    getMember(req) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.isMember) {
                throw new Error(`call is not from outbound queue`);
            }
            return this.client.request(`cc_member_page`, {
                queue_id: this.task.queueId,
                member_id: this.task.memberId,
            });
        });
    }
    /**
     * Перевіряє, чи дзвінок є учасником.
     * @returns Чи дзвінок є учасником.
     */
    get isMember() {
        return !!(this.task && this.task.isMember);
    }
    /**
     * Перевіряє, чи перший активний дзвінок.
     * @returns Чи перший активний дзвінок.
     */
    get firstActive() {
        return this._activeCounter === 1;
    }
    get recordings() {
        return !!this._recordFile;
    }
    get allowRecordings() {
        return !this._recordFile && this.talking;
    }
    get talking() {
        return this.answeredAt > 0 && !this.hangupAt;
    }
    get hasVideo() {
        return this.remoteVideo === VideoMediaFlow.SendRecv;
    }
    /**
     * Встановлює активність дзвінка.
     * @param e - Дані події дзвінка.
     */
    setActive(e) {
        this._activeCounter++;
        if (this._autoAnswerTimerId) {
            clearTimeout(this._autoAnswerTimerId);
            this._autoAnswerTimerId = null;
        }
        if (!this.answeredAt) {
            if (this.direction === CallDirection.Inbound) {
                this.bridgedAt = +e.timestamp;
                if (this.parentId) {
                    this.bridgedId = this.parentId;
                }
            }
            this.answeredAt = +e.timestamp;
        }
        const isHold = this.isHold || this.firstActive;
        this.setState(e);
        this.setVideo(e.data);
        if (isHold && this.direction === CallDirection.Inbound) {
            this.trySendInfo(this.firstActive);
        }
    }
    /**
     * Встановлює інформацію про мосту.
     * @param s - Дані події мосту.
     */
    setBridged(s) {
        const bridged = s.data;
        if (!this.bridgedAt) {
            this.bridgedAt = +s.timestamp;
        }
        this.bridgedId = bridged.bridged_id;
        if (bridged.to) {
            if (this.direction === CallDirection.Inbound) {
                this.from = bridged.to;
            }
            else {
                this.to = bridged.to;
            }
        }
        this.bridgedId = bridged.bridged_id;
        if (bridged.payload) {
            this.variables = bridged.payload;
        }
        if (bridged.queue) {
            this.queue = bridged.queue;
        }
        this.setContactData(bridged);
        this.setVideo(bridged);
    }
    /**
     * Встановлює інформацію про утримання.
     * @param e - Дані події утримання.
     */
    setHold(e) {
        this.setState(e);
        this.trySendInfo();
    }
    /**
     * Встановлює ідентифікатор контакту.
     * @param id - Ідентифікатор контакту.
     */
    setContactId(id) {
        if (!this.contact) {
            this.contact = {
                hide: false,
                id,
            };
        }
        else {
            this.contact.id = id;
        }
    }
    /**
     * Встановлює інформацію про дзвінок.
     * @param s - Інформація про дзвінок.
     */
    setInfo(s) {
        this.parentId = s.parent_id;
        this.destination = s.destination;
        this.direction = s.direction;
        this.from = s.from;
        this.to = s.to;
        this.variables = s.payload;
        this.queue = s.queue || null;
        this.sipId = s.sip_id || null;
        this.params = s.params;
        this.setContactData(s);
    }
    /**
     * Встановлює потоки для співрозмовників.
     * @param streams - Потоки для співрозмовників.
     */
    setPeerStreams(streams) {
        if (!streams) {
            this.peerStreams = [];
        }
        else {
            this.peerStreams = streams;
        }
    }
    /**
     * Встановлює локальні потоки.
     * @param streams - Локальні потоки.
     */
    setLocalStreams(streams) {
        if (!streams) {
            this.localStreams = [];
        }
        else {
            this.localStreams = streams;
        }
    }
    /**
     * Увімкнути голос.
     */
    setVoice() {
        this.voice = true;
    }
    /**
     * Вимкнути голос.
     */
    setSilence() {
        this.voice = false;
    }
    /**
     * Додає виконання програми.
     * @param s - Дані події виконання.
     */
    setExecute(s) {
        this.applications.push(s.application);
    }
    /**
     * Додає DTMF.
     * @param s - Дані події DTMF.
     */
    addDigit(s) {
        this.digits.push(s.digit);
    }
    /**
     * Встановлює стан прослуховування.
     * @param e - Дані події прослуховування.
     */
    setEavesdropState(e) {
        if (e.type === EavesdropType.Joined) {
            this._eavesdrop = e;
        }
        else if (e.type === EavesdropType.Leave) {
            this._eavesdrop = null;
        }
        else {
            this._eavesdrop.state = e.state;
        }
    }
    /**
     * Встановлює інформацію про завершення дзвінка.
     * @param s - Дані події завершення дзвінка.
     */
    setHangup(s) {
        const hangup = s.data;
        this.hangupAt = +s.timestamp;
        this.hangupCause = hangup.cause;
        this.hangupSipCode = hangup.sip;
        this.notificationHangup = hangup.notification_hangup || false;
        this.voice = false;
        this.peerStreams = [];
        if (+hangup.reporting_at) {
            this.reportingAt = +hangup.reporting_at; // FIXME тип number
        }
        if (this._recordFile) {
            this.stopRecord();
        }
        this.setState(s);
    }
    /**
     * Перевіряє, чи дозволена звітність.
     * @returns Чи дозволена звітність.
     */
    get allowReporting() {
        const autoAnswer = this.params && this.params.autoAnswer;
        const isAutoAnswerTrue = autoAnswer === true || autoAnswer === 'true';
        return this.hasReporting && (this.answeredAt > 0 || isAutoAnswerTrue);
    }
    /**
     * Перевіряє, чи є звітність.
     * @returns Чи є звітність.
     */
    get hasReporting() {
        if (this.task) {
            return this.task.hasReporting;
        }
        return false;
    }
    /**
     * Отримує відображення дзвінка.
     * @returns Відображення дзвінка.
     */
    get display() {
        return `${this.displayNumber} (${this.displayName})`;
    }
    /**
     * Перевіряє, чи вимкнений звук.
     * @returns Чи вимкнений звук.
     */
    get muted() {
        return this._muted;
    }
    /**
     * Перевіряє, чи дзвінок перебуває в режимі утримання.
     * @returns Чи дзвінок перебуває в режимі утримання.
     */
    get isHold() {
        return this.state === CallActions.Hold;
    }
    /**
     * Перевіряє, чи дозволено відео для вхідних дзвінків.
     * @returns Чи дозволено відео для вхідних дзвінків.
     */
    get allowInboundVideo() {
        if (this.params) {
            return this.params.video || false;
        }
        return false;
    }
    /**
     * Перевіряє, чи дозволено відео для вихідних дзвінків.
     * @returns Чи дозволено відео для вихідних дзвінків.
     */
    get allowOutboundVideo() {
        if (this.params) {
            return this.params.video || false;
        }
        return false;
    }
    /**
     * Перевіряє, чи дзвінок активний.
     * @returns Чи дзвінок активний.
     */
    get active() {
        return this.hangupAt === 0;
    }
    /**
     * Отримує номер для відображення.
     * @returns Номер для відображення.
     */
    get displayNumber() {
        if (this.direction === 'inbound') {
            return this.from.number;
        }
        else {
            if (this.to) {
                return this.to.number;
            }
            return this.destination;
        }
    }
    get _displayNameValue() {
        if (this.direction === 'inbound') {
            return this.from.name;
        }
        else {
            if (this.to) {
                return this.to.name;
            }
            return this.destination;
        }
    }
    /**
     * Отримує ім'я для відображення.
     * @returns Ім'я для відображення.
     */
    get displayName() {
        const name = this._displayNameValue;
        // todo, bug fs
        if (name === 'Outbound Call' || name === this.displayNumber) {
            return '';
        }
        return name;
    }
    /**
     * Перевіряє, чи дозволено автоматичне відповідання.
     * @returns Чи дозволено автоматичне відповідання.
     */
    get autoAnswer() {
        return ((this.queue && this.queue.queue_type === 'offline') ||
            this.autoAnswerDelay > 0);
    }
    /**
     * Отримує затримку автоматичного відповідання.
     * @returns Затримка автоматичного відповідання.
     */
    get autoAnswerDelay() {
        if (!this.params ||
            !this.params.autoAnswer ||
            `${this.params.autoAnswer}` === 'false') {
            return 0;
        }
        else if (isFinite(+this.params.autoAnswer)) {
            return +this.params.autoAnswer;
        }
        return this.client.autoAnswerDelayTime;
    }
    // todo task is deprecated
    /**
     * Отримує спробу.
     * @returns Спроба.
     */
    get attempt() {
        return this.task;
    }
    /* Call control */
    /**
     * Відповідає на дзвінок.
     * @param req - Запит на відповідання.
     * @returns Чи успішно відповіли.
     */
    answer(req) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.sip && this.client.phone) {
                try {
                    const params = yield this.client.phone.callOption(req);
                    yield this.sip.answer(params);
                }
                catch (e) {
                    this.client.handleError(e);
                }
                return true;
            }
            return false;
        });
    }
    /**
     * Затримка автоматичного відповідання.
     * @param req - Запит на відповідання.
     */
    answerDelay(req) {
        if (this.autoAnswered) {
            return;
        }
        if (this._autoAnswerTimerId) {
            clearTimeout(this._autoAnswerTimerId);
        }
        this._autoAnswerTimerId = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
            if (this.autoAnswered) {
                return;
            }
            this.autoAnswered = true;
            this.autoAnswered = yield this.answer(req);
        }), this.autoAnswerDelay);
    }
    /**
     * Завершує дзвінок.
     * @param cause - Причина завершення.
     * @returns Результат завершення дзвінка.
     */
    hangup(cause) {
        return __awaiter(this, void 0, void 0, function* () {
            let _cause = cause;
            if (this.answeredAt === 0 && !cause) {
                _cause =
                    this.direction === CallDirection.Inbound
                        ? 'USER_BUSY'
                        : 'ORIGINATOR_CANCEL';
            }
            return this.client.request('call_hangup', {
                id: this.id,
                app_id: this.appId,
                cause: _cause,
            });
        });
    }
    /**
     * Запускає прослуховування дзвінка.
     * @param req - Запит на прослуховування.
     * @returns Результат прослуховування.
     */
    eavesdrop(req) {
        return __awaiter(this, void 0, void 0, function* () {
            req.id = this.id;
            return this.client.request('call_eavesdrop', req);
        });
    }
    /**
     * Змінює стан прослуховування.
     * @param state - Новий стан прослуховування.
     * @returns Результат зміни стану прослуховування.
     */
    changeEavesdropState(state) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.isEavesdrop) {
                throw new Error(`this call not in eavesdrop`);
            }
            if (this.eavesdropState === state) {
                throw new Error(`this call already eavesdrop state: ${state}`);
            }
            return this.client.request('call_eavesdrop_state', {
                id: this.id,
                state,
            });
        });
    }
    /**
     * Перемикає утримання дзвінка.
     * @returns Результат утримання дзвінка.
     */
    toggleHold() {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.state === CallActions.Hold) {
                return this.unHold();
            }
            else {
                return this.hold();
            }
        });
    }
    /**
     * Утримує дзвінок.
     * @returns Результат утримання дзвінка.
     */
    hold() {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.state === CallActions.Hold) {
                throw new Error('Call is hold');
            }
            return this.client.request('call_hold', {
                id: this.id,
                app_id: this.appId,
            });
        });
    }
    /**
     * Виймає дзвінок з утримання.
     * @returns Результат виймання дзвінка з утримання.
     */
    unHold() {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.state !== CallActions.Hold) {
                throw new Error('Call is active');
            }
            return this.client.request('call_unhold', {
                id: this.id,
                app_id: this.appId,
            });
        });
    }
    /**
     * Надсилає DTMF.
     * @param dtmf - DTMF.
     * @returns Результат надсилання DTMF.
     */
    sendDTMF(dtmf) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.client.request('call_dtmf', {
                id: this.id,
                app_id: this.appId,
                dtmf,
            });
        });
    }
    /**
     * Виконує сліпий переказ дзвінка.
     * @param destination - Місце призначення.
     * @param variables - Змінні.
     * @returns Результат переказу.
     */
    blindTransfer(destination, variables) {
        return __awaiter(this, void 0, void 0, function* () {
            if (variables) {
                return this.client.request('call_blind_transfer_ext', {
                    id: this.id,
                    app_id: this.appId,
                    destination,
                    variables,
                });
            }
            // todo deprecated
            return this.client.request('call_blind_transfer', {
                id: this.id,
                app_id: this.appId,
                destination,
            });
        });
    }
    /**
     * Вимикає або включає мікрофон.
     * @param mute - Якщо true, вимикає мікрофон; якщо false, включає мікрофон.
     * @returns Результат вимикання або включення мікрофона.
     */
    mute(mute = false) {
        return __awaiter(this, void 0, void 0, function* () {
            const res = yield this.client.request('call_mute', {
                id: this.id,
                app_id: this.appId,
                mute,
            });
            this._muted = mute;
            this.trySendInfo();
            return res;
        });
    }
    /*
    TODO
     */
    muteVideo(mute = true) {
        return __awaiter(this, void 0, void 0, function* () {
            let changed = false;
            (this.localStreams || []).forEach((localStream) => {
                localStream.getVideoTracks().forEach((track) => {
                    if (track.enabled !== !mute) {
                        changed = true;
                        track.enabled = !mute;
                    }
                    this._mutedVideo = mute;
                });
            });
            if (changed) {
                this.trySendInfo();
            }
        });
    }
    trySendInfo(syncRequested) {
        if (this.sip && this.sip.setMediaConfig) {
            const req = {
                videoMuted: this.mutedVideo,
                audioMuted: this.muted,
                hold: this.isHold,
            };
            if (syncRequested) {
                req.syncRequested = true;
            }
            this.sip.setMediaConfig(req);
        }
    }
    get mutedVideo() {
        return this._mutedVideo;
    }
    get remoteVideoMuted() {
        return this.sip && !!this.sip.remoteVideoMuted;
    }
    get remoteAudioMuted() {
        return this.sip && !!this.sip.remoteAudioMuted;
    }
    get remoteHold() {
        return this.sip && !!this.sip.remoteHold;
    }
    get allowRecordCall() {
        return this.talking;
    }
    /**
     * Створює міст між дзвінками.
     * @param call - Дзвінок, з яким створюється міст.
     * @param variables - Змінні.
     * @returns Результат створення мосту.
     */
    bridgeTo(call, variables) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.task) {
                yield this.task.saveForm(null, null);
            }
            if (call.task) {
                yield call.task.saveForm(null, null);
            }
            return this.client.request('call_bridge', {
                from_id: this.id,
                from_app_id: this.appId,
                to_id: call.id,
                to_app_id: call.appId,
                variables,
            });
        });
    }
    /**
     * Надсилає звітність про дзвінок.
     * @param reporting - Дані звітності.
     * @returns Результат надсилання звітності.
     */
    reporting(reporting) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.task) {
                throw new Error(`this call not in queue`);
            }
            return this.task.reporting(reporting);
        });
    }
    /**
     * Оновлює розмову.
     * @param sec - Кількість секунд.
     * @returns Результат оновлення розмови.
     */
    renew(sec) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.task) {
                throw new Error(`this conversation not in queue`);
            }
            return this.task.renew(sec);
        });
    }
    /**
     * Робить запрошення користувача.
     * @param req - Запит на запрошення.
     * @returns Результат запрошення.
     */
    callToUser(req) {
        return __awaiter(this, void 0, void 0, function* () {
            req.nodeId = this.appId;
            req.parentCallId = this.id || null;
            req.sendToCallId = this.parentId || null;
            return this.client.inviteToUser(req);
        });
    }
    /**
     * Встановлює контакт для дзвінка.
     * @param contactId - Ідентифікатор контакту.
     * @returns Результат встановлення контакту.
     */
    setContact(contactId) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.client.request(`call_set_contact`, {
                id: this.id,
                contact_id: contactId,
            });
        });
    }
    processTransferAgent(agentId, params) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.client.request(`call_to_queue`, {
                parent_id: this.id,
                agent_id: agentId,
                params,
            });
        });
    }
    processTransferQueue(queueId, params) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.client.request(`call_to_queue`, {
                parent_id: this.id,
                queue_id: queueId,
                params,
            });
        });
    }
    blindTransferQueue(queueId) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.client.request(`call_bt_queue`, {
                id: this.id,
                queue_id: queueId,
            });
        });
    }
    startRecordNative(name) {
        return __awaiter(this, void 0, void 0, function* () {
            let fileName = name;
            let ext = 'mp3';
            if (this._recordFile) {
                throw new Error('Call already recording');
            }
            if (this.hasVideo) {
                ext = 'mp4';
            }
            if (!fileName) {
                fileName = `recording_vc_${this._userId}_${generateTimestampFilename()}.${ext}`;
            }
            yield this.client.request('call_start_rec', {
                id: this.parentId || this.id,
                name: fileName,
                video: this.video === VideoMediaFlow.SendRecv,
            });
            this._recordFile = fileName;
        });
    }
    stopRecordNative() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this._recordFile) {
                throw new Error('Call not recording');
            }
            yield this.client.request('call_stop_rec', {
                id: this.parentId || this.id,
                name: this._recordFile,
                video: this.video === VideoMediaFlow.SendRecv,
            });
            this._recordFile = null;
        });
    }
    startRecord(name) {
        return __awaiter(this, void 0, void 0, function* () {
            let fileName = name;
            let ext = 'mp3';
            if (!this.peerStreams.length) {
                return;
            }
            if (this.hasVideo) {
                ext = 'mp4';
            }
            if (!fileName) {
                fileName = `recording_vc_${this._userId}_${generateTimestampFilename()}.${ext}`;
            }
            const media = new Array();
            this.peerStreams.forEach((stream) => {
                media.push(stream.clone());
            });
            this.localStreams.forEach((stream) => {
                media.push(stream.clone());
            });
            try {
                const capture = new StorageMediaCapture(this.parentId || this.id, fileName, media, [], this.client.basePath, this.client.sessionInfo().token);
                // TODO
                capture.on('close', () => {
                    this._recordFile = null;
                    this._recordCapture = null;
                });
                yield capture.cast();
                this._recordCapture = capture;
                this._recordFile = fileName;
            }
            catch (e) {
                media.length = 0; // TODO
                throw e;
            }
        });
    }
    stopRecord() {
        if (!this._recordFile) {
            throw new Error('Call not recording');
        }
        if (this._recordCapture) {
            this._recordCapture.close();
        }
        this._recordFile = null;
        this._recordCapture = null;
    }
    screenshot(name) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.peerStreams.length) {
                const imgTrack = this.peerStreams[0].getVideoTracks()[0];
                if (!imgTrack) {
                    throw new Error('No video');
                }
                let fileName = name;
                if (!fileName) {
                    fileName = `screenshot_vc_${this._userId}_${generateTimestampFilename()}.png`;
                }
                return sendWebRTCFrame(this.peerStreams[0].clone(), fileName, this.client.basePath, this.parentId || this.id, this.client.sessionInfo().token);
            }
        });
    }
    /**
     * Встановлює дані контакту.
     * @param e - Дані події контакту.
     */
    setContactData(e) {
        this.contact = {
            id: e.contact_id || null,
            hide: e.hide_contact || false,
        };
    }
    setVideo(s) {
        if (!s) {
            return;
        }
        this.video = s.video || null;
        if (this.meetingId) {
            this.remoteVideo = VideoMediaFlow.SendRecv; // TODO, park variable
        }
        else {
            this.remoteVideo = s.remote_video || VideoMediaFlow.Inactive;
        }
    }
}
//# sourceMappingURL=call.js.map