let canvas = document.getElementById('snake32');
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;

let context = canvas.getContext('2d');
context.scale(canvas.width / 32.0, canvas.height / 32.0);

context['imageSmoothingEnabled'] = false;       /* standard */
context['mozImageSmoothingEnabled'] = false;    /* Firefox */
context['oImageSmoothingEnabled'] = false;      /* Opera */
context['webkitImageSmoothingEnabled'] = false; /* Safari */
context['msImageSmoothingEnabled'] = false;     /* IE */

context.fillStyle = '#fff';
context.fillRect(1, 1, 1, 1);



let emptyField = [];
let drawableField = [];
let field = [];
for (let i = 0; i < 32 * 32; i++) {
  emptyField[i] = 0;
  drawableField[i] = 0;
  field[i] = 0;
}

field = emptyField.slice();

let autoRedraw = true;

function redrawField() {
  if (autoRedraw) {
    context.fillStyle = '#000';
    context.fillRect(0, 0, 32, 32);

    for (let i = 0; i < 32*32; i++) {
      if (drawableField[i] == 0) {
      } else if (drawableField[i] == 1) {
        context.fillStyle = '#888';
        context.fillRect(i % 32, (i / 32)|0, 1, 1);
      } else if (drawableField[i] == 2) {
        if (Math.floor((new Date()).getTime() / 300) % 2) {
          context.fillStyle = '#fff';
        } else {
          context.fillStyle = '#000';
        }
        context.fillRect(i % 32, (i / 32)|0, 1, 1);
      } else {
        context.fillStyle = [null, null, null, '#f66', '#6f6', '#66f', '#ff6', '#f6f', '#6ff'][drawableField[i]]
        context.fillRect(i % 32, (i / 32)|0, 1, 1);
      }
    }
  }

  requestAnimationFrame(redrawField);
}

requestAnimationFrame(redrawField);

function fillScreen() {
  return new Promise((resolve, reject) => {
    let f = emptyField.slice();

    let x = 0;
    let y = 31;
    let dx = 0;
    let dy = -1;

    let timer = setInterval(() => {
      for (let q = 0; q < 16; q++) {
        let i = y * 32 + x;

        f[i] = 1;
        drawableField[i] = 1;
        field[i] = 1;

        context.fillStyle = '#fff';
        context.fillRect(x, y, 1, 1);

        x += dx;
        y += dy;

        if (x < 0 || y < 0 || x > 31 || y > 31 || f[y * 32 + x]) {
          x -= dx;
          y -= dy;

          if (dx > 0) {
            dx = 0;
            dy = 1;
          } else if (dy > 0) {
            dx = -1;
            dy = 0;
          } else if (dx < 0) {
            dx = 0;
            dy = -1;
          } else if (dy < 0) {
            dx = 1;
            dy = 0;
          }

          if (f[(y + dy) * 32 + x + dx]) {
            clearInterval(timer);
            resolve();
            return;
          }
        }
      }
    }, 10);
  });
}

function clearScreen(level) {
  return new Promise((resolve, reject) => {
    let f = drawableField.slice();

    let x = 0;
    let y = 31;
    let dx = 0;
    let dy = -1;

    let timer = setInterval(() => {
      for (let q = 0; q < 16; q++) {
        let i = y * 32 + x;

        f[i] = 0;
        drawableField[i] = level[i];
        field[i] = level[i];

        if (drawableField[i]) {
          context.fillStyle = '#fff';
        } else {
          context.fillStyle = '#000';
        }
        context.fillRect(x, y, 1, 1);

        x += dx;
        y += dy;

        if (x < 0 || y < 0 || x > 31 || y > 31 || !f[y * 32 + x]) {
          x -= dx;
          y -= dy;

          if (dx > 0) {
            dx = 0;
            dy = 1;
          } else if (dy > 0) {
            dx = -1;
            dy = 0;
          } else if (dx < 0) {
            dx = 0;
            dy = -1;
          } else if (dy < 0) {
            dx = 1;
            dy = 0;
          }

          if (!f[(y + dy) * 32 + x + dx]) {
            clearInterval(timer);
            resolve();
            return;
          }
        }
      }
    }, 10);
  });
}


let playerId = null;
let players = [];

