/* HR Candidate Matcher — UI Layer */
/* global window, document */
(function () {
'use strict';
var APP = window.HRMatcher = window.HRMatcher || {};
var $ = function (sel) { return document.querySelector(sel); };
var $$ = function (sel) { return Array.prototype.slice.call(document.querySelectorAll(sel)); };
var toastTimer = null;
var confirmCallback = null;
var currentFilter = 'all';
var criteriaEditState = [];
APP.ui = {
showToast: function (message, type) {
var container = $('#toast-container');
if (!container) return;
var toast = document.createElement('div');
toast.className = 'toast' + (type ? ' toast-' + type : '');
toast.textContent = message;
container.appendChild(toast);
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toast.classList.add('toast-out');
setTimeout(function () { if (toast.parentNode) toast.parentNode.removeChild(toast); }, 200);
}, 3000);
},
showConfirm: function (message, onConfirm) {
var modal = $('#modal-confirm');
var desc = $('#confirm-desc');
if (!modal || !desc) return;
desc.textContent = message;
modal.hidden = false;
confirmCallback = onConfirm;
$('#btn-confirm-ok').focus();
},
hideConfirm: function () {
var modal = $('#modal-confirm');
if (modal) modal.hidden = true;
confirmCallback = null;
},
resolveConfirm: function () {
if (confirmCallback) confirmCallback();
},
showError: function (fieldId, message) {
var field = $('#field-' + fieldId);
var error = $('#' + fieldId + '-error');
if (field) field.classList.add('has-error');
if (error) {
error.textContent = message;
error.hidden = false;
}
},
clearError: function (fieldId) {
var field = $('#field-' + fieldId);
var error = $('#' + fieldId + '-error');
if (field) field.classList.remove('has-error');
if (error) {
error.textContent = '';
error.hidden = true;
}
},
clearAllErrors: function () {
$$('.field').forEach(function (f) { f.classList.remove('has-error'); });
$$('.field-error').forEach(function (e) { e.textContent = ''; e.hidden = true; });
},
showScreen: function (screenName) {
$$('.screen').forEach(function (s) { s.hidden = true; });
var screen = $('#screen-' + screenName);
if (screen) {
screen.hidden = false;
screen.removeAttribute('hidden');
}
var nav = $('#app-nav');
var clearBtn = $('#btn-clear-all');
if (screenName === 'welcome') {
if (nav) nav.hidden = true;
if (clearBtn) clearBtn.hidden = true;
} else {
if (nav) nav.hidden = false;
if (clearBtn) clearBtn.hidden = false;
}
this.updateStepsIndicator(screenName);
window.scrollTo(0, 0);
},
updateStepsIndicator: function (current) {
var steps = ['input', 'criteria', 'match', 'interview'];
var currentIdx = steps.indexOf(current);
$$('.step').forEach(function (el) {
var stepName = el.getAttribute('data-step');
var stepIdx = steps.indexOf(stepName);
el.classList.remove('step-active', 'step-done');
if (stepIdx === currentIdx) el.classList.add('step-active');
else if (stepIdx < currentIdx) el.classList.add('step-done');
});
},
renderCriteriaTable: function (criteria) {
var tbody = $('#criteria-tbody');
var emptyMsg = $('#criteria-empty');
var tableWrap = $('.criteria-table-wrap');
if (!tbody) return;
criteriaEditState = criteria.map(function (c) {
return {
id: c.id,
label: c.label,
required: c.required,
weight: c.weight,
synonyms: (c.synonyms || []).join(', ')
};
});
if (criteria.length === 0) {
tbody.innerHTML = '';
if (tableWrap) tableWrap.hidden = true;
if (emptyMsg) emptyMsg.hidden = false;
return;
}
if (tableWrap) tableWrap.hidden = false;
if (emptyMsg) emptyMsg.hidden = true;
var html = '';
for (var i = 0; i < criteriaEditState.length; i++) {
var c = criteriaEditState[i];
html += '
';
html += '
';
html += '
';
html += '
';
html += '
';
html += '
';
html += '
';
}
tbody.innerHTML = html;
},
readCriteriaFromTable: function () {
var rows = $$('#criteria-tbody tr');
var criteria = [];
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
var id = row.getAttribute('data-id');
var label = row.querySelector('[data-field="label"]').value.trim();
var required = row.querySelector('[data-field="required"]').value === 'true';
var weight = parseInt(row.querySelector('[data-field="weight"]').value, 10);
var synonymsStr = row.querySelector('[data-field="synonyms"]').value;
var synonyms = synonymsStr.split(',').map(function (s) { return s.trim(); }).filter(Boolean);
criteria.push({ id: id, label: label, required: required, weight: weight, synonyms: synonyms });
}
return criteria;
},
renderMatchTable: function (criteria, matchResults, filter) {
var tbody = $('#match-tbody');
var emptyMsg = $('#match-empty');
var tableWrap = $('.match-table-wrap');
if (!tbody) return;
var filtered = APP.logic.getFilteredResults(matchResults, filter);
if (filtered.length === 0) {
tbody.innerHTML = '';
if (tableWrap) tableWrap.hidden = true;
if (emptyMsg) emptyMsg.hidden = false;
return;
}
if (tableWrap) tableWrap.hidden = false;
if (emptyMsg) emptyMsg.hidden = true;
var html = '';
for (var i = 0; i < filtered.length; i++) {
var r = filtered[i];
var c = APP.logic.getCriterionById(criteria, r.criterionId);
if (!c) continue;
var statusClass = 'status-' + r.status.replace('_', '-');
var statusIcon = '';
var statusText = '';
if (r.status === APP.STATUS.CONFIRMED) {
statusIcon = '';
statusText = 'Подтверждено';
} else if (r.status === APP.STATUS.NOT_FOUND) {
statusIcon = '';
statusText = 'Не найдено';
} else {
statusIcon = '';
statusText = 'Уточнить';
}
var evidenceHtml = '';
if (r.evidence && r.evidence.length > 0) {
evidenceHtml = '
';
for (var e = 0; e < r.evidence.length; e++) {
evidenceHtml += '
' + escapeHtml(r.evidence[e].fragment) + '
';
}
evidenceHtml += '
';
} else {
evidenceHtml = 'Фрагменты не найдены';
}
html += '
';
html += '
' + escapeHtml(c.label) + '
';
html += '
' + evidenceHtml + '
';
html += '
';
html += '';
html += '
';
html += '
';
html += '
';
}
tbody.innerHTML = html;
},
renderCoverage: function (coverage) {
var bar = $('#coverage-bar-fill');
var value = $('#coverage-value');
if (bar) {
bar.style.width = coverage + '%';
bar.setAttribute('aria-valuenow', coverage);
}
if (value) {
value.textContent = coverage + '%';
}
},
renderInterview: function (interviewData) {
var container = $('#interview-questions');
var emptyMsg = $('#interview-empty');
if (!container) return;
if (interviewData.length === 0) {
container.innerHTML = '';
if (emptyMsg) emptyMsg.hidden = false;
return;
}
if (emptyMsg) emptyMsg.hidden = true;
var statusLabels = {};
statusLabels[APP.STATUS.NOT_FOUND] = 'Не найдено';
statusLabels[APP.STATUS.UNCLEAR] = 'Требует уточнения';
var html = '';
var globalNum = 1;
for (var i = 0; i < interviewData.length; i++) {
var section = interviewData[i];
html += '
';
html += '
' + escapeHtml(section.criterion.label);
html += ' ' + (statusLabels[section.status] || section.status) + '';
html += '
';
html += '
';
html += '
';
if (section.criterion.required) html += 'Обязательное';
else html += 'Желательное';
html += ' · Вес ' + section.criterion.weight;
html += '
';
html += '';
for (var q = 0; q < section.questions.length; q++) {
html += '