// src/game.mbt
// Core game logic for MoonTetris

pub struct Game {
  pub width : Int
  pub height : Int
  pub board : Array[Array[Int]] // 0 empty, >0 index of color/kind
  pub mut current_x : Int
  pub mut current_y : Int
  pub mut current_kind : Int
  pub mut current_rotation : Int
  pub mut next_kind : Int
  pub mut hold_kind : Int // 0 if empty, 1..7 for kinds
  pub mut can_hold : Bool
  pub mut score : Int
  pub mut lines : Int
  pub mut level : Int
  pub mut game_over : Bool
  pub mut seed : Int
}

pub fn get_block_raw(kind : Int, row : Int, col : Int) -> Bool {
  match kind {
    1 => // I: size 4
      row == 1
    2 => // O: size 2
      true
    3 => // T: size 3
      (row == 0 && col == 1) || (row == 1 && (col == 0 || col == 1 || col == 2))
    4 => // S: size 3
      (row == 0 && (col == 1 || col == 2)) || (row == 1 && (col == 0 || col == 1))
    5 => // Z: size 3
      (row == 0 && (col == 0 || col == 1)) || (row == 1 && (col == 1 || col == 2))
    6 => // J: size 3
      (row == 0 && col == 0) || (row == 1 && (col == 0 || col == 1 || col == 2))
    7 => // L: size 3
      (row == 0 && col == 2) || (row == 1 && (col == 0 || col == 1 || col == 2))
    _ => false
  }
}

pub fn get_block(kind : Int, rotation : Int, row : Int, col : Int) -> Bool {
  let n = if kind == 1 { 4 } else if kind == 2 { 2 } else { 3 }
  let (r, c) = match rotation % 4 {
    0 => (row, col)
    1 => (col, n - 1 - row)
    2 => (n - 1 - row, n - 1 - col)
    3 => (n - 1 - col, row)
    _ => (row, col) // unreachable
  }
  get_block_raw(kind, r, c)
}

pub fn Game::new() -> Game {
  let board = Array::make(20, Array::make(10, 0))
  for r = 0; r < 20; r = r + 1 {
    board[r] = Array::make(10, 0)
  }
  let mut seed = 12345
  seed = (seed * 1103515245 + 12345) & 0x7fffffff
  let current_kind = (seed % 7) + 1
  seed = (seed * 1103515245 + 12345) & 0x7fffffff
  let next_kind = (seed % 7) + 1
  
  {
    width: 10,
    height: 20,
    board,
    current_x: 3,
    current_y: -1,
    current_kind,
    current_rotation: 0,
    next_kind,
    hold_kind: 0,
    can_hold: true,
    score: 0,
    lines: 0,
    level: 1,
    game_over: false,
    seed,
  }
}

pub fn Game::next_random_kind(self : Game) -> Int {
  self.seed = (self.seed * 1103515245 + 12345) & 0x7fffffff
  (self.seed % 7) + 1
}

pub fn Game::check_collision(self : Game, new_x : Int, new_y : Int, rotation : Int) -> Bool {
  let kind = self.current_kind
  let n = if kind == 1 { 4 } else if kind == 2 { 2 } else { 3 }
  for r = 0; r < n; r = r + 1 {
    for c = 0; c < n; c = c + 1 {
      if get_block(kind, rotation, r, c) {
        let board_x = new_x + c
        let board_y = new_y + r
        if board_x < 0 || board_x >= 10 || board_y >= 20 {
          return true
        }
        if board_y >= 0 {
          if self.board[board_y][board_x] != 0 {
            return true
          }
        }
      }
    }
  }
  false
}

pub fn Game::spawn(self : Game) -> Unit {
  self.current_kind = self.next_kind
  self.next_kind = self.next_random_kind()
  self.current_rotation = 0
  self.current_x = 3
  self.current_y = -1
  self.can_hold = true
  if self.check_collision(self.current_x, self.current_y, self.current_rotation) {
    self.game_over = true
    play_sound(3) // Game Over sound
  }
}

pub fn Game::move_left(self : Game) -> Bool {
  if self.game_over { return false }
  if not(self.check_collision(self.current_x - 1, self.current_y, self.current_rotation)) {
    self.current_x = self.current_x - 1
    play_sound(1) // Move sound
    true
  } else {
    false
  }
}

