// Светофор
// Используя асинхронную функцию и бесконечный цикл, просимулируйте светофор:
// Для отображения включения того или иного света используйте один или три DOM-элемента.
// Stage 2
// Сделайте trafficLight более универсальной - добавьте в параметры DOM-элемент для отображения, а так же время
// работы каждого цвета
traffic_light: {
  const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms));

  let trafficLightEl = document.createElement('div');
  document.body.append(trafficLightEl);
  trafficLightEl.classList.add('traffic-light');
  let red = document.createElement('div');
  trafficLightEl.append(red);
  red.classList.add('cell');
  let yellow = document.createElement('div');
  trafficLightEl.append(yellow);
  yellow.classList.add('cell');
  let green = document.createElement('div');
  trafficLightEl.append(green);
  green.classList.add('cell');

  async function trafficLight(greenEl, yellowEl, redEl, greenTime, yellowTime, redTime) {
    while (true) {
      greenEl.classList.add('green');
      await delay(greenTime);
      greenEl.classList.remove('green');
      yellowEl.classList.add('yellow');
      await delay(yellowTime);
      yellowEl.classList.remove('yellow');
      redEl.classList.add('red');
      await delay(redTime);
      redEl.classList.remove('red');
    }
  }
  trafficLight(green, yellow, red, 6000, 1000, 6000);
}

// PedestrianTrafficLight
// Напишите упрощенный светофор для пешеходов
// Stage 2
// Используя Promise.race, domEventPromise и кнопку в DOM сделайте пешеходный светофор с кнопкой, который так
// же переключается по времени периодически.
// Stage 3
// Не давайте возможности пешеходам сильно наглеть - предусмотрите задержку, после которой будет работать
// кнопка.
pedestrian_traffic_light: {
  const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms));

  let pedestrianTrafficLightEl = document.createElement('div');
  document.body.append(pedestrianTrafficLightEl);
  pedestrianTrafficLightEl.classList.add('traffic-light');
  let red = document.createElement('div');
  pedestrianTrafficLightEl.append(red);
  red.classList.add('cell');
  let green = document.createElement('div');
  pedestrianTrafficLightEl.append(green);
  green.classList.add('cell');
  let button = document.createElement('button');
  button.innerText = 'switch';
  document.body.append(button);

  function domEventPromise(element, eventName) {
    function executor(resolve) {
      function myEvent(event) {
        element.disabled = true;
        element.removeEventListener(eventName, myEvent);
        setTimeout(() => resolve(event), 2000);
      }
      element.disabled = false;
      element.addEventListener(eventName, myEvent)
    }
    return new Promise(executor);
  }

  async function pedestrianTrafficLight(ms) {
    while (true) {
      red.classList.add('red');
      await Promise.race([
        delay(ms),
        domEventPromise(button, 'click')
      ]);
      red.classList.remove('red');
      green.classList.add('green');
      await delay(ms);
      green.classList.remove('green');
    }
  }
  pedestrianTrafficLight(6000);
}

// speedtest
// Написать асинхронную функцию, где:
// count - количество повторов
// parallel - количество одновременных запросов/промисов в одном повторе
// getPromise - функция, которая умеет вернуть нужный Вам промис для тестирования скорости его работы
// которая будет в цикле count раз создавать parallel промисов с помощью переданной функции getPromise,
// дожидаться выполнения всех parallel промисов, после чего цикл повторяется.
// Замерить время общее время выполнения, и вычислить:
// duration, общую длительность работы цикла
// parallelDuration, среднее время обработки запроса параллельно (за какое время исполнилось parallel*count
// промисов),
// paralledSpeed, скорость в запросах в миллисекунду
// queryDuration, реальное среднее время запроса (отталкиваясь от count и времени работы цикла).
// querySpeed, реальное средняя скорость запроса
// Эти переменные вернуть в одном объекте-результате (см. заготовку выше)
// Для отладки попробуйте на delay (пример выше есть, реальное время будет отличаться на единицы-десятки
// миллисекунд). Потом можете попробовать на swapi.dev. Не создавайте чрезмерно много параллельных запросов.
speedtest: {

  const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms));

  function makeProfileTimer() {
    let t0 = performance.now();
    return function () {
      let t1 = performance.now();
      return t1 - t0;
    }
  }

  async function speedtest(getPromise, count, parallel = 1) {
    let timer = makeProfileTimer();
    for (let i = 0; i < count; i++) {
      let promises = [];
      for (let j = 0; j < parallel; j++) {
        promises.push(getPromise());
      }
      console.log(await Promise.all(promises));
    }
    let duration = timer();
    let parallelDuration = duration / (count * parallel);
    let parallelSpeed = 1 / parallelDuration;
    let queryDuration = duration / count;
    let querySpeed = 1 / queryDuration;

    return {
      duration,
      querySpeed, //средняя скорость одного запроса
      queryDuration, //
      parallelSpeed,
      parallelDuration
    }
  }

  speedtest(() => delay(1000), 10, 10).then(result => console.log(result));
  // {duration: 10000, 
  // querySpeed: 0.001, //1 тысячная запроса за миллисекунду
  // queryDuration: 1000, //1000 миллисекунд на один реальный запрос в среднем 
  // parallelSpeed: 0.01  // 100 запросов за 10000 миллисекунд
  // parallelDuration: 100 // 100 запросов за 10000 миллисекунд
  speedtest(() => fetch('http://swapi.dev/api/people/1').then(res => res.json()), 10, 5).then(result => console.log(result));
}

