'use strict';

let selectedRecord = null;
let selectedElem = null;

const prettifyThing = (name, value, record = null, globalParms = null) => {
    if (name === 'source' || name === 'destination' || name === 'any') {
        return common.prettifyPhone(value);
    } else if (name === 'totalDuration' || name === 'callDuration') {
        return (globalParms.timeInSeconds ? value : common.convertToDuration(value));
    } else if (name === 'dateStart' || name === 'dateEnd') {
        return dayjs(value).format('DD.MM.YYYY');
    } else if (name === 'callDate') {
        return (globalParms.disableGrouping ? dayjs(value).format('DD.MM.YYYY HH:mm:ss') : dayjs(value).format('HH:mm:ss'));
    } else if (name === 'callResult') {
        return ['Отвечен', 'Не отвечен', 'Занято', 'Ошибка', 'Другое', 'Отменен'][value];
    } else if (name === 'dailyCT') {
        return ['ВХ', 'ИСХ', 'ВН'][record.callType] + '-' + value;
    }
    return value;
};

const uglifyThing = (name, value) => {
    if (name === 'source' || name === 'destination' || name === 'any') {
        return common.uglifyPhone(value);
    } else if (name === 'dateStart' || name === 'dateEnd') {
        return value.replace(/(\d{1,2})\.(\d{1,2})\.(\d+)/, '$3-$2-$1');
    } else if (name === 'dailyID' || name === 'dailyCT' || name === 'id') {
        return value.replace(/\D/g, '');
    }
    return value;
};

const preferableSortDirs = {
    callDate: 'desc',
    source: 'asc', destination: 'asc',
    totalDuration: 'desc', callDuration: 'desc'
};

const filterProperties = ['source', 'destination', 'any', 'dateStart', 'dateEnd', 'id', 'callTypes', 'wcSource', 'wcDestination', 'wcAny'];
const sortProperties = ['sort', 'dir'];

const getCdrParams = () => {
    let parms = {};

    // specify page if its not the 1st one
    if (cdr.thisPage !== 1) { parms.page = cdr.thisPage; }

    // iterate over all known SORT and FILTER properties, add them if necessary
    [...sortProperties, ...filterProperties].forEach(e => {
        if (cdr.filter[e]) {
            parms[e] = uglifyThing(e, cdr.filter[e]);
        }
    });

    // remove default sort options
    if (parms.sort === 'callDate' && parms.dir === 'desc') {
        delete parms.sort;
        delete parms.dir;
    }

    // check if grouping is disabled
    if (document.querySelector('.left-panel .settings .checkbox.grouping > input').checked) {
        parms.disableGrouping = 1;
    }

    return Object.keys(parms).map(e => e + '=' + parms[e]);
};

const getCdr = async () => {
    try {
        let url = [...getCdrParams()].join('&');
        url = url ? ('?' + url) : '/';

        // update browser url
        if (history.pushState) {
            history.pushState({}, null, url);
        }

        const response = await fetch('/api/query' + url);
        if (!response.ok) {
            throw new Error(response.status, ' ', response.statusText);
        }

        return (await response.json());
    } catch (e) {
        showMessage({
            icon: 'icon-error',
            header: 'Ошибка загрузки данных',
            text: 'Не удалось загрузить данные: ' + e
        });
        console.warn('Failed to fetch data: ', e)
        return null;
    }
};


const getCallsSinceLastUpdate = async () => {
    try {
        if (cdr && cdr.latest) {
            const response = await fetch('/api/check-new?lastUpdateAt=' + dayjs(cdr.latest).unix());
            if (response.ok) {
                return (await response.json()).numSinceLastUpdate;
            }
        }
    } catch (e) {
        console.warn('Failed to query last update API: ' + e);
    }
};


const performUpdate = async () => {
    const count = await getCallsSinceLastUpdate();
    if (count > 0) {
        if (document.querySelector('.left-panel .settings .checkbox.auto-update > input').checked) {
            document.querySelector('.left-panel .new-entries').classList.remove('active');
            populate();
        } else {
            document.querySelector('.left-panel .new-entries .num').innerHTML = count;
            document.querySelector('.left-panel .new-entries').classList.add('active');
        }
    }

    updateTimerHandle = setTimeout(performUpdate, 5000);
};


