import { ChannelType } from './agent';
/**
 * Перелік станів завдання.
 * @enum {string}
 */
export var JobState;
(function (JobState) {
    /**
     * Стан завдання - розподіл.
     */
    JobState["Distribute"] = "distribute";
    /**
     * Стан завдання - пропозиція.
     */
    JobState["Offering"] = "offering";
    /**
     * Стан завдання - з'єднано.
     */
    JobState["Bridged"] = "bridged";
    /**
     * Стан завдання - пропущено.
     */
    JobState["Missed"] = "missed";
    /**
     * Стан завдання - обробка.
     */
    JobState["Processing"] = "processing";
    /**
     * Стан завдання - закрито.
     */
    JobState["Closed"] = "closed";
    /**
     * Стан завдання - знищено.
     */
    JobState["Destroy"] = "destroy";
})(JobState || (JobState = {}));
/**
 * Перелік назв каналів.
 * @enum {string}
 */
export var ChannelName;
(function (ChannelName) {
    /**
     * Назва каналу - дзвінок.
     */
    ChannelName["Call"] = "call";
    /**
     * Назва каналу - вихідний дзвінок.
     */
    ChannelName["OutCall"] = "out_call";
    /**
     * Назва каналу - чат.
     */
    ChannelName["Chat"] = "chat";
    /**
     * Назва каналу - завдання.
     */
    ChannelName["Task"] = "task";
})(ChannelName || (ChannelName = {}));
export class Task {
    /**
     * Конструктор класу.
     * @param {Client} client - Клієнт.
     * @param {ChannelEvent} e - Подія каналу.
     * @param {Distribute} distribute - Інформація про розподіл.
     */
    constructor(client, e, distribute) {
        this.client = client;
        this.distribute = distribute;
        this.id = e.attempt_id;
        this.state = JobState.Offering;
        this.setState(e.status);
        this.lastStatusChange = e.timestamp;
        this.createdAt = e.timestamp;
        this._processing = null;
        this.offeringAt = 0;
        this.answeredAt = 0;
        this.bridgedAt = 0;
        this.reportedAt = 0;
        this.startProcessingAt = 0;
        this.stopAt = 0;
        this.closedAt = 0;
        this.form = null;
        this.autoAnswered = false;
        this._autoAnswerParam = false;
        this._autoAnswerTimerId = null;
        this.communication = distribute.communication;
        this.history = [distribute];
    }
    /**
     * Отримати чергу завдання.
     * @returns {Queue}
     */
    get queue() {
        return {
            id: this.distribute.queue_id,
            name: this.distribute.queue_name,
        };
    }
    /**
     * Отримати тривалість завдання в секундах.
     * @returns {number}
     */
    get duration() {
        return Math.round((Date.now() - this.lastStatusChange) / 1000);
    }
    /**
     * Чи є форма.
     * @returns {boolean}
     */
    get hasForm() {
        return this.distribute.has_form || false;
    }
    /**
     * Отримати канал.
     * @returns {string}
     */
    get channel() {
        return this.distribute.channel;
    }
    /**
     * Чи дозволено прийняття завдання.
     * @returns {boolean}
     */
    get allowAccept() {
        return (this.channel === ChannelName.Task &&
            (this.bridgedAt === 0 && this.closedAt === 0));
    }
    /**
     * Чи дозволено відхилення завдання.
     * @returns {boolean}
     */
    get allowDecline() {
        return this.allowAccept;
    }
    /**
     * Чи дозволено закриття завдання.
     * @returns {boolean}
     */
    get allowClose() {
        return (this.channel === ChannelName.Task &&
            this.closedAt === 0 &&
            this.bridgedAt > 0);
    }
    /**
     * Отримати ідентифікатор учасника.
     * @returns {number}
     */
    get memberId() {
        return this.distribute.member_id;
    }
    /**
     * Отримати ідентифікатор черги.
     * @returns {number}
     */
    get queueId() {
        return this.distribute.queue_id;
    }
    /**
     * Чи є звітність.
     * @returns {boolean}
     */
    get hasReporting() {
        return this.distribute.has_reporting;
    }
    /**
     * Чи дозволено звітування.
     * @returns {boolean}
     */
    get allowReporting() {
        return this.hasReporting && this.bridgedAt > 0;
    }
    /**
     * Отримати ідентифікатор каналу агента.
     * @returns {string}
     */
    get agentChannelId() {
        return this.distribute.agent_channel_id;
    }
    /**
     * Встановити стан завдання.
     * @param {string} state - Стан завдання.
     * @todo
     */
    setState(state) {
        this.state = state;
    }
    setForm(form) {
        this.form = form;
        if (!this.allowReporting) {
            this.distribute.has_form = true;
            this.distribute.has_reporting = true;
        }
    }
    /**
     * Встановити час відповіді.
     * @param {number} t - Час відповіді.
     */
    setAnswered(t) {
        this.answeredAt = t;
        this.lastStatusChange = Date.now();
        if (this._autoAnswerTimerId) {
            clearTimeout(this._autoAnswerTimerId);
            this._autoAnswerTimerId = null;
        }
    }
    /**
     * Встановити пропозицію.
     * @param {OfferingEvent} e - Подія пропозиції.
     */
    setOffering(e) {
        this.offeringAt = e.timestamp;
        if (e.offering.auto_answer &&
            (this.channel === ChannelType.Job || this.channel === ChannelType.IM)) {
            this._autoAnswerParam = e.offering.auto_answer;
            this.acceptDelay().catch((err) => {
                this.client.emit('error', err);
            });
        }
    }
    /**
     * Встановити з'єднання.
     * @param {BridgedEvent} e - Подія з'єднання.
     */
    setBridged(e) {
        this.bridgedAt = e.timestamp;
        this.lastStatusChange = Date.now();
        if (e.form) {
            this.form = e.form;
        }
        if (this._autoAnswerTimerId) {
            clearTimeout(this._autoAnswerTimerId);
            this._autoAnswerTimerId = null;
        }
    }
    /**
     * Встановити обробку.
     * @param {number} now - Час обробки.
     * @param {Processing} p - Інформація про обробку.
     */
    setProcessing(now, p) {
        this.state = JobState.Processing;
        this.closedAt = now;
        if (!this.startProcessingAt) {
            this.startProcessingAt = Date.now();
        }
        if (p.sec && !p.timeout) {
            p.timeout = Date.now() + p.sec * 1000; // bug
        }
        this._processing = p;
    }
    /**
     * Встановити закриття завдання.
     * @param {number} now - Час закриття.
     */
    setClosed(now) {
        this.stopAt = now;
        this.state = JobState.Closed;
    }
    /**
     * Встановити новий розподіл.
     * @param {Distribute} d - Інформація про новий розподіл.
     */
    setTransferred(d, f) {
        this.distribute = d;
        this.history.push(d);
        this.form = f || null;
    }
    /**
     * Встановити пропущене завдання.
     */
    setMissed() {
        this.state = JobState.Missed;
    }
    /**
     * Отримати час тайм-ауту обробки.
     * @returns {number | null}
     */
    get processingTimeoutAt() {
        if (!this._processing || !this._processing.timeout) {
            return null;
        }
        return this._processing.timeout;
    }
    /**
     * Отримати тривалість обробки в секундах.
     * @returns {number | null}
     */
    get processingSec() {
        if (!this._processing || !this._processing.sec) {
            return null;
        }
        return this._processing.sec;
    }
    /**
     * Отримати спробу.
     * @returns {Task}
     */
    get attempt() {
        return this;
    }
    /**
     * Отримати змінні завдання.
     * @returns {object}
     */
    get variables() {
        const res = {};
        for (const k in this.distribute.variables) {
            if (k.startsWith('cc_')) {
                continue;
            }
            res[k] = this.distribute.variables[k];
        }
        return res;
    }
    /**
     * Чи є учасник.
     * @returns {boolean}
     */
    get isMember() {
        return !!this.memberId;
    }
    /**
     * Отримати номер для відображення.
     * @returns {string}
     */
    get displayNumber() {
        return this.communication.destination;
    }
    /**
     * Отримати ім'я для відображення.
     * @returns {string | null}
     */
    get displayName() {
        return this.distribute.member_name || null;
    }
    /**
     * Отримати відображення (ім'я та номер).
     * @returns {string}
     */
    get display() {
        return `${this.displayName} (${this.displayNumber})`;
    }
    /**
     * Отримати тривалість оновлення в секундах.
     * @returns {number | null}
     */
    get renewalSec() {
        if (!this._processing || !this._processing.renewal_sec) {
            return null;
        }
        return this._processing.renewal_sec;
    }
    /**
     * Чи є автоматичний прийом.
     * @returns {boolean}
     */
    get autoAnswer() {
        return this.autoAnswerDelay > 0;
    }
    /**
     * Отримати затримку автоматичного прийому.
     * @returns {number}
     */
    get autoAnswerDelay() {
        if (!this._autoAnswerParam || `${this._autoAnswerParam}` === 'false') {
            return 0;
        }
        else if (isFinite(+this._autoAnswerParam)) {
            return +this._autoAnswerParam;
        }
        return this.client.autoAnswerDelayTime;
    }
    /**
     * Прийняти завдання.
     * @returns {Promise<any>}
     */
    async accept() {
        return this.client.request(`cc_agent_task_accept`, {
            agent_id: this.distribute.agent_id,
            attempt_id: this.id,
            app_id: this.distribute.app_id,
        });
    }
    /**
     * Автоматично прийняти завдання із затримкою.
     * @returns {Promise<void>}
     */
    async acceptDelay() {
        this._autoAnswerTimerId = setTimeout(async () => {
            if (this.autoAnswered) {
                return;
            }
            if (!this.answeredAt) {
                this.autoAnswered = true;
                await this.accept();
            }
        }, this.autoAnswerDelay);
    }
    /**
     * Закрити завдання.
     * @returns {Promise<any>}
     */
    async close() {
        return this.client.request(`cc_agent_task_close`, {
            agent_id: this.distribute.agent_id,
            attempt_id: this.id,
            app_id: this.distribute.app_id,
        });
    }
    /**
     * Відхилити завдання.
     * @returns {Promise<any>}
     */
    async decline() {
        return this.client.request(`cc_agent_task_close`, {
            agent_id: this.distribute.agent_id,
            attempt_id: this.id,
            app_id: this.distribute.app_id,
        });
    }
    /**
     * Звітувати про завдання.
     * @param {Reporting} reporting - Дані звітності.
     * @returns {Promise<any>}
     */
    async reporting(reporting) {
        const res = await this.client.request('cc_reporting', {
            attempt_id: this.id,
            ...reporting,
        });
        this.reportedAt = Date.now();
        return res;
    }
    /**
     * Оновити завдання.
     * @param {number} [sec] - Кількість секунд для оновлення.
     * @returns {Promise<any>}
     */
    async renew(sec) {
        return this.client.request('cc_renewal', {
            attempt_id: this.id,
            renewal_sec: sec ? sec : this.processingSec,
        });
    }
    /**
     * Виконати дію з формою.
     * @param {string} action - Дія, яку потрібно виконати.
     * @param {Map<string, string | number | object | any[]>} fields - Поля форми.
     * @returns {Promise<any>}
     * @throws {Error} Якщо активна форма не знайдена.
     */
    async formAction(action, fields) {
        if (!this.form) {
            throw new Error('not found active form');
        }
        return this.client.request('cc_form_action', {
            attempt_id: this.id,
            app_id: this.distribute.app_id,
            action,
            fields: formFields(fields || this.form.fields),
        });
    }
    async saveForm(form, fields) {
        if (!this.form) {
            return;
        }
        return this.client.request('cc_form_save', {
            attempt_id: this.id,
            app_id: this.distribute.app_id,
            fields: formFields(fields || this.form.fields),
            form: form || this.form,
        });
    }
    async componentAction(componentId, action, vars, sync) {
        if (!this.form) {
            throw new Error('no form');
        }
        return this.client.request('cc_component_action', {
            attempt_id: this.id,
            app_id: this.distribute.app_id,
            action,
            componentId,
            vars: formFields(vars),
            formId: this.form.id,
            sync: !!sync,
        });
    }
}
function formFields(fields) {
    const res = {};
    if (!fields)
        return res;
    for (const [key, value] of Object.entries(fields)) {
        if (typeof value === 'object') {
            ;
            res[key] = JSON.stringify(value);
        }
        else {
            ;
            res[key] = value;
        }
    }
    return res;
}
//# sourceMappingURL=task.js.map