// =============================================================================
//  Name: Pip-Pong
//  License: CC-BY-NC-4.0
//  Repository: https://github.com/CodyTolene/pip-apps
//  Description: A simple pong game for the Pip-Boy 3000 Mk V.
//  Version: 1.0.0
// =============================================================================

const SCREEN_WIDTH = g.getWidth();
const SCREEN_HEIGHT = g.getHeight();
const TILE_SIZE = 8;
const PADDLE_HEIGHT = 5;
const PADDLE_WIDTH = 4;
const BALL_SIZE = 1;
const GAME_SPEED = 100;
const COLOR_GREEN = '#0F0';
const COLOR_RED = '#F00';
const COLOR_BLACK = '#000';
const COLOR_WHITE = '#FFF';

const GRID_WIDTH = Math.floor(SCREEN_WIDTH / TILE_SIZE);
const GRID_HEIGHT = Math.floor(SCREEN_HEIGHT / TILE_SIZE);

let ball,
  playerPaddle,
  aiPaddle,
  ballVelocity,
  gameLoopInterval,
  inputInterval,
  gameOver = false,
  playerScore = 0;

function drawRect(x, y, w, h, color) {
  g.setColor(color);
  const px = x * TILE_SIZE;
  const py = y * TILE_SIZE;
  g.fillRect(px, py, px + w * TILE_SIZE - 1, py + h * TILE_SIZE - 1);
}

function resetBall() {
  ball = {
    x: Math.floor(GRID_WIDTH / 2),
    y: Math.floor(GRID_HEIGHT / 2),
  };
  const dx = Math.random() > 0.5 ? 1 : -1;
  const dy = Math.random() > 0.5 ? 1 : -1;
  ballVelocity = { x: dx, y: dy };
}

function resetGame() {
  g.clear();
  playerScore = 0;
  gameOver = false;

  playerPaddle = {
    x: 4,
    y: Math.floor(GRID_HEIGHT / 2) - Math.floor(PADDLE_HEIGHT / 2),
  };

  aiPaddle = {
    x: GRID_WIDTH - 8,
    y: Math.floor(GRID_HEIGHT / 2) - Math.floor(PADDLE_HEIGHT / 2),
  };

  resetBall();
  drawScene();

  if (gameLoopInterval) clearInterval(gameLoopInterval);
  gameLoopInterval = setInterval(gameLoop, GAME_SPEED);
}

function drawScene() {
  g.clear();
  drawPaddle(playerPaddle, COLOR_WHITE);
  drawPaddle(aiPaddle, COLOR_WHITE);
  drawBall();
  drawScore();
}

function drawPaddle(paddle, color) {
  drawRect(paddle.x, paddle.y, PADDLE_WIDTH, PADDLE_HEIGHT, color);
}

function drawBall() {
  drawRect(ball.x, ball.y, BALL_SIZE, BALL_SIZE, COLOR_RED);
}

function drawScore() {
  const fixedWidth = 120;
  const rectX = (SCREEN_WIDTH - fixedWidth) / 2;
  const rectY = SCREEN_HEIGHT - 26;
  g.clearRect(rectX, rectY, rectX + fixedWidth, SCREEN_HEIGHT);
  g.setColor(COLOR_GREEN);
  g.setFont('6x8', 2);
  g.drawString('Score: ' + playerScore, SCREEN_WIDTH / 2, SCREEN_HEIGHT - 20);
}

function moveBall() {
  drawRect(ball.x, ball.y, BALL_SIZE, BALL_SIZE, COLOR_BLACK);

  ball.x += ballVelocity.x;
  ball.y += ballVelocity.y;

  if (ball.y <= 0 || ball.y >= GRID_HEIGHT - 1) {
    ballVelocity.y *= -1;
    ball.y = E.clip(ball.y, 0, GRID_HEIGHT - 1);
  }

  if (
    ball.x >= playerPaddle.x &&
    ball.x < playerPaddle.x + PADDLE_WIDTH &&
    ball.y >= playerPaddle.y &&
    ball.y < playerPaddle.y + PADDLE_HEIGHT
  ) {
    ballVelocity.x = 1;
    playerScore++;
    drawScore();
  } else if (
    ball.x >= aiPaddle.x - BALL_SIZE + 1 &&
    ball.x < aiPaddle.x + PADDLE_WIDTH &&
    ball.y >= aiPaddle.y &&
    ball.y < aiPaddle.y + PADDLE_HEIGHT
  ) {
    ballVelocity.x = -1;
  }

  if (ball.x < 0 || ball.x >= GRID_WIDTH) {
    gameOver = true;
    endGame();
    return;
  }

  drawBall();
}