let updateTimerHandle = 0;

const handlerDoUpdate = (ev, el) => {
    clearTimeout(updateTimerHandle);
    updateTimerHandle = setTimeout(performUpdate, 5000);
    document.querySelector('.left-panel .new-entries').classList.remove('active');
    populate();
};





const columnNameToId = name => {
    switch (name) {
        case 'dailyid': { return 'dailyID'; }
        case 'dailyct': { return 'dailyCT'; }
        case 'date': { return 'callDate'; }
        case 'result': { return 'callResult'; }
        case 'total-duration': { return 'totalDuration'; }
        case 'call-duration': { return 'callDuration'; }
        case 'id': { return 'uniqueID'; }
        default: { return name; }
    }
};

const addInfoToGroup = (group, cd, gp) => {
    const element = cdr.dailyStats.find( e => dayjs(e.day).isSame(cd, 'day'));

    if (element) {
        const stats = document.createElement('div');
        stats.classList.add('stats');

        const phone = createSVG(['image'], 'icon-phone');
        const numCalls = document.createElement('span');
        numCalls.classList.add('num-calls');
        numCalls.innerHTML = element.totalCalls;

        const clock = createSVG(['image'], 'icon-clock');
        const duration = document.createElement('span');
        duration.innerHTML = prettifyThing('totalDuration', element.totalDuration, null, gp)
            + ' / ' + prettifyThing('callDuration', element.callDuration, null, gp);

        stats.appendChild(phone); stats.appendChild(numCalls);
        stats.appendChild(clock); stats.appendChild(duration);
        group.appendChild(stats);
    }
}

const tryNewGroup = (id, cdrBody, gp) => {
    if (id === 0 || !dayjs(cdr.records[id - 1].callDate).isSame(dayjs(cdr.records[id].callDate), 'day')) {
        const group = document.createElement('div');
        group.classList.add('entry', 'group');

        const groupText = document.createElement('span');
        groupText.classList.add('group-text');
        groupText.innerHTML = dayjs(cdr.records[id].callDate).format('DD.MM.YYYY');

        if (cdr.isFirstCont && id === 0) {
            groupText.innerHTML += ' (продолжение)';
        }

        group.appendChild(groupText);

        if (cdr.dailyStats) {
            addInfoToGroup(group, cdr.records[id].callDate, gp);
        }

        cdrBody.appendChild(group);
    }
};

