const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

const arenaSize = 500;
const subSquareSize = arenaSize / 3;
const clockRadius = subSquareSize / 9;
const playerSize = subSquareSize / 10;
const handLength = clockRadius;
const triangleOpacity = 0.5;

let rotationStep = 0;
const maxRotationSteps = 6;
let rotationStarted = false;
let rotationComplete = false;
let randomLayout = Math.floor(Math.random() * 5);
let lastRotationTime = performance.now();
let gameStopped = false;

let player = null;
let clocks = null;

let deathImage = new Image();

// Set the source of the image
deathImage.src = "../images/vuln-stack.png";


function rotateClocks(elapsedTime) {
  if (rotationStep < maxRotationSteps && elapsedTime >= 1000) {
    clocks.forEach(clock => clock.rotateHand());
    rotationStep++;
    lastRotationTime = performance.now();
  } else if (rotationStep === maxRotationSteps) {
    rotationComplete = true;
  }
}

function resetRotation() {
  rotationStep = 0;
  rotationComplete = false;
}

class Clock {
  constructor(x, y, handDirection) {
    this.x = x;
    this.y = y;
    this.handDirection = handDirection;
  }
   
  drawArrow() {
    ctx.lineWidth = 1;
    ctx.strokeStyle = "black";
    // Draw the line
    ctx.beginPath();
    ctx.moveTo(this.x, this.y);
    ctx.lineTo(
      this.x + handLength * Math.cos(this.handDirection * Math.PI / 180),
      this.y + handLength * Math.sin(this.handDirection * Math.PI / 180)
    );
    ctx.stroke();

    // Draw the arrowhead
    var arrowSize = 7; // Change the value to adjust the size of the arrowhead
    var arrowAngle = Math.PI / 9; // Change the value to adjust the angle of the arrowhead
    var angle = Math.atan2(handLength * Math.sin(this.handDirection * Math.PI / 180), handLength * Math.cos(this.handDirection * Math.PI / 180));
    ctx.beginPath();
    ctx.moveTo(
      this.x + handLength * Math.cos(this.handDirection * Math.PI / 180),
      this.y + handLength * Math.sin(this.handDirection * Math.PI / 180)
    );
    ctx.lineTo(
      this.x + (handLength - arrowSize) * Math.cos(angle - arrowAngle),
      this.y + (handLength - arrowSize) * Math.sin(angle - arrowAngle)
    );
    ctx.lineTo(
      this.x + (handLength - arrowSize) * Math.cos(angle + arrowAngle),
      this.y + (handLength - arrowSize) * Math.sin(angle + arrowAngle)
    );
    ctx.closePath();
    ctx.fillStyle = "red"; // Set the fill color to red
    ctx.fill();
  }

  draw() {
    ctx.beginPath();
    ctx.arc(this.x, this.y, clockRadius, 0, 2 * Math.PI);
    ctx.fillStyle = "gold";
    ctx.fill();
    ctx.strokeStyle = "orange";
    ctx.lineWidth = 3;
    ctx.stroke();

    this.drawArrow();
    ctx.stroke();
  }

  rotateHand() {
    this.handDirection = (this.handDirection + 90) % 360;
  }

drawConal() {
    const angle = 45;
    const sideLength = 50;
    
    ctx.beginPath();
    ctx.moveTo(this.x, this.y);
    ctx.lineTo(
      this.x + sideLength * handLength * Math.cos((this.handDirection - angle) * Math.PI / 180),
      this.y + sideLength * handLength * Math.sin((this.handDirection - angle) * Math.PI / 180)
    );
    ctx.lineTo(
      this.x + sideLength * handLength * Math.cos((this.handDirection + angle) * Math.PI / 180),
      this.y + sideLength * handLength * Math.sin((this.handDirection + angle) * Math.PI / 180)
    );
    ctx.closePath();
    ctx.fillStyle = `rgba(255, 255, 0, ${triangleOpacity})`;
    ctx.fill();
    

    // Draw red lines
    ctx.beginPath();
    ctx.moveTo(this.x, this.y);
    ctx.lineTo(
      this.x + sideLength * handLength * Math.cos((this.handDirection - angle) * Math.PI / 180),
      this.y + sideLength * handLength * Math.sin((this.handDirection - angle) * Math.PI / 180)
    );
    ctx.strokeStyle = 'red';
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(this.x, this.y);
    ctx.lineTo(
      this.x + sideLength * handLength * Math.cos((this.handDirection + angle) * Math.PI / 180),
      this.y + sideLength * handLength * Math.sin((this.handDirection + angle) * Math.PI / 180)
    );
    ctx.strokeStyle = 'red';
    ctx.stroke();
    ctx.strokeStyle = 'black';
  }
}

