var draw = use('draw2d')
var input = use('input')
var config = use('config')
var color = use('color')
var random = use('random')

prosperon.camera.transform.pos = [0,0]

// Board constants
var COLS = 10, ROWS = 20
var TILE = 6 // each cell is 6x6

// Board storage (2D), each cell is either 0 or a [r,g,b,a] color
var board = []

// Gravity timing
var baseGravity = 0.8 // seconds between drops at level 0
var gravityTimer = 0

// Current piece & position
var piece = null
var pieceX = 0
var pieceY = 0

// Next piece
var nextPiece = null

// Score/lines/level
var score = 0
var linesCleared = 0
var level = 0

// Rotation lock to prevent spinning with W
var rotateHeld = false
var gameOver = false

// Horizontal movement gating
var hMoveTimer = 0
var hDelay = 0.2      // delay before repeated moves begin
var hRepeat = 0.05    // time between repeated moves
var prevLeft = false
var prevRight = false

// Tetrimino definitions
var SHAPES = {
  I: { color:[0,1,1,1], blocks:[[0,0],[1,0],[2,0],[3,0]] },
  O: { color:[1,1,0,1], blocks:[[0,0],[1,0],[0,1],[1,1]] },
  T: { color:[1,0,1,1], blocks:[[0,0],[1,0],[2,0],[1,1]] },
  S: { color:[0,1,0,1], blocks:[[1,0],[2,0],[0,1],[1,1]] },
  Z: { color:[1,0,0,1], blocks:[[0,0],[1,0],[1,1],[2,1]] },
  J: { color:[0,0,1,1], blocks:[[0,0],[0,1],[1,1],[2,1]] },
  L: { color:[1,0.5,0,1], blocks:[[2,0],[0,1],[1,1],[2,1]] }
}
var shapeKeys = array(SHAPES)

// Initialize board with empty (0)
function initBoard() {
  board = []
  var r = 0;
  var row = null;
  var c = 0;
  for (r=0; r<ROWS; r++) {
    row = []
    for (c=0; c<COLS; c++) push(row, 0)
    push(board, row)
  }
}
initBoard()

function randomShape() {
  var key = shapeKeys[floor(random.random()*length(shapeKeys))]
  // Make a copy of the shape's blocks
  return {
    type: key,
    color: SHAPES[key].color,
    blocks: array(SHAPES[key].blocks, b => [b[0], b[1]])
  }
}

function spawnPiece() {
  piece = nextPiece || randomShape()
  nextPiece = randomShape()
  pieceX = 3
  pieceY = 0
  // Collision on spawn => game over
  if (collides(pieceX, pieceY, piece.blocks)) gameOver = true
}

function collides(px, py, blocks) {
  var i = 0;
  var x = 0;
  var y = 0;
  for (i=0; i<length(blocks); i++) {
    x = px + blocks[i][0]
    y = py + blocks[i][1]
    if (x<0 || x>=COLS || y<0 || y>=ROWS) return true
    if (y>=0 && board[y][x]) return true
  }
  return false
}

// Lock piece into board
function lockPiece() {
  var i = 0;
  var x = 0;
  var y = 0;
  for (i=0; i<length(piece.blocks); i++) {
    x = pieceX + piece.blocks[i][0]
    y = pieceY + piece.blocks[i][1]
    if (y>=0) board[y][x] = piece.color
  }
}

// Rotate 90° clockwise
function rotate(blocks) {
  // (x,y) => (y,-x)
  var i = 0;
  var x = 0;
  var y = 0;
  for (i=0; i<length(blocks); i++) {
    x = blocks[i][0]
    y = blocks[i][1]
    blocks[i][0] = y
    blocks[i][1] = -x
  }
}

function clearLines() {
  var lines = 0
  var r = ROWS-1;
  var newRow = null;
  var c = 0;
  for (r=ROWS-1; r>=0;) {
    if (every(board[r], cell => cell)) {
      lines++
      // remove row
      board = array(array(board, 0, r), array(board, r+1))
      // add empty row on top
      newRow = []
      for (c=0; c<COLS; c++) push(newRow, 0)
      board.unshift(newRow)
    } else {
      r--
    }
  }
  // Score
  if (lines==1) score += 100
  else if (lines==2) score += 300
  else if (lines==3) score += 500
  else if (lines==4) score += 800
  linesCleared += lines
  level = floor(linesCleared/10)
}

function placePiece() {
  lockPiece()
  clearLines()
  spawnPiece()
}