const draw = () => {
    if (!cdr) {
        throw new Error("Tried to draw without CDR data");
    }

    // no-cdrs box
    document.querySelector('.cdr .body .no-cdrs').classList.toggle('active', !cdr.records || cdr.records.length === 0);

    // pages
    document.querySelector('.cdr .controls .status').innerHTML = `${cdr.thisPage} из ${cdr.maxPages}`;
    document.querySelector('.cdr .controls .goto-page').value = cdr.thisPage;
    document.querySelector('.cdr .controls .goto-page').max = cdr.maxPages;

    // page buttons
    document.querySelector('.cdr .controls .button_begin').classList.toggle('active', cdr.thisPage > 1);
    document.querySelector('.cdr .controls .button_left').classList.toggle('active', cdr.thisPage > 1);
    document.querySelector('.cdr .controls .button_right').classList.toggle('active', cdr.thisPage < cdr.maxPages);
    document.querySelector('.cdr .controls .button_end').classList.toggle('active', cdr.thisPage < cdr.maxPages);
    document.querySelector('.cdr .controls .button_goto').classList.toggle('active', cdr.maxPages > 1);
    document.querySelector('.cdr .controls .goto-page').classList.toggle('active', cdr.maxPages > 1);

    // filters
    document.querySelectorAll('.left-panel .filters .filter').forEach( e => {
        let id = e.getAttribute('filter-id');
        if (id) {
            e.querySelector('.value').value = cdr.filter[id] ? prettifyThing(id, cdr.filter[id]) : "";
            e.querySelector('.status').classList.toggle('active', !!cdr.filter[id]);
        }
    });

    // call type filters
    document.querySelector('.left-panel .call-type.call-type_incoming').classList.toggle('active', cdr.filter.callTypes & (1 << common.ctIncoming));
    document.querySelector('.left-panel .call-type.call-type_outgoing').classList.toggle('active', cdr.filter.callTypes & (1 << common.ctOutgoing));
    document.querySelector('.left-panel .call-type.call-type_internal').classList.toggle('active', cdr.filter.callTypes & (1 << common.ctInternal));

    // wildcards
    document.querySelector('.left-panel .filters .filter .wildcard_source').classList.toggle('active', cdr.filter.wcSource);
    document.querySelector('.left-panel .filters .filter .wildcard_destination').classList.toggle('active', cdr.filter.wcDestination);
    document.querySelector('.left-panel .filters .filter .wildcard_any').classList.toggle('active', cdr.filter.wcAny);


    // sortable fields
    document.querySelectorAll('.cdr .header .cell.sortable').forEach( e => {
        let id = "" + e.getAttribute('sort-id');
        if (id) {
            e.querySelector('.sort-button').classList.toggle('sort-none', cdr.filter.sort !== id);
            e.querySelector('.sort-button').classList.toggle('sort-asc', cdr.filter.sort === id && cdr.filter.dir === 'asc');
            e.querySelector('.sort-button').classList.toggle('sort-desc', cdr.filter.sort === id && cdr.filter.dir === 'desc');
        }
    });

    // records

    // cache CDR body descriptor
    // (not actually cdr body due to scrollbars)
    const cdrBody = document.querySelector('.cdr .body .no-cdrs').parentElement;

    // cache some settings
    const globalParms = {
        timeInSeconds: document.querySelector('.left-panel .settings .checkbox.time-in-seconds > input').checked,
        disableGrouping: document.querySelector('.left-panel .settings .checkbox.grouping > input').checked
    };


    // change date header if grouping is enabled
    document.querySelector('.cdr .header .cell.cell_date .name').innerHTML =
        globalParms.disableGrouping ? 'Дата' : 'Время';



    // remove all records first
    cdrBody.querySelectorAll('.entry').forEach( e => { e.remove(); })

    // iterate over records if there are any
    let idx = (cdr.thisPage - 1) * cdr.filter.limit + 1;
    let localIdx = 0;

    // clear out selectedElem
    selectedElem = null;

    cdr.records.forEach( record => {
        // if grouping is enabled, attempt to place a group header
        if (!globalParms.disableGrouping) {
            tryNewGroup(localIdx, cdrBody, globalParms);
        }

        let entry = document.createElement('div');
        entry.classList.add('entry', 'record');
        entry.addEventListener('click', wrapListener(handlerSelectRecord, entry, record.uniqueID));

        // check if this entry has been previously selected
        if (selectedRecord === record.uniqueID) {
            entry.classList.add('active');
            selectedElem = entry;
        }

        ['id', 'dailyct', 'type', 'date', 'source', 'destination', 'total-duration', 'call-duration', 'result', 'records'].forEach( name => {
            const cell = document.createElement('div');
            cell.classList.add('cell', 'cell_' + name);

            switch (name) {
                case 'id': {
                    cell.innerHTML = idx;
                    break;
                }
                case 'type': {
                    const ct = common.callTypeToString(record.callType);
                    cell.appendChild(createSVG(['image', 'type_' + ct], 'icon-' + ct + '-call'))
                    break;
                }
                case 'records': {
                    let play = createSVG(['image', 'link', 'play'], 'icon-play');
                    play.addEventListener('click', wrapListener(handlerPlay, record.uniqueID));
                    cell.appendChild(play);

                    let save = createSVG(['image', 'link', 'save'], 'icon-save');
                    save.addEventListener('click', wrapListener(handlerSave, record.uniqueID));
                    cell.appendChild(save);
                    break;
                }
                default: {
                    const colName = columnNameToId(name);
                    cell.innerHTML = prettifyThing(colName, record[colName], record, globalParms);
                }
            }

            entry.appendChild(cell);
        });

        cdrBody.appendChild(entry);
        idx++;
        localIdx++;
    });

    // TODO group view
};


const populate = async () => {
    const newCdr = await getCdr();
    if (!newCdr) {
        return;
    }

    cdr = newCdr;
    draw();
};



function handlerSave(ev, uid) {
    if (uid) {
        window.location.assign('/api/recording/' + uid + '?asFile=true');
    }

    ev.stopPropagation();
}