const keysPressed = {
  ArrowUp: false, W: false, w: false,
  ArrowLeft: false, A: false, a: false,
  ArrowDown: false, S: false, s: false,
  ArrowRight: false, D: false, d: false
};

class Player {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.hasMoved = false;
  }

  draw() {
    ctx.fillStyle = 'blue';
    ctx.fillRect(this.x - playerSize / 2, this.y - playerSize / 2, playerSize, playerSize);
  }

  move(dx, dy) {
    const newX = this.x + dx;
    const newY = this.y + dy;

    if (newX >= playerSize / 2 && newX <= arenaSize - playerSize / 2) {
      this.x = newX;
      this.hasMoved = true;
    }
    if (newY >= playerSize / 2 && newY <= arenaSize - playerSize / 2) {
      this.y = newY;
      this.hasMoved = true;
    }
  }
}

function getClockPositions(layout) {
  switch (layout) {
  case 0:
    return [
      new Clock(subSquareSize, subSquareSize, 180),
      new Clock(arenaSize - subSquareSize, subSquareSize * 2, 0)
    ];

  case 1:
    return [
      new Clock(subSquareSize, subSquareSize, 180),
      new Clock(subSquareSize, subSquareSize * 2, 180),
      new Clock(arenaSize - subSquareSize, subSquareSize + (subSquareSize / 2), 0)
    ];

  case 2:
    return [
      new Clock(subSquareSize, subSquareSize, 270),
      new Clock(subSquareSize, subSquareSize * 2, 90),
      new Clock(arenaSize - subSquareSize, subSquareSize + (subSquareSize / 2), 180)
    ];

  case 3:
    return [
      new Clock(subSquareSize + (subSquareSize / 2), subSquareSize, 270),
      new Clock(subSquareSize, subSquareSize * 2, 90),
      new Clock(arenaSize - subSquareSize, subSquareSize + (subSquareSize / 2), 180)
    ];

   case 4: 
    return [
      new Clock(subSquareSize + (subSquareSize / 2), subSquareSize, 0),
      new Clock(subSquareSize, subSquareSize * 2, 180),
      new Clock(arenaSize - subSquareSize, subSquareSize + (subSquareSize / 2), 90)
    ]
  }
}


function pointInTriangle(px, py, ax, ay, bx, by, cx, cy) {
  const v0x = cx - ax;
  const v0y = cy - ay;
  const v1x = bx - ax;
  const v1y = by - ay;
  const v2x = px - ax;
  const v2y = py - ay;

  const d00 = v0x * v0x + v0y * v0y;
  const d01 = v0x * v1x + v0y * v1y;
  const d11 = v1x * v1x + v1y * v1y;
  const d20 = v2x * v0x + v2y * v0y;
  const d21 = v2x * v1x + v2y * v1y;

  const denominator = d00 * d11 - d01 * d01;
  const a = (d11 * d20 - d01 * d21) / denominator;
  const b = (d00 * d21 - d01 * d20) / denominator;

  return a >= 0 && b >= 0 && a + b <= 1;
}