pub fn Game::move_right(self : Game) -> Bool {
  if self.game_over { return false }
  if not(self.check_collision(self.current_x + 1, self.current_y, self.current_rotation)) {
    self.current_x = self.current_x + 1
    play_sound(1) // Move sound
    true
  } else {
    false
  }
}

pub fn Game::rotate(self : Game) -> Bool {
  if self.game_over { return false }
  let next_rot = (self.current_rotation + 1) % 4
  
  // Try direct rotation
  if not(self.check_collision(self.current_x, self.current_y, next_rot)) {
    self.current_rotation = next_rot
    play_sound(1) // Rotate sound
    return true
  }
  
  // Basic Wall Kick
  let kicks = [(-1, 0), (1, 0), (0, -1), (-2, 0), (2, 0)]
  for i = 0; i < 5; i = i + 1 {
    let (dx, dy) = kicks[i]
    if not(self.check_collision(self.current_x + dx, self.current_y + dy, next_rot)) {
      self.current_x = self.current_x + dx
      self.current_y = self.current_y + dy
      self.current_rotation = next_rot
      play_sound(1) // Rotate sound
      return true
    }
  }
  
  false
}

pub fn Game::soft_drop(self : Game) -> Bool {
  if self.game_over { return false }
  if not(self.check_collision(self.current_x, self.current_y + 1, self.current_rotation)) {
    self.current_y = self.current_y + 1
    true
  } else {
    self.lock_piece()
    false
  }
}

pub fn Game::hard_drop(self : Game) -> Unit {
  if self.game_over { return }
  while not(self.check_collision(self.current_x, self.current_y + 1, self.current_rotation)) {
    self.current_y = self.current_y + 1
  }
  play_sound(4) // Drop sound
  self.lock_piece()
}

pub fn Game::hold(self : Game) -> Unit {
  if self.game_over || not(self.can_hold) { return }
  let temp = self.current_kind
  if self.hold_kind == 0 {
    self.hold_kind = temp
    self.spawn()
  } else {
    self.current_kind = self.hold_kind
    self.hold_kind = temp
    self.current_rotation = 0
    self.current_x = 3
    self.current_y = -1
  }
  self.can_hold = false
  play_sound(1)
}

pub fn Game::lock_piece(self : Game) -> Unit {
  let kind = self.current_kind
  let n = if kind == 1 { 4 } else if kind == 2 { 2 } else { 3 }
  for r = 0; r < n; r = r + 1 {
    for c = 0; c < n; c = c + 1 {
      if get_block(kind, self.current_rotation, r, c) {
        let board_y = self.current_y + r
        let board_x = self.current_x + c
        if board_y >= 0 && board_y < 20 && board_x >= 0 && board_x < 10 {
          self.board[board_y][board_x] = kind
        }
      }
    }
  }
  self.clear_lines()
  self.spawn()
}

pub fn Game::clear_lines(self : Game) -> Unit {
  let mut cleared = 0
  
  for r = 19; r >= 0; r = r - 1 {
    let mut full = true
    for c = 0; c < 10; c = c + 1 {
      if self.board[r + cleared][c] == 0 {
        full = false
        break
      }
    }
    
    if full {
      cleared = cleared + 1
    } else if cleared > 0 {
      for c = 0; c < 10; c = c + 1 {
        self.board[r + cleared][c] = self.board[r][c]
      }
    }
  }
  
  if cleared > 0 {
    for r = 0; r < cleared; r = r + 1 {
      for c = 0; c < 10; c = c + 1 {
        self.board[r][c] = 0
      }
    }
    
    self.lines = self.lines + cleared
    let score_add = match cleared {
      1 => 100 * self.level
      2 => 300 * self.level
      3 => 500 * self.level
      4 => 800 * self.level
      _ => 0
    }
    self.score = self.score + score_add
    self.level = (self.lines / 10) + 1
    play_sound(2) // Line clear sound
  }
}

pub fn Game::tick(self : Game) -> Unit {
  if self.game_over { return }
  let _ = self.soft_drop()
}
fn main { }