function handlerSelectRecord(ev, el, id) {
    if (selectedRecord !== id && selectedElem) {
        selectedElem.classList.remove('active');
    }

    selectedRecord = (selectedRecord === id) ? null : id;
    selectedElem = (selectedRecord !== null) ? el : null;
    el.classList.toggle('active');
}








function handlerFilterNotify(ev, el) {
    el.parentElement.querySelector('.status').classList.toggle('active', el.value && el.value.length > 0);
}
document.querySelectorAll('.left-panel .filters .filter .value').forEach(e => e.addEventListener('change', wrapListener(handlerFilterNotify, e)));
document.querySelectorAll('.left-panel .filters .filter .value').forEach(e => e.addEventListener('input', wrapListener(handlerFilterNotify, e)));



function handlerSort(ev, el) {
    const id = "" + el.getAttribute('sort-id');

    if (id) {
        if (cdr.filter.sort === id) {
            cdr.filter.dir = (cdr.filter.dir === 'asc') ? 'desc' : 'asc';
        } else {
            cdr.thisPage = 1;
            cdr.filter.sort = id;
            cdr.filter.dir = preferableSortDirs[cdr.filter.sort] ? preferableSortDirs[cdr.filter.sort] : 'desc';
        }
    }

    populate();
}

function handlerBegin() {
    if (cdr.thisPage !== 1) {
        cdr.thisPage = 1;
        populate();
    }
}

function handlerLeft() {
    if (cdr.thisPage > 1) {
        --cdr.thisPage;
        populate();
    }
}

function handlerRight() {
    if (cdr.thisPage < cdr.maxPages) {
        ++cdr.thisPage;
        populate();
    }
}

function handlerEnd() {
    if (cdr.thisPage !== cdr.maxPages) {
        cdr.thisPage = cdr.maxPages;
        populate();
    }
}

function handlerGoto() {
    const page = parseInt(document.querySelector('.cdr .controls .goto-page').value, 10);

    if (!isNaN(page) && page !== cdr.thisPage && page >= 1 && page <= cdr.maxPages) {
        cdr.thisPage = page;
        populate();
    }
}




// apply all filters and redraw
function handlerApply() {
    let filters = {};

    // iterate over filters, uglify and apply
    document.querySelectorAll('.left-panel .filters .filter .value').forEach( e => {
        const id = "" + e.getAttribute('filter-id');
        if (id) {
            filters[id] = uglifyThing(id, e.value);

            if (!filters[id] || filters[id].length === 0) {
                delete filters[id];
            }
        }
    });

    // iterate over callType filters, combine into bitmask
    filters.callTypes = 0;
    ['internal', 'outgoing', 'incoming'].forEach( e => {
        filters.callTypes = (filters.callTypes << 1) +
            (document.querySelector('.left-panel .call-type.call-type_' + e).classList.contains('active') ? 1 : 0);
    });

    // do not specify callfilters if none or all are selected
    if (filters.callTypes === 0 || filters.callTypes === 7) {
        delete filters.callTypes;
    }


    // iterate over wildcards
    if (document.querySelector('.left-panel .filters .filter .wildcard_source').classList.contains('active')) { filters.wcSource = true; }
    if (document.querySelector('.left-panel .filters .filter .wildcard_destination').classList.contains('active')) { filters.wcDestination = true; }
    if (document.querySelector('.left-panel .filters .filter .wildcard_any').classList.contains('active')) { filters.wcAny = true; }


    // compare new filters with old filters
    let shouldPopulate = false;
    for (let prop in filters) {
        if (filters[prop] !== cdr.filter[prop]) {
            shouldPopulate = true;
            break;
        }
    }

    // compare old filters with new filters
    for (let prop in cdr.filter) {
        if (typeof filters[prop] === 'undefined') {
            shouldPopulate = true;
            break;
        }
    }

    // should re-filter?
    if (shouldPopulate) {
        cdr.thisPage = 1;
        cdr.filter = filters;
        populate();
    }
}
document.querySelector('.left-panel .filters .button.apply').addEventListener('click', wrapListener(handlerApply));


