const isB2 = process.env.HWVERSION === 2;

// Bangle.js 1 runs just too fast in direct mode??? (also no getPixel)
if (!isB2) Bangle.setLCDMode("120x120");

const options = Bangle.getOptions();

options.lockTimeout = 0;
options.lcdPowerTimeout = 0;

Bangle.setOptions(options);

g.reset();
g.setBgColor(0, 0, 0);
g.setColor(255, 255, 255);
g.clear();
const h = g.getHeight();

function trigToCoord(ret) {
  return ((ret + 1) * h) / 2;
}

function trigToLen(ret) {
  return (ret * h) / 2;
}

let i = 0.2;
let speedCoef = 0.014;

let flowFile = require("Storage").readJSON("flow.json");

let highestI = (flowFile && flowFile.hiscore) || 0.1;

let colorA = [255, 255, 0];
let colorB = [0, 255, 255];

let x = 0;
let xt = 0;
let safeMode = false;
let lost = false;

function offsetRect(g, x, y, w) {
  g.fillRect(x, y, x + w, y + w);
}

function getColor(num) {
  return [
    [1, 0, 0],
    [0, 1, 0],
    [0, 0, 1],
    [1, 1, 0],
    [0, 1, 1],
    [1, 0, 1],
    [0.5, 0.5, 1],
    [1, 0.5, 0],
    [0, 1, 0.5],
    [0.5, 0.5, 0.5],
  ][num];
}

function calculateColor(num) {
  colorA = getColor(Math.floor((num % 1) * 10));
  colorB = getColor(Math.floor((num % 10) - (num % 1)));
}

calculateColor(highestI);

Bangle.on("touch", () => (safeMode = !safeMode));

function resetGame() {
  x = xt = 0;
  safeMode = lost = false;
  i = 0.2;
  speedCoef = 0.014;
  obstaclePeriod = 150;
  obstacleMode = 1;
  g.clear();
  shownScore = false;
  intervalId = setInterval(draw);
}

function checkCollision() {
  lost = g.getPixel(trigToCoord(+x), (h * 2) / 3 - 4) !== 0;
  if (lost) {
    scoringI = i;
    speedCoef = Math.min(speedCoef, 0.02);
    g.setFont(isB2 ? "6x15" : "4x6", 3);
    g.setColor(colorA[0], colorA[1], colorA[2])
      .drawString(
        "Game over",
        trigToCoord(0) - g.stringWidth("Game over") / 2,
        trigToCoord(0)
      )
      .setColor(1, 1, 1);
  }
}

function drawPlayer() {
  if (!safeMode) xt = Math.cos(i * Math.PI * 4) / 7.5;
  else xt = -Math.cos(i * Math.PI * 2) / 20 + 0.35;
  x = x * 0.8 + xt * 0.2;
  if (highestI > 250) calculateColor(i);
  g.setColor(colorA[0], colorA[1], colorA[2]);
  offsetRect(g, trigToCoord(+x), (h * 2) / 3, 3);
  g.setColor(colorB[0], colorB[1], colorB[2]);
  offsetRect(g, trigToCoord(-x), (h * 2) / 3, 3);
}

let obstaclePeriod = 150;
let obstacleMode = 1;

function drawObstracle() {
  g.setColor(1, 1, 1);
  switch (obstacleMode) {
    case 0:
      offsetRect(g, trigToCoord(-0.15), 0, trigToLen(0.3));
      break;
    case 1:
      offsetRect(g, trigToCoord(0.2), 0, trigToLen(0.2));
      offsetRect(g, trigToCoord(-0.4), 0, trigToLen(0.2));
      break;
    case 2:
      break;
  }
  obstaclePeriod--;
  if (obstaclePeriod <= 0) {
    // If we are off cooldown mode, pick a random actual mode
    if (obstacleMode === 2) {
      obstaclePeriod = Math.random() * 50 + 50;
      obstacleMode = Math.round(Math.random());
    } else if (Math.random() > 0.5) {
      // Give it a chance to repeat with no cooldown
      obstaclePeriod = 25 + 2.5 * speedCoef;
      obstacleMode = 2;
    }
  }
}

let shownScore = false;
let scoringI = 0;

function draw() {
  if (!lost) {
    drawPlayer();
    checkCollision();
    speedCoef *= 1.0005;
    drawObstracle();
  } else {
    speedCoef /= 1.05;
    if (speedCoef <= 0.005) {
      clearInterval(intervalId);
      i -= speedCoef;
      g.setFont(isB2 ? "6x15" : "4x6", 1);
      const str = "Hiscore: " + Math.round(highestI * 10);
      g.setColor(
        scoringI > highestI ? 0 : 255,
        0,
        scoringI > highestI ? 255 : 0
      )
        .drawString(
          str,
          trigToCoord(0) - g.stringWidth(str) / 2,
          trigToCoord(0)
        )
        .setColor(255, 255, 255);
      if (scoringI > highestI) {
        highestI = scoringI;
        require("Storage").writeJSON("flow.json", {
          hiscore: highestI,
        });
        calculateColor(highestI);
      }
      setTimeout(resetGame, 3000);
    } else if (speedCoef <= 0.01 && !shownScore) {
      shownScore = true;
      g.setFont(isB2 ? "6x15" : "4x6", 2);
      const str = "Score: " + Math.round(scoringI * 10);
      g.setColor(colorB[0], colorB[1], colorB[2])
        .drawString(
          str,
          trigToCoord(0) - g.stringWidth(str) / 2,
          trigToCoord(0)
        )
        .setColor(1, 1, 1);
    }
  }
  i += speedCoef;
  g.scroll(0, speedCoef * h);
  g.flip();
}

let intervalId;

if (BTN.read()) {
  for (let i = 0; i < 10; i++) {
    color = getColor(i);
    g.setColor(color[0], color[1], color[2]);
    g.fillRect((i / 10) * h, 0, ((i + 1) / 10) * h, h);
  }
  g.setColor(0);
  g.setFont("Vector", 9);
  let str = "Welcome to the debug screen!";
  g.drawString(
    str,
    trigToCoord(0) - g.stringWidth(str) / 2,
    trigToCoord(0) - 9
  );
  str = "Don't hold BTN while opening to play!";
  g.drawString(str, trigToCoord(0) - g.stringWidth(str) / 2, trigToCoord(0));
  g.flip();
  setInterval(() => {
    g.scroll(0, 0.014 * h);
    i += 0.014;
    calculateColor(i);
    g.setColor(colorA[0], colorA[1], colorA[2]);
    g.fillRect(0, 0, trigToCoord(0), 0.014 * h);
    g.setColor(colorB[0], colorB[1], colorB[2]);
    g.fillRect(trigToCoord(0), 0, trigToCoord(1), 0.014 * h);
  }, 1000 / 30);
} else intervalId = setInterval(draw, 1000 / 30);