function processPlayers() {
  let newPlayers = [];
  players.forEach(player => {
    let time = (new Date()).getTime();

    if (player.gameOver) {
      return;
    }

    if (time - player.lastCheck < player.speed) {
      newPlayers.push(player);
      return;
    }

    player.lastCheck = time;

    player.x += player.dx;
    player.y += player.dy;

    if (player.x < 0) {
      player.x = 31;
    } else if (player.x > 31) {
      player.x = 0;
    }

    if (player.y < 0) {
      player.y = 31;
    } else if (player.y > 31) {
      player.y = 0;
    }

    drawableField = field.slice();

    let index = player.y * 32 + player.x;

    if (drawableField[index] === 2) {
      field[index] = 0;

      player.tail.splice(0, 0, {
        x: player.x,
        y: player.y
      });

      player.speed = Math.max(50, player.speed - 20);
    } else if (drawableField[index] === 0) {
      for (let i = player.tail.length - 1; i > 0; i--) {
        player.tail[i].x = player.tail[i - 1].x;
        player.tail[i].y = player.tail[i - 1].y;
      }

      player.tail[0].x = player.x;
      player.tail[0].y = player.y;
    } else {
      if (player.id === playerId) {
        gameOver = false;
      }

      autoRedraw = false;
    }

    newPlayers.push(player);
  });

  players = newPlayers;
}


function updateDrawableField() {
  drawableField = field.slice();

  players.forEach(player => {
    player.tail.forEach(coords => {
      drawableField[coords.y * 32 + coords.x] = 3 + player.color
    });
  });
}

setInterval(() => {
  processPlayers();
  updateDrawableField();
}, 10);

autoRedraw = false;
gameOver = true;
fillScreen().then(() => {
  let wsUrl = '';
  if (document.location.protocol === 'http:') {
    wsUrl += 'ws://';
  } else if (document.location.protocol === 'https:') {
    wsUrl += 'wss://';
  }
  wsUrl += document.location.hostname
  if (document.location.port) {
    wsUrl += ':' + document.location.port;
  }
  wsUrl += '/ws';

  let ws = new WebSocket(wsUrl);
  let isConnected = false;

  let setWsHandlers = () => {
    ws.onopen = () => {
      isConnected = true;
    };

    ws.onclose = () => {
      isConnected = false;

      autoRedraw = false;
      fillScreen().then(() => {
        ws = new WebSocket(wsUrl);
        setWsHandlers(ws);
      });
    };

    ws.onerror = () => {
      isConnected = false
    };

    ws.onmessage = (e) => {
      let data = JSON.parse(e.data);

      if (data.ping) {
        ws.send(JSON.stringify({
          direction: 0
        }));
      }

      if (!data.room) {
        return;
      }

      if (data.now) {
        console.log('ping: ' + ((new Date).getTime() - data.now) + ' ms');
      }

      field = emptyField.slice();
      if (data.room.items) {
        data.room.items.forEach(item => {
          field[item.i] = item.t;
        });
      }

      playerId = data.playerId;
      players = data.room.players;

      let currPlayer = players.find(x => x.id === playerId);
      if (!currPlayer || currPlayer.gameOver) {
        ws.close();
      }

      autoRedraw = true;
    };
  };

  setWsHandlers(ws);


  document.body.addEventListener('keydown', e => {
    let direction = 0;
    let player = players.find(x => x.id === playerId);

    if (!player) return;

    if (e.keyCode == 37) {
      if (player.dy != 0) {
//      player.dx = -1;
//      player.dy = 0;

        direction = 4;
      }
    } else if (e.keyCode == 39) {
      if (player.dy != 0) {
//      player.dx = 1;
//      player.dy = 0;

        direction = 2;
      }
    } else if (e.keyCode == 38) {
      if (player.dx != 0) {
//        player.dx = 0;
//      player.dy = -1;

        direction = 1;
      }
    } else if (e.keyCode == 40) {
      if (player.dx != 0) {
//        player.dx = 0;
//        player.dy = 1;

        direction = 3;
      }
    }

    if (isConnected && direction) {
      ws.send(JSON.stringify({
        direction: direction,
      }));
    }
  });

  Array.from(document.querySelectorAll('#buttons .button')).forEach(el => {
    el.addEventListener('click', e => {
      e.preventDefault();

      ws.send(JSON.stringify({
        direction: parseInt(el.dataset.direction),
      }));
    });
  });
});
