// Chat Homework

// Этапы.

// Используя функцию jsonPost на адрес http://students.a-level.com.ua:10012 напишите чат-клиент, который:

// Stage 0

// Для поиграться скопируйте в консоль функцию jsonPost (или запустите её с этой страницы) и вызовите её с теми или иными 
// объектами в качестве второго параметра. см. RPC.

// jsonPost('http://students.a-level.com.ua:10012', {func: 'addMessage', nick: 'Anon', message: 'Я не умею копипастить в консоль, зато умею жать красную кнопку.'})

// Если после объявления функции jsonPost запустить пример выше, то вы напишите в чат.

// Stage 1

// Отправляет сообщения в чат. Для проверки отслеживайте приходящий с сервера nextMessageId, который должен увеличиваться. 
// Интерфейс: поле ввода ника, поле ввода сообщения, кнопка отправки.

// Stage 2

// Читает все сообщения из чата и выводит их в отдельном контейнере. 
// Интерфейс: некий div-контейнер, в котором на каждое сообщение создается div (или иной блочный контейнерный тэг) 
// и в него помещается ник и сообщение. Также там есть timestamp который может показывать время отправки сообщения.

// Stage 3

// Читает только новые сообщения из чата. Для этого надо после каждого получения запоминать nextMessageId и отправлять его 
// при следующем запросе новых сообщений. Изначально nextMessageId равен нулю, что бы вычитать всю историю сообщений с сервера.

// Stage 4

// Делаем Stage 3 в setInterval для периодической проверки сообщений (раз в 2 -5 секунд).

// Stage 5

// Напишите асинхронную функцию отправки, которая внутри себя будет делать два запроса: на отправку и на проверку, для того 
// что бы минимизировать задержку между отправкой сообщения пользователя и его появлением в окне чата. 
// Оформите отдельно функции отправки и проверки новых сообщений как асинхронные (async, возвращает Promise):

// async function sendMessage(nick, message) отсылает сообщение.
// async function getMessages() получает сообщения и отрисовывает их в DOM
// async function sendAndCheck() использует две предыдущие для минимизации задержки между отправкой сообщения и приходом их. 
// Именно эта функция должна запускаться по кнопке.
// async function checkLoop() использует delay и бесконечный цикл для периодического запуска getMessages().

// Stage 6

// Прогуглить и разобраться с fetch и заменить внутренности jsonPost на код, использующий fetch вместо XMLHttpRequest.

// Информация

// jsonPost

// Данная промисифицированная функция (кстати, сделайте из неё асинхронную) умеет общаться с моим чат-сервером отправляя 
// RPC запросы используя JSON. Remote Procedure Call - вызов функций удаленно, имя функции и параметры передаются AJAX-ом 
// в формате (например) JSON.

// function jsonPost(url, data)
// {
//     return new Promise((resolve, reject) => {
//         var x = new XMLHttpRequest();   
//         x.onerror = () => reject(new Error('jsonPost failed'))
//         //x.setRequestHeader('Content-Type', 'application/json');
//         x.open('POST', url, true);
//         x.send(JSON.stringify(data))

//         x.onreadystatechange = () => {
//             if (x.readyState == XMLHttpRequest.DONE && x.status == 200){
//                 resolve(JSON.parse(x.responseText))
//             }
//             else if (x.status != 200){
//                 reject(new Error('status is not 200'))
//             }
//         }
//     })
// }

// Первым параметром указывается URL (см. выше) на который отправляется методом POST с JSON, вторым - готовый к JSONификации 
// объект, который вы хотите отправить на сервер.

// RPC

// addMessage

// Если вы отправите подобный JSON на сервер (см jsonPost), то сервер запишет ваше сообщение во внутренний массив и отдаст 
// новую длину массива. После этого другие могут прочесть это сообщение, используя метод getMessages.

// {func: 'addMessage', nick: 'msg', message: 'msg'}

// Поле func является обязательным и содержит имя функции, которая должна быть вызвана на сервере. Функция на сервере получает 
// параметром остальной объект (поля nick и message) В ответ вы получите так же объект:

// {nextMessageId: 100500} 
// где 100500: новая длина массива сообщений на сервере после добавления вашего сообщения.

// getMessages

// Позволяет прочесть часть массива сообщений от отпределенного индекса и до конца. 
// Используется для последовательной дочитки новых сообщений. Для этого надо передать в jsonPost подобный объект:

// {func: 'getMessages', messageId: 0}

// При значении 0 в messageId сервер отдаст сообщения от 0 до конца, т. е. весь массив:

// {
// 	'data': [
// 		{
// 			'nick': 'test',
// 			'message': 'test',
// 			'timestamp': 1524225450317
// 		},
// 		{
// 			'nick': 'test',
// 			'message': 'test2',
// 			'timestamp': 1524225460973
// 		},
// 		{
// 			'nick': 'test',
// 			'message': 'test3',
// 			'timestamp': 1524225504849
// 		},
// 		{
// 			'nick': 'SirkoSobaka',
// 			'message': 'Hello!',
// 			'timestamp': 1524226323310
// 		},
// 		{
// 			'nick': 'SirkoSobaka',
// 			'message': 'Hello!',
// 			'timestamp': 1524226326628
// 		},
// 	],
// 	'nextMessageId': 5
// }

// После чего вы итерируете по data и выводите каждый отдельный объект как DOM-элемент с текстом, и, возможно, вложенной 
// версткой (время в отдельном элементе и т.п.)
// nextMessageId вы запоминаете для того, что бы отправить следующий запрос начиная с него (т. е. с 68 в примере выше). 
// Тогда сервер отдаст вам только сообщения новее последнего запроса.

// Chat Server

// Если у вас не чрезмерно свежий хром, то это можно делать даже на локалхосте и открывать файл из браузера с диска. 
// Сервер позволяет соединятся с собой с любого домена.

// Удачи :-)

const url = 'http://students.a-level.com.ua:10012';
const nick = document.getElementById('nick');
const message = document.getElementById('message');
const btnSendMessage = document.getElementById('button');
const container = document.getElementById('container');
let nextMessageId = 1;
let delay = 1000;
setInterval(getMessages, delay);

function getMessages() {
    jsonPost(url, { func: 'getMessages', messageId: nextMessageId })
        .then((response) => response.json())
        .then((data) => {
            nextMessageId = data.nextMessageId;
            updateMessages(data.data);
        });
}

function jsonPost(url, data) {
    return fetch(url, {
        method: 'POST',
        body: JSON.stringify(data),
    });
}

function updateMessages(messageList) {
    messageList.forEach((msg) => {
        newGotMessage(msg);
    });
}

function newGotMessage({ nick, message, timestamp }) {
    const newBlock = document.createElement('div');
    newBlock.classList.add('block');
    const time = new Date(timestamp);
    let html = '';
    html += `<p>${nick}<p>`;
    html += `<p class='message'>'${message}'</p>`;
    html += `<p>${time.toString()}</p>`;
    newBlock.innerHTML = html;
    container.prepend(newBlock);
}

btnSendMessage.addEventListener('click', sendAndCheck);

async function sendAndCheck() {
    await sendMessage();
    getMessages();
    message.value = '';
}

async function sendMessage() {
    jsonPost(url, {
        func: 'addMessage',
        nick: nick.value,
        message: message.value,
    });
}