// Hard drop
function hardDrop() {
  while(!collides(pieceX, pieceY+1, piece.blocks)) pieceY++
  placePiece()
}

spawnPiece()

var update = function(dt) {
  if (gameOver) return

  // ======= Horizontal Movement Gate =======
  var leftPressed = input.keyboard.down('a')
  var rightPressed = input.keyboard.down('d')
  var horizontalMove = 0

  // If user just pressed A, move once & start gating
  if (leftPressed && !prevLeft) {
    horizontalMove = -1
    hMoveTimer = hDelay
  }
  // If user is holding A & the timer is up, move again, then reset timer to repeat
  else if (leftPressed && hMoveTimer <= 0) {
    horizontalMove = -1
    hMoveTimer = hRepeat
  }

  // Same logic for D
  if (rightPressed && !prevRight) {
    horizontalMove = 1
    hMoveTimer = hDelay
  } else if (rightPressed && hMoveTimer <= 0) {
    horizontalMove = 1
    hMoveTimer = hRepeat
  }

  // Move horizontally if it doesn't collide
  if (horizontalMove < 0 && !collides(pieceX-1, pieceY, piece.blocks)) pieceX--
  else if (horizontalMove > 0 && !collides(pieceX+1, pieceY, piece.blocks)) pieceX++

  // If neither A nor D is pressed, reset the timer so next press is immediate
  if (!leftPressed && !rightPressed) {
    hMoveTimer = 0
  }

  // Decrement horizontal timer
  hMoveTimer -= dt
  prevLeft = leftPressed
  prevRight = rightPressed
  // ======= End Horizontal Movement Gate =======

  // Rotate with W (once per press, no spinning)
  var test = null;
  if (input.keyboard.down('w')) {
    if (!rotateHeld) {
      rotateHeld = true
      test = array(piece.blocks, b => [b[0], b[1]])
      rotate(test)
      if (!collides(pieceX, pieceY, test)) piece.blocks = test
    }
  } else {
    rotateHeld = false
  }

  // Soft drop if S is held (accelerates gravity)
  var fallSpeed = input.keyboard.down('s') ? 10 : 1

  // Gravity
  gravityTimer += dt * fallSpeed
  var dropInterval = max(0.1, baseGravity - level*0.05)
  if (gravityTimer >= dropInterval) {
    gravityTimer = 0
    if (!collides(pieceX, pieceY+1, piece.blocks)) {
      pieceY++
    } else {
      placePiece()
    }
  }

  // Hard drop if space is held
  if (input.keyboard.down('space')) {
//    hardDrop()
  }
}

var hud = function() {
  // Clear screen
  draw.rectangle({x:0, y:0, width:config.width, height:config.height}, [0,0,0,1])

  // Draw board
  var r = 0;
  var c = 0;
  var cell = null;
  var i = 0;
  var x = 0;
  var y = 0;
  var nx = 0;
  var ny = 0;
  var dx = 0;
  var dy = 0;
  for (r=0; r<ROWS; r++) {
    for (c=0; c<COLS; c++) {
      cell = board[r][c]
      if (!cell) continue
      draw.rectangle({x:c*TILE, y:(ROWS-1-r)*TILE, width:TILE, height:TILE}, cell)
    }
  }

  // Draw falling piece
  if (!gameOver && piece) {
    for (i=0; i<length(piece.blocks); i++) {
      x = pieceX + piece.blocks[i][0]
      y = pieceY + piece.blocks[i][1]
      draw.rectangle({x:x*TILE, y:(ROWS-1-y)*TILE, width:TILE, height:TILE}, piece.color)
    }
  }

  // Next piece window
  draw.text("Next", {x:70, y:5, width:50, height:10}, null, 0, color.white)
  if (nextPiece) {
    for (i=0; i<length(nextPiece.blocks); i++) {
      nx = nextPiece.blocks[i][0]
      ny = nextPiece.blocks[i][1]
      dx = 12 + nx
      dy = 16 - ny
      draw.rectangle({x:dx*TILE, y:(ROWS-1-dy)*TILE, width:TILE, height:TILE}, nextPiece.color)
    }
  }

  // Score & Level
  var info = "Score: " + score + "\nLines: " + linesCleared + "\nLevel: " + level
  draw.text(info, {x:70, y:30, width:90, height:50}, null, 0, color.white)

  if (gameOver) {
    draw.text("GAME OVER", {x:10, y:config.height*0.5-5, width:config.width-20, height:20}, null, 0, color.red)
  }
}
