require 'dare'

class Paddle

  attr_reader :x, :y, :width, :height

  def initialize(game, side)
    @game = game
    @side = side
    @x = 20
    @y = Game::HEIGHT/2
    @width = 30
    @height = 80
  end

  def draw
    @game.draw_rect(
      top_left: [@x,@y-@height/2],
      width: @width,
      height: @height,
      color: 'red'
    )
  end

  def update
    @y = @game.mouse_y || Game::HEIGHT/2
    if @y < @height/2
      @y = @height/2
    end
    if @y > Game::HEIGHT - @height/2
      @y = Game::HEIGHT - @height/2
    end
  end

end

class Ball

  def initialize(game)
    reset!
    @size = 10
    @game = game
  end

  def draw
    @game.draw_rect(
      top_left: [@x-@size,@y-@size],
      width: 2*@size,
      height: 2*@size,
      color: 'red'
    )
  end

  def update
    check_bounds
    if overlapped_with(@game.paddles[0])
      @angle = (180.0-@angle)
      @game.boops[:paddle].play
    end
    travel_distance = @speed*(Dare.ms-@birth)/16.666666
    @x += Dare.offset_x(@angle, travel_distance)
    @y += Dare.offset_y(@angle, travel_distance)
    @birth = Dare.ms
  end

  def check_bounds
    if (@x > Game::WIDTH)
      @game.score += 1
      reset!
    end
    if (@x < 0)
      reset!
    end
    if (@y > Game::HEIGHT-@size) || (@y < 0+@size)
      @angle = 360.0-@angle
      @game.boops[:wall].play
    end
  end

  def overlapped_with(paddle)
    left_side_of_ball_past_right_side_of_paddle(paddle) &&
    right_side_of_ball_past_left_side_of_paddle(paddle) &&
    top_of_ball_past_bottom_of_paddle(paddle) &&
    bottom_of_ball_past_top_of_paddle(paddle)
  end

  def left_side_of_ball_past_right_side_of_paddle(paddle)
    (@x-@size) < (paddle.x+paddle.width)
  end

  def right_side_of_ball_past_left_side_of_paddle(paddle)
    (@x+@size) > (paddle.x-paddle.width)
  end

  def top_of_ball_past_bottom_of_paddle(paddle)
    (@y+@size) < paddle.y+paddle.height/2
  end

  def bottom_of_ball_past_top_of_paddle(paddle)
    (@y-@size) > paddle.y-paddle.height/2
  end

  def reset!
    @x = Game::WIDTH/2.0
    @y = Game::HEIGHT/2.0+5
    @angle = 90.0*rand - 45.0
    @angle = @angle+180.0 if rand > 0.5
    @birth = Dare.ms
    @speed = 10.0
  end

end

class Game < Dare::Window

  WIDTH = 1024
  HEIGHT = 768

  attr_reader :paddles, :boops
  attr_accessor :score

  def initialize
    super width: WIDTH, height: HEIGHT, border: true
    @ball = Ball.new(self)
    @paddles = []
    @paddles[0] = Paddle.new(self, :left)
    @paddles[1] = Paddle.new(self, :right)
    @boops = {}
    @boops[:paddle] = Dare::Sound.new('assets/pong_bounce.mp3', volume: 0.3)
    @boops[:wall] = Dare::Sound.new('assets/wall_bounce.mp3', volume: 0.3)
    @score_font = Dare::Font.new
    @score = 10
  end

  def draw
    @ball.draw
    @paddles[0].draw
    @score_font.draw(@score)
  end

  def update
    @ball.update
    @paddles[0].update
  end

end

Game.new.run!