module BookKeeping
  VERSION = 4
end

class TwoBucket
  attr_reader :goal_bucket, :other_bucket

  def initialize(first_size, second_size, goal, start_bucket)
    @first_size = first_size
    @second_size = second_size
    @goal = goal
    @start_bucket = start_bucket
  end

  def moves
    if @start_bucket == 'one'
      @levels = [@first_size, 0]
      strategy = method(:start_from_first)
    else
      @levels = [0, @second_size]
      strategy = method(:start_from_second)
    end
    if other_bucket_matches_goal
      strategy = method(:fill_other_bucket)
    end
    solve strategy
  end

  private

  def solve(strategy)
    moves_count = 1

    loop do
      return moves_count if solved?
      strategy.call
      moves_count += 1
    end
  end

  def solved?
    if @levels.any? { |level| level == @goal }
      if @levels.first == @goal
        @goal_bucket = 'one'
        @other_bucket = @levels.last
      else
        @goal_bucket = 'two'
        @other_bucket = @levels.first
      end

      true
    end
  end

  def start_from_first
    if first_bucket_empty?
      fill_first_bucket
    elsif second_bucket_full?
      empty_second_bucket
    elsif can_move_to_second_bucket?
      fill_second_bucket_from_first
    end
  end

  def start_from_second
    if first_bucket_full?
      empty_first_bucket
    elsif second_bucket_empty?
      fill_second_bucket
    elsif can_move_to_first_bucket?
      fill_first_bucket_from_second
    end
  end

  def fill_other_bucket
    if first_bucket_empty?
      fill_first_bucket
    else
      fill_second_bucket
    end
  end

  def other_bucket_matches_goal
    if @start_bucket == 'one'
      @second_size == @goal
    else
      @first_size == @goal
    end
  end

  def first_bucket_empty?
    @levels.first == 0
  end

  def first_bucket_full?
    @levels.first == @first_size
  end

  def second_bucket_empty?
    @levels.last == 0
  end

  def second_bucket_full?
    @levels.last == @second_size
  end

  def can_move_to_second_bucket?
    (first_bucket_full? && !second_bucket_full?) ||
      (!first_bucket_full? && second_bucket_empty?)
  end

  def can_move_to_first_bucket?
    @levels.reduce(:+) != @first_size
  end

  def empty_first_bucket
    @levels[0] = 0
  end

  def fill_first_bucket
    @levels[0] = @first_size
  end

  def empty_second_bucket
    @levels[1] = 0
  end

  def fill_second_bucket
    @levels[1] = @second_size
  end

  def fill_first_bucket_from_second
    @levels = [@levels.reduce(:+), @first_size].min,
              [@levels.reduce(:+) - @first_size, 0].max
  end

  def fill_second_bucket_from_first
    @levels = [@levels.reduce(:+) - @second_size, 0].max,
              [@levels.reduce(:+), @second_size].min
  end
end