// reset all filters and redraw
function handlerReset() {
    if (cdr.filter) {
        filterProperties.forEach(e => { delete cdr.filter[e]; });
    }

    document.querySelectorAll('.left-panel .filters .filter .value').forEach( e => e.value = "" );
    document.querySelectorAll('.left-panel .filters .filter .status').forEach( e => e.classList.remove('active') );
    document.querySelectorAll('.left-panel .filters .call-type').forEach( e => e.classList.remove('active') );
    populate();
}
document.querySelector('.left-panel .filters .button.reset').addEventListener('click', wrapListener(handlerReset));
document.querySelector('.cdr .no-cdrs .button.reset').addEventListener('click', wrapListener(handlerReset));



// handle click on calltypes
document.querySelectorAll('.left-panel .filters .call-types .call-type').forEach(e => e.addEventListener('click', wrapListener((ev, el) => {
    el.classList.toggle('active');
}, e)));

// wildcard clicks
document.querySelectorAll('.left-panel .filters .filter .wildcard').forEach(e => e.addEventListener('click', wrapListener((ev, el) => {
    el.classList.toggle('active');
}, e)));



// handle click on settings and set initial values
document.querySelectorAll('.left-panel .settings .checkbox').forEach(e => {
    const state = storageGet('setting-' + e.getAttribute('component-id'));
    if (state === 'on' || state === 'off') {
        e.querySelector('input').checked = (state === 'on');
    }

    e.querySelector('input').addEventListener('click', wrapListener((ev, el) => {
        storageSet('setting-' + el.getAttribute('component-id'), el.querySelector('input').checked ? 'on' : 'off');
    }, e));
});




// handle settings
document.querySelector('.left-panel .settings .checkbox.grouping > input').addEventListener('click', populate);
document.querySelector('.left-panel .settings .checkbox.time-in-seconds > input').addEventListener('click', draw);

// handle page buttons
document.querySelector('.cdr .controls .button_begin').addEventListener('click', wrapListener(handlerBegin));
document.querySelector('.cdr .controls .button_left').addEventListener('click', wrapListener(handlerLeft));
document.querySelector('.cdr .controls .button_right').addEventListener('click', wrapListener(handlerRight));
document.querySelector('.cdr .controls .button_end').addEventListener('click', wrapListener(handlerEnd));
document.querySelector('.cdr .controls .button_goto').addEventListener('click', wrapListener(handlerGoto));


// handle sorting
document.querySelectorAll('.cdr .header .cell.sortable .cell-clickable-area').forEach( e => e.addEventListener('click', wrapListener(handlerSort, e)));





createListener(document.querySelector('.left-panel .new-entries .button.update'), 'click', handlerDoUpdate);


















window.addEventListener('resize', ev => {
    let vh = window.innerHeight;
    let lph = Array.prototype.slice.call(document.querySelectorAll('.body-wrapper > .panel-wrapper > .left-panel > *'))
        .map(e => e.offsetHeight)
        .reduce((acc, cv) => acc + cv);
    let fh = document.querySelector('.body-wrapper > .footer').offsetHeight;

    let bh = 0;
    if (vh > lph + fh) {
        bh = vh - 165;
    } else {
        bh = lph + fh - 165;
    }

    document.querySelector('.cdr .table .body').style.maxHeight = bh + 'px';
});

document.onreadystatechange = e => {
    if (document.readyState === 'complete') {
        draw();

        updateTimerHandle = setTimeout(performUpdate, 5000);
    }
}


// 3rd party stuff

document.addEventListener('DOMContentLoaded', () => {
    OverlayScrollbars(document.querySelector('.cdr .body'), {});
});

const commonPikadayOptions = {
    format: 'dd.mm.yyyy',
    i18n: {
        previousMonth : 'Предыдущий месяц',
        nextMonth : 'Следующий месяц',
        months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
        weekdays: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'],
        weekdaysShort: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб']
    },
    toString(date, format) {
        return date.toLocaleDateString('ru-ru', {});
    },
    theme: 'pd-theme',
    firstDay: 1
};

const startPicker = new Pikaday({ field: document.querySelector('.filters .filter_date-start .value'), ...commonPikadayOptions});
const endPicker = new Pikaday({ field: document.querySelector('.filters .filter_date-end .value'), ...commonPikadayOptions});