function moveAI() {
  drawPaddle(aiPaddle, COLOR_BLACK);

  if (ball.y > aiPaddle.y + 1) {
    aiPaddle.y = Math.min(GRID_HEIGHT - PADDLE_HEIGHT, aiPaddle.y + 1);
  } else if (ball.y < aiPaddle.y) {
    aiPaddle.y = Math.max(0, aiPaddle.y - 1);
  }

  drawPaddle(aiPaddle, COLOR_WHITE);
}

function movePlayer(dy) {
  drawRect(
    playerPaddle.x,
    playerPaddle.y,
    PADDLE_WIDTH,
    PADDLE_HEIGHT,
    COLOR_BLACK,
  );
  playerPaddle.y += dy;
  playerPaddle.y = E.clip(playerPaddle.y, 0, GRID_HEIGHT - PADDLE_HEIGHT);
  drawPaddle(playerPaddle, COLOR_WHITE);
}

function handleInput() {
  if (BTN_TUNEUP.read()) {
    movePlayer(-1);
  } else if (BTN_TUNEDOWN.read()) {
    movePlayer(1);
  } else if (BTN_TORCH.read()) {
    stopGame();
  }
}

function gameLoop() {
  if (gameOver) return;
  handleInput();
  moveAI();
  moveBall();
}

function endGame() {
  clearInterval(gameLoopInterval);
  g.clear();
  g.setColor(COLOR_GREEN);
  g.setFont('6x8', 4);
  g.drawString('GAME OVER', SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 - 30);
  g.setFont('6x8', 2);
  g.drawString('Score: ' + playerScore, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);
  g.drawString(
    'Press tuner-play to restart',
    SCREEN_WIDTH / 2,
    SCREEN_HEIGHT / 2 + 30,
  );

  inputInterval = setInterval(() => {
    if (BTN_PLAY.read()) {
      clearInterval(inputInterval);
      resetGame();
    }
  }, 100);
}

function stopGame() {
  if (gameLoopInterval) clearInterval(gameLoopInterval);
  if (inputInterval) clearInterval(inputInterval);

  gameOver = true;
  g.clear();

  g.setColor(COLOR_RED);
  g.setFont('6x8', 4);
  g.drawString('GAME HALTED', SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 - 30);
  g.setFont('6x8', 2);
  g.drawString(
    'Press torch again to reboot',
    SCREEN_WIDTH / 2,
    SCREEN_HEIGHT / 2 + 10,
  );

  const waitLoop = setInterval(() => {
    if (BTN_TORCH.read()) {
      clearInterval(waitLoop);
      E.reboot();
    }
  }, 100);
}

function initializeGame() {
  g.clear();
  g.setColor(COLOR_GREEN);
  g.setFont('6x8', 4);
  g.drawString('PIP-PONG', SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 - 80);

  g.setFont('6x8', 2);
  g.drawString(
    'Use tuner-up/down to move',
    SCREEN_WIDTH / 2,
    SCREEN_HEIGHT / 2 - 40,
  );
  g.drawString(
    'Torch: Quit | Tuner-play: Start',
    SCREEN_WIDTH / 2,
    SCREEN_HEIGHT / 2 - 10,
  );

  g.setColor(COLOR_RED);
  g.drawString(
    "Don't let the ball pass!",
    SCREEN_WIDTH / 2,
    SCREEN_HEIGHT / 2 + 20,
  );

  g.setColor(COLOR_GREEN);
  g.drawString(
    'Press tuner-play to START',
    SCREEN_WIDTH / 2,
    SCREEN_HEIGHT / 2 + 50,
  );

  const waitLoop = setInterval(() => {
    if (BTN_PLAY.read()) {
      clearInterval(waitLoop);
      resetGame();
    }
  }, 100);
}

initializeGame();