import asyncio
from multiprocessing import Queue
import pygame
import time
from pygame.math import Vector2


class Waiter(object):

    def __init__(self, game, x, y):
        self.game = game
        self.grid = game.grid
        game.idItem += 1
        self.size= self.game.screen.get_size()
        self.x = x
        self.y = y
        self.positionX = int(x / 50)
        self.positionY = int(y / 50)
        self.image = pygame.image.load("./Images/waiter.png").convert()
        self.image.set_colorkey((255, 255, 255))
        self.type = "waiter"
        self.lastStep = []
        self.whatKeep = 0

        self.dfsStack = []
        self.dfsPaths = []


        self.bfsQueue = []
        self.bfsPaths = []

    # NIEUZYWANA FUNKCJA ZNAJDOWANIA KELNERA NA PLANSZY; ZWRACA POZYCJĘ KELNERA
    def findWaiter(self, grid):
        for y in range(10):
            for x in range(10):
                if grid[y][x].type =="waiter":
                    #print(x,y)
                    return [x, y]


    def moveLeft(self):
        if self.positionX != 0:
            collisionObject = self.game.grid[self.positionY][self.positionX - 1]
            if collisionObject.type == "gridElement":
                self.game.grid[self.positionY][self.positionX - 1].x += 50
                self.game.grid[self.positionY][self.positionX].x -= 50
                self.game.grid[self.positionY][self.positionX - 1], \
                self.game.grid[self.positionY][self.positionX] = \
                self.game.grid[self.positionY][self.positionX], \
                self.game.grid[self.positionY][self.positionX - 1]
                self.positionX -= 1
                #print(self.positionX)
                self.lastStep.append("Left")
            else:
                self.work(collisionObject)
    def moveRight(self):
        if self.positionX != self.game.x-1:
            collisionObject = self.game.grid[self.positionY][self.positionX + 1]
            if collisionObject.type == "gridElement":
                self.game.grid[self.positionY][self.positionX + 1].x -= 50
                self.game.grid[self.positionY][self.positionX].x += 50
                self.game.grid[self.positionY][self.positionX + 1], \
                self.game.grid[self.positionY][self.positionX] = \
                    self.game.grid[self.positionY][self.positionX], \
                    self.game.grid[self.positionY][self.positionX + 1]
                self.positionX += 1
                #print(self.positionX)
                self.lastStep.append("Right")
            else:
                self.work(collisionObject)

    def moveUp(self):
        if self.positionY != 0:
            collisionObject = self.game.grid[self.positionY - 1][self.positionX]
            if collisionObject.type == "gridElement":
                self.game.grid[self.positionY - 1][self.positionX].y += 50
                self.game.grid[self.positionY][self.positionX].y -= 50
                self.game.grid[self.positionY - 1][self.positionX], \
                self.game.grid[self.positionY][self.positionX] = \
                self.game.grid[self.positionY][self.positionX], \
                self.game.grid[self.positionY - 1][self.positionX]
                self.positionY -= 1
                self.lastStep.append("Up")
            else:
                self.work(collisionObject)

    def moveDown(self):
        if self.positionY != self.game.y-1:
            collisionObject = self.game.grid[self.positionY + 1][self.positionX]
            if collisionObject.type == "gridElement":
                self.game.grid[self.positionY + 1][self.positionX].y -= 50
                self.game.grid[self.positionY][self.positionX].y += 50
                self.game.grid[self.positionY + 1][self.positionX], \
                self.game.grid[self.positionY][self.positionX] = \
                    self.game.grid[self.positionY][self.positionX], \
                    self.game.grid[self.positionY + 1][self.positionX]
                self.positionY += 1
                self.lastStep.append("Down")
            else:
                self.work(collisionObject)


    # SPRAWDZA NACIŚNIĘTE KLAWISZE
    def move(self, game):
        keys = pygame.key.get_pressed()

        if keys[pygame.K_LEFT]:
            self.moveLeft()
        if keys[pygame.K_RIGHT]:
            self.moveRight()
        if keys[pygame.K_UP]:
            self.moveUp()
        if keys[pygame.K_DOWN]:
            self.moveDown()
        if keys[pygame.K_s]:
            game.showGrid(game.grid)


    def draw(self):
        self.rect1 = pygame.Rect(self.x, self.y, 50, 50)
        pygame.draw.rect(self.game.screen, (0, 150, 255), self.rect1)
        if self.whatKeep == 0:
            self.game.screen.blit(self.image, (self.x, self.y))
        elif self.whatKeep == 1:
            self.game.screen.blit(pygame.image.load("./Images/waiterJedzenie.png"), (self.x, self.y))
        elif self.whatKeep == 2:
            self.game.screen.blit(pygame.image.load("./Images/waiterBrudneTalerze.png"), (self.x, self.y))

    # SPRAWDZA CZY ELELEMNT, KTORY POBIERAMY NIE JEST SPOZA PLANSZY
    def isMoveInRange(self, move, position):

        positionX = position[0]
        positionY = position[1]

        if move == "Left":
            if positionX  == 0:
                return False
        if move == "Right":
            if positionX == 9:
                return False
        if move == "Up":
            if positionY == 0:
                return False
        if move == "Down":
            if positionY == 9:
                return False
        return True
    # SPRAWDZA MOZLIWOSCI RUCHU ZGODNIE Z OSTATNIM RUCHEM
    def checkPoss(self, position, lastOperation):

        stackMove = []

        positionX = position[0]
        positionY = position[1]

        if len(lastOperation) == 0:
            if self.isMoveInRange("Up", position):
                collisionObjectUp = self.grid[positionY - 1][positionX]
                if collisionObjectUp.type == "gridElement" or collisionObjectUp.type == "waiter":
                    stackMove.append("Up")
            if self.isMoveInRange("Down", position):
                collisionObjectDown = self.grid[positionY + 1][positionX]
                if collisionObjectDown.type == "gridElement":
                    stackMove.append("Down")
            if self.isMoveInRange("Left", position):
                collisionObjectLeft = self.grid[positionY][positionX - 1]
                if collisionObjectLeft.type == "gridElement" or collisionObjectLeft.type == "waiter":
                    stackMove.append("Left")
            if self.isMoveInRange("Right", position):
                collisionObjectRight = self.grid[positionY][positionX + 1]
                if collisionObjectRight.type == "gridElement" or collisionObjectRight.type == "waiter":
                    stackMove.append("Right")
            return stackMove
        else:
            last = lastOperation[-1]
            if last == "Left":
                if self.isMoveInRange("Up", position):
                    collisionObjectUp = self.grid[positionY - 1][positionX]
                    if collisionObjectUp.type == "gridElement":
                        stackMove.append("Up")
                if self.isMoveInRange("Down", position):
                    collisionObjectDown = self.grid[positionY + 1][positionX]
                    if collisionObjectDown.type == "gridElement":
                        stackMove.append("Down")
                if self.isMoveInRange("Left", position):
                    collisionObjectLeft = self.grid[positionY][positionX - 1]
                    if collisionObjectLeft.type == "gridElement":
                        stackMove.append("Left")

                return stackMove

            if last == "Right":
                if self.isMoveInRange("Up", position):
                    collisionObjectUp = self.grid[positionY - 1][positionX]
                    if collisionObjectUp.type == "gridElement":
                        stackMove.append("Up")
                if self.isMoveInRange("Down", position):
                    collisionObjectDown = self.grid[positionY + 1][positionX]
                    if collisionObjectDown.type == "gridElement":
                        stackMove.append("Down")

                if self.isMoveInRange("Right", position):
                    collisionObjectRight = self.grid[positionY][positionX + 1]
                    if collisionObjectRight.type == "gridElement":
                        stackMove.append("Right")
                return stackMove

            if last == "Up":
                if self.isMoveInRange("Up", position):
                    collisionObjectUp = self.grid[positionY - 1][positionX]
                    if collisionObjectUp.type == "gridElement":
                        stackMove.append("Up")

                if self.isMoveInRange("Left", position):
                    collisionObjectLeft = self.grid[positionY][positionX - 1]
                    if collisionObjectLeft.type == "gridElement":
                        stackMove.append("Left")
                if self.isMoveInRange("Right", position):
                    collisionObjectRight = self.grid[positionY][positionX + 1]
                    if collisionObjectRight.type == "gridElement":
                        stackMove.append("Right")
                return stackMove

            if last == "Down":

                if self.isMoveInRange("Down", position):
                    collisionObjectDown = self.grid[positionY + 1][positionX]
                    if collisionObjectDown.type == "gridElement":
                        stackMove.append("Down")
                if self.isMoveInRange("Left", position):
                    collisionObjectLeft = self.grid[positionY][positionX - 1]
                    if collisionObjectLeft.type == "gridElement":
                        stackMove.append("Left")
                if self.isMoveInRange("Right", position):
                    collisionObjectRight = self.grid[positionY][positionX + 1]
                    if collisionObjectRight.type == "gridElement":
                        stackMove.append("Right")
                return stackMove
    # DFS
    def dfsFind(self, position, currentOperation, visited, idTable):
        #print("Sprawdzam czy stolik")

        positionX = position[0]
        positionY = position[1]
        #print("Pozycja kelnera: ", position)
        if self.isMoveInRange("Up", position):
            if self.grid[positionY - 1][positionX].type == "table":
                if self.grid[positionY - 1][positionX].id == idTable:
                    self.dfsPaths.append(currentOperation)
                    print("Dodalem sciezke: ", currentOperation)
                    return 0
        if self.isMoveInRange("Down", position):
            if self.grid[positionY + 1][positionX].type == "table":
                if self.grid[positionY + 1][positionX].id == idTable:
                    self.dfsPaths.append(currentOperation)
                    print("Dodalem sciezke: ", currentOperation)
                    return 0
        if self.isMoveInRange("Left", position):
            if self.grid[positionY][positionX - 1].type == "table":
                if self.grid[positionY][positionX - 1].id == idTable:
                    self.dfsPaths.append(currentOperation)
                    print("Dodalem sciezke: ", currentOperation)
                    return 0
        if self.isMoveInRange("Right", position):
            if self.grid[positionY][positionX + 1].type == "table":
                if self.grid[positionY][positionX + 1].id == idTable:
                    self.dfsPaths.append(currentOperation)
                    print("Dodalem sciezke: ", currentOperation)
                    return 0
        # print("Sprawdzilem nie jest to stolik")
        steps = []
        steps.append(self.checkPoss(position, currentOperation))
        allstep = steps[-1]
        # print("Naszymi mozliwosciami sa ", allstep)

        if not allstep:
            return 0
        else:
            for step in allstep:
                newCurrentOperation = currentOperation[:]
                newCurrentOperation.append(step)
                newPosition = position[:]
                newVisited = visited[:]

                #print("newVisited", newVisited)
                if step == "Left":
                    if [newPosition[0] - 1, newPosition[1]] in visited:
                        # print("Tam gdzie chce isc bylem juz: ", step)
                        continue
                    newPosition[0] -= 1
                    if len(self.checkPoss(newPosition, newCurrentOperation)) == 1:
                        newVisited.append(newPosition)

                elif step == "Right":
                    if [newPosition[0] + 1, newPosition[1]] in visited:
                        # print("Tam gdzie chce isc bylem juz: ", step)
                        continue
                    newPosition[0] += 1
                    if len(self.checkPoss(newPosition, newCurrentOperation)) == 1:
                        newVisited.append(newPosition)
                elif step == "Up":
                    if [newPosition[0], newPosition[1] - 1] in visited:
                        # print("Tam gdzie chce isc bylem juz: ", step)
                        continue
                    newPosition[1] -= 1
                    if len(self.checkPoss(newPosition, newCurrentOperation)) == 1:
                        newVisited.append(newPosition)
                else:
                    if [newPosition[0], newPosition[1] + 1] in visited:
                        # print("Tam gdzie chce isc bylem juz: ", step)
                        continue
                    newPosition[1] += 1
                    if len(self.checkPoss(newPosition, newCurrentOperation)) == 1:
                        newVisited.append(newPosition)
                self.dfsStack.append([newPosition, newCurrentOperation, newVisited, idTable])
            while self.dfsStack:
                move = self.dfsStack.pop()
                self.dfsFind(move[0], move[1], move[2], move[3])
    # BFS
    def bfsFind(self, position, currentOperation, visited, idTable):
        #print("Sprawdzam czy stolik")

        positionX = position[0]
        positionY = position[1]
        # print("Pozycja kelnera: ", position)
        if self.isMoveInRange("Up", position):
            if self.grid[positionY - 1][positionX].type == "table":
                if self.grid[positionY - 1][positionX].id == idTable:
                    currentOperation.append("Up")
                    self.bfsPaths.append(currentOperation)
                    print("Dodalem sciezke: ", currentOperation)
                    return 0
        if self.isMoveInRange("Down", position):
            if self.grid[positionY + 1][positionX].type == "table":
                if self.grid[positionY + 1][positionX].id == idTable:
                    currentOperation.append("Down")
                    self.bfsPaths.append(currentOperation)
                    print("Dodalem sciezke: ", currentOperation)
                    return 0
        if self.isMoveInRange("Left", position):
            if self.grid[positionY][positionX - 1].type == "table":
                if self.grid[positionY][positionX - 1].id == idTable:
                    currentOperation.append("Left")
                    self.bfsPaths.append(currentOperation)
                    print("Dodalem sciezke: ", currentOperation)
                    return 0
        if self.isMoveInRange("Right", position):
            if self.grid[positionY][positionX + 1].type == "table":
                if self.grid[positionY][positionX + 1].id == idTable:
                    currentOperation.append("Right")
                    self.bfsPaths.append(currentOperation)
                    print("Dodalem sciezke: ", currentOperation)
                    return 0
        # print("Sprawdzilem nie jest to stolik")
        steps = []
        steps.append(self.checkPoss(position, currentOperation))
        allstep = steps[-1]
        # print("Naszymi mozliwosciami sa ", allstep)

        if not allstep:
            return 0
        else:
            for step in allstep:
                newCurrentOperation = currentOperation[:]
                newCurrentOperation.append(step)
                newPosition = position[:]
                newVisited = visited[:]
                # print("newVisited", newVisited)
                if step == "Left":
                    if [newPosition[0] - 1, newPosition[1]] in visited:
                        # print("Tam gdzie chce isc bylem juz: ", step)
                        continue
                    newPosition[0] -= 1
                    if len(self.checkPoss(newPosition, newCurrentOperation)) == 1:
                        newVisited.append(newPosition)

                elif step == "Right":
                    if [newPosition[0] + 1, newPosition[1]] in visited:
                        # print("Tam gdzie chce isc bylem juz: ", step)
                        continue
                    newPosition[0] += 1
                    if len(self.checkPoss(newPosition, newCurrentOperation)) == 1:
                        newVisited.append(newPosition)
                elif step == "Up":
                    if [newPosition[0], newPosition[1] - 1] in visited:
                        # print("Tam gdzie chce isc bylem juz: ", step)
                        continue
                    newPosition[1] -= 1
                    if len(self.checkPoss(newPosition, newCurrentOperation)) == 1:
                        newVisited.append(newPosition)
                else:
                    if [newPosition[0], newPosition[1] + 1] in visited:
                        # print("Tam gdzie chce isc bylem juz: ", step)
                        continue
                    newPosition[1] += 1
                    if len(self.checkPoss(newPosition, newCurrentOperation)) == 1:
                        newVisited.append(newPosition)
                self.bfsQueue.append([newPosition, newCurrentOperation, newVisited, idTable])
            while not(self.bfsPaths) and self.bfsQueue:
                 move = self.bfsQueue.pop(0)
                 self.bfsFind(move[0], move[1],move[2], move[3])

    # PORUSZA KELNERA WEDŁUG LISTY KROKOW
    def followThePath(self, path):
        for direction in path:
            if direction == "Left":
                self.moveLeft()
            if direction == "Right":
                self.moveRight()
            if direction == "Up":
                self.moveUp()
            if direction == "Down":
                self.moveDown()
            self.game.draw()
            time.sleep(.50)

    def takeDish(self, orderTable):
        orderTable.hasDish = False
        self.whatKeep = 1

    def putDish(self, table):
        self.whatKeep = 0
        table.hasDish = True
        table.isWaiting = False

    def takePlate(self, table):
        table.hasDish = False
        table.isClean = True
        self.whatKeep = 2

    def putPlate(self):
        self.whatKeep = 0

    def takeOrder(self, table):
        table.isOrdering = False

    def work(self, object: object) -> object:
        if object.type == "wasteTable" and self.whatKeep == 2:
            self.putPlate()
        elif object.type == "orderTable" and object.hasDish and self.whatKeep == 0:
            self.takeDish(object)
        elif object.type == "table":
            if not object.isClean and (self.whatKeep == 0 or self.whatKeep == 2):
                self.takePlate(object)
            elif object.isOrdering and self.whatKeep == 0:
                self.takeOrder(object)
            elif object.isWaiting and self.whatKeep == 1:
                self.putDish(object)