''' Implement an AI to play tetris '''
from random import Random
from te_settings import Direction
import time

class Search():
    def __init__(self):
        self.testvar = None
        self.doSearch = True
        self.lastSearchY = 20
        

    def isNewBlock(self, gamestate):
        #print(f"isNewBlock called || lastY: {self.lastSearchY} - currentY: {gamestate.get_falling_block_position()[1]}")
        if(self.lastSearchY > gamestate.get_falling_block_position()[1]):
            self.doSearch = True
        self.lastSearchY = gamestate.get_falling_block_position()[1]
        
        
        
        
        
    def estScore(self, tstate):
        self.tiles = tstate.get_tiles()
        #daa.print_tiles()
        self.score = 0
        self.highestPt = 19
        self.covered = False
        
        #print(f"estinmating score for {self.tiles}")
        
        for rowNum, row in enumerate(self.tiles):
            self.rowFilled = 0
            for colNum, column in enumerate(row):
                if column != 0:        #if that spot is filled
                    self.score += rowNum#score gets higher when more blocks on row
                    self.rowFilled += 1
                    if rowNum<self.highestPt:
                        self.highestPt = rowNum
                else:                  #otherwise if it's empty
                    
                    for i in range(rowNum, 0, -1):
                        if self.tiles[i][colNum] != 0:  #if there is a block above the hole
                            self.covered = True
                            break
                        if self.covered == True:
                            self.score -= 50
                            self.covered = False
            self.score -= (20-self.highestPt)
            
            if self.rowFilled == 10:
                self.score += 100#score gets improved if it allows to fill out an entire row
                
                
            #need to figure out a way to calculate holes that is covered.
        
                
                
                
                
            #print(f"total score at row number {rowNum}:{self.score}pts")
            #self.score = 0
        print(self.score)
        #time.sleep(1)
        return self.score
            
    
    
    
    
    def testMove(self, gamestate, shift, rotate):
        #print(f"\n======================================\ntestMove called -- testing s{shift}r{rotate}")
        self.oldY = 0
        tstate = gamestate.clone(True)
        while(shift!=0 or rotate!=0 or tstate.get_falling_block_position()[1] > self.oldY):
            #print(f"in testMove. s:{shift} r:{rotate} y:{tstate.get_falling_block_position()[1]}")
            #time.sleep(0.1)
            if shift < 0:
                #something
                tstate.move(Direction.LEFT)
                shift += 1
            elif shift > 0:
                tstate.move(Direction.RIGHT)
                shift -= 1
                #something
            #else: we do nothing.
                
            if rotate != 0:
                tstate.rotate(Direction.RIGHT)
                rotate -= 1
            self.oldY = tstate.get_falling_block_position()[1]
            tstate.update()
            
        tstate.print_tiles()
        #print(f"testMove completed")
        
        
        return self.estScore(tstate)
                
                
    def findBestMove(self, gamestate):
        #print("findBestMove called")
        self.best = 0
        self.bestMove = None
        #print(f"lastY: {self.lastSearchY} - currentY: {gamestate.get_falling_block_position()[1]}")
        self.lastSearchY = gamestate.get_falling_block_position()[1]
        #if(self.doSearch == True):
        #test all possible moves
        moves = []
        for mvnum in range(-5,6):
            for rotnum in range(0,4):
                #self.testMove(gamestate, mvnum, rotnum)
                moves.append([mvnum, rotnum, self.testMove(gamestate, mvnum, rotnum)])
        #gamestate.print_tiles()
        print(moves)
        
        #find highest score from list of possible moves
        for listNum, lists in enumerate(moves):
            if lists[2] > self.best:
                self.best = lists[2]
                self.bestMove = listNum
        self.doSearch = False
        if self.best == 0:
            return (-3,0)
        else:
            print(f"\n\n======\nbest moves are: {moves[self.bestMove][0]} shift, {moves[self.bestMove][1]} rotate\n======")
            return (moves[self.bestMove][0], moves[self.bestMove][1])
            
        
class AutoPlayer():
    ''' A very simple dumb AutoPlayer controller '''
    def __init__(self, controller):
        self.controller = controller
        self.rand = Random()
        self.previousState = None
        self.search = Search()
        self.nextMove = None
        self.doShift = 0
        self.doRotate = 0
        
        

    def next_move(self, gamestate):
        ''' next_move() is called by the game, once per move.
            gamestate supplies access to all the state needed to autoplay the game.'''
        #self.search.isNewBlock(gamestate)
        #if self.search.doSearch == True:
        self.nextMove = self.search.findBestMove(gamestate)
        self.doShift = self.nextMove[0]
        self.doRotate = self.nextMove[1]
        self.doMove(gamestate, self.doShift, self.doRotate)


    def doMove(self, gamestate, shift, rotation):
        if shift < 0:
            #something
            gamestate.move(Direction.LEFT)
            shift += 1
        elif shift > 0:
            gamestate.move(Direction.RIGHT)
            shift -= 1
            #something
        #else: we do nothing.
            
        if rotation != 0:
            gamestate.rotate(Direction.RIGHT)
            rotation -= 1

    def random_next_move(self, gamestate):
        ''' make a random move and a random rotation.  Not the best strategy! '''
        rnd = self.rand.randint(-1, 1)
        if rnd == -1:
            direction = Direction.LEFT
        elif rnd == 1:
            direction = Direction.RIGHT
        if rnd != 0:
            gamestate.move(direction)
        rnd = self.rand.randint(-1, 1)
        if rnd == -1:
            direction = Direction.LEFT
        elif rnd == 1:
            direction = Direction.RIGHT
        if rnd != 0:
            gamestate.rotate(direction)