function checkCollisions() {
  const px = player.x;
  const py = player.y;
  let collision = false;

  for (const clock of clocks) {
    const ax = clock.x;
    const ay = clock.y;
    const angle = 45;
    const sideLength = 50;

    const bx = clock.x + sideLength * handLength * Math.cos((clock.handDirection - angle) * Math.PI / 180);
    const by = clock.y + sideLength * handLength * Math.sin((clock.handDirection - angle) * Math.PI / 180);
    const cx = clock.x + sideLength * handLength * Math.cos((clock.handDirection + angle) * Math.PI / 180);
    const cy = clock.y + sideLength * handLength * Math.sin((clock.handDirection + angle) * Math.PI / 180);

    if (pointInTriangle(px, py, ax, ay, bx, by, cx, cy)) {
      collision = true;
      break;
    }
  }

  return collision;
}

function displaySafeStatus(isSafe) {
  if (isSafe)
    succeeded();
  else
    failed();
}


function succeeded() {
  drawText("SUCCESS!", 'green');
}

function failed() {
  ctx.drawImage(deathImage, player.x - playerSize, player.y - playerSize, playerSize * 2, playerSize * 2);
  drawText("FAILED!", 'red');
}

function drawText(text, colour) {
  ctx.font = '35px Verdana'; // Set the font size and type
  ctx.fillStyle = colour; // Set the fill color
  ctx.textAlign = 'center'; // Set the horizontal alignment
  ctx.textBaseline = 'middle'; // Set the vertical alignment

  const x = canvas.width / 2; // Set the x-coordinate of the text
  const y = 80; // Set the y-coordinate of the text

  ctx.fillText(text, x, y); // Draw the text using fillText()
}

function gameLoop(currentTime) {

  if (gameStopped) {
    requestAnimationFrame(gameLoop);
    return;
  }

  ctx.fillStyle = "gray";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  if (rotationStarted === false && player.hasMoved) {
    rotationStarted = true;
  }

  const elapsedTime = currentTime - lastRotationTime;

  if (rotationStarted && !rotationComplete) {
    rotateClocks(elapsedTime);
  }

  const moveAmount = 4;
  if (movingUp()) player.move(0, -moveAmount);
  if (movingDown()) player.move(0, moveAmount);
  if (movingLeft()) player.move(-moveAmount, 0);
  if (movingRight()) player.move(moveAmount, 0);

  player.draw();
  clocks.forEach(clock => {
    clock.draw();
    if (rotationComplete) {
      clock.drawConal();
    }
  });

  if (rotationComplete) {
    const isSafe = !checkCollisions();
    displaySafeStatus(isSafe);
    stopGame();
  }

  requestAnimationFrame(gameLoop);
}

function movingUp() { return keysPressed.ArrowUp || keysPressed.W || keysPressed.w; }
function movingDown() { return keysPressed.ArrowDown || keysPressed.S || keysPressed.s; }
function movingLeft() { return keysPressed.ArrowLeft || keysPressed.A || keysPressed.a; }
function movingRight() { return keysPressed.ArrowRight || keysPressed.D || keysPressed.d; }

function startGame() {
  gameStopped = false;
  rotationStarted = false;
  rotationComplete = false;

  player = new Player(arenaSize / 2, arenaSize / 2);
  clocks = getClockPositions(randomLayout);
}

function stopGame() {
  gameStopped = true;
}

function generateNewLayout() {
  let newLayout;
  do {
    newLayout = Math.floor(Math.random() * 5);
  } while (newLayout === randomLayout);
  randomLayout = newLayout;
}


function keydownHandler(event) {
  if (keysPressed.hasOwnProperty(event.key)) {
    keysPressed[event.key] = true;
  }
}

function keyupHandler(event) {
  if (keysPressed.hasOwnProperty(event.key)) {
    keysPressed[event.key] = false;
  }
}

document.addEventListener('keydown', keydownHandler);
document.addEventListener('keyup', keyupHandler);

document.getElementById("resetButton").addEventListener("click", function() {
  stopGame();
  resetRotation();
  generateNewLayout();
  startGame();
});

document.getElementById("retryButton").addEventListener("click", function() {
  stopGame();
  resetRotation();
  startGame();
});

startGame();
gameLoop();