// gql
// Напишите функцию gql, которая осуществляет GraphQL запрос. Функция принимает три параметра:
// Эндпоинт - адрес сервера. Например "http://shop-roles.node.ed.asmer.org.ua/graphql"
// Текст запроса (query).
// Параметры(переменные) (variables) запроса объектом
// Функция должна возвращать промис, созданный fetch со следующими настройками:
// Метод POST
// Заголовки:
// Content-Type - application/json
// Accept- application/json
// Тело - JSON, объект с двумя ключами - query (текст запроса) и variables
gql: {
  function gql(endpoint, query, variables) {
    return fetch(endpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      },
      body: JSON.stringify({
        query,
        variables
      }),
    }).then(response => response.json());
  }

  (async () => {
    const catQuery = `query cats($q: String){
                                        CategoryFind(query: $q){
                                            _id name
                                        }
                                    }`
    const cats = await gql("http://shop-roles.node.ed.asmer.org.ua/graphql", catQuery, { q: "[{}]" })
    console.log(cats) //список категорий с _id name и всем таким прочим


    const loginQuery = `query login($login:String, $password:String){
                            	login(login:$login, password:$password)
                        }`

    const token = await gql("http://shop-roles.node.ed.asmer.org.ua/graphql", loginQuery, { login: "test457", password: "123123" })
    console.log(token)
  })()
}

// jwtDecode
// Напишете функцию jwtDecode, которая принимает единственный параметр token и возвращает информацию из
// переданного JWT токена.
// Алгоритм раскодирования:
// Разбить токен на три части. Разделитель - . (точка)
// Выделить среднюю часть.
// Используя функцию atob раскодировать среднюю часть из кодировки Base64, получив JSON
// Раскодировать JSON
// Вернуть раскодированные данные из JSON
// Учтите, что в качестве токена может быть передана какая-то дичь. В таком случае раскодировка не получится,
// и функция:
// Не должна сыпать красными матюками (ошибками) в консоль
// Должна просто вернуть undefined
jwtDecode: {
  const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOnsiaWQiOiI2MzIyMDVhZWI3NGUxZjVmMmVjMWEzMjAiLCJsb2dpbiI6InRlc3Q0NTciLCJhY2wiOlsiNjMyMjA1YWViNzRlMWY1ZjJlYzFhMzIwIiwidXNlciJdfSwiaWF0IjoxNjY4MjcyMTYzfQ.rxV1ki9G6LjT2IPWcqkMeTi_1K9sb3Si8vLB6UDAGdw";
  function jwtDecode(token) {
    let result;
    try {
      let mediumStr = token.split('.')[1];
      result = JSON.parse(atob(mediumStr));
    } catch (e) {
    }

    return result;
  }
  console.log(jwtDecode(token));
  //{
  //  "sub": {
  //    "id": "632205aeb74e1f5f2ec1a320",
  //    "login": "test457",
  //    "acl": [
  //      "632205aeb74e1f5f2ec1a320",
  //      "user"
  //    ]
  //  },
  //  "iat": 1668272163
  //}

  try {
    console.log(jwtDecode());         //undefined
    console.log(jwtDecode("дичь"));   //undefined
    console.log(jwtDecode("ey.ey.ey"));   //undefined

    console.log('до сюда доработало, а значит jwtDecode не матерился в консоль красным цветом');
  }
  finally {
    console.log('ДЗ, видимо, окончено');
  }
}