import pygame 
from pygame.locals import *

from Classes.Game.Cards.MonsterCard import MonsterCard
from Classes.System.Components.Window import Window
from Classes.System.Components.InputHandler import InputHandler
from Classes.Game.World import World
from Classes.System.Network.TCPClient import TCPClient
from Classes.Game.Events.Login import Login
from Classes.Game.Events.PlaceCard import PlaceCard
from Classes.Game.Player import Player
from Classes.Game.Cards.Card import Card

class App:

    __window:Window
    __running:bool = True
    __FPS = 60
    __clock = pygame.time.Clock()
    __myFont:pygame.font
    __world:World
    __inputHandler: InputHandler
    __tcpClient: TCPClient

    def __init__(self, width:int=1920, height:int=1080, title:str="default title"):
        pygame.font.init() 
        self.__myFont = pygame.font.SysFont('Comic Sans MS', 30)
        self.__window = Window(width=width, height=height, title=title)
        self.__inputHandler = InputHandler()
        
        # store selected card globaly in order to prevent packet flooding
        self.selectedCard = None

        # game word
        self.__world = World(self.__window.getScreen())
        
        try:
            self.__tcpClient = TCPClient("127.0.0.1", "54322", self.__world, self.__inputHandler)
            Login(self.__tcpClient) # will login to the server
        except Exception as e:
            print(f"failed to login due to error {e}")
            print("server connection failed or got refused")
            pass

        self.startGameLoop()
        self.onCleanup()

    def startGameLoop(self):

        # create sprite groups
        # todo: remove these and let server handle card creation instead
        # blocker: server - client communication [WIP]
        # self.__world.spawnCard("Assets/Cards/1/", pygame.Vector2(500, 1050), self.__inputHandler, Player(1000, 0, "test"))
        # self.__world.spawnCard("Assets/Cards/1/", pygame.Vector2(600, 1050), self.__inputHandler, Player(1000, 0, "test"))
        # self.__world.spawnCard("Assets/Cards/1/", pygame.Vector2(700, 1050), self.__inputHandler, Player(1000, 0, "test"))
        # self.__world.spawnCard("Assets/Cards/1/", pygame.Vector2(800, 1050), self.__inputHandler, Player(1000, 0, "test"))
        # self.__world.spawnCard("Assets/Cards/1/", pygame.Vector2(900, 1050), self.__inputHandler, Player(1000, 0, "test"))
        # self.__world.spawnCard("Assets/Cards/1/", pygame.Vector2(1000, 1050), self.__inputHandler, Player(1000, 0, "test"))

        while self.__running:
            self.__clock.tick(self.__FPS)

            self.__window.getScreen().fill((0,0,0))

            # render world
            self.__window.drawWorld(self.__world)

            # updates all cards inside the cards Spritegroup at each step the gameloops does
            self.__world.getCards().update()
            self.__world.getHandCards().update()

            # draw groups
            self.__window.drawSpriteGroup(self.__world.getCards())
            self.__window.drawSpriteGroup(self.__world.getHandCards())

            # event handler
            self.handleEvent(pygame.event.get())

            # emits update to the game
            pygame.display.update()

    # handles incoming event queue
    def handleEvent(self, events):
        # TODO: fix bug that stacks cards when dragging them around
        # TODO: something prevents selected card from becoming function global

        for event in events:
            if event.type == pygame.QUIT:
                self.onCleanup()
            elif pygame.mouse.get_pressed()[0]:  # Wenn linke Maustaste gedrückt wird
                    mouse_x, mouse_y = pygame.mouse.get_pos()
                    mouse_pos = pygame.Vector2(mouse_x, mouse_y)

                    for card in self.__world.getCards():
                        if card.rect.collidepoint(mouse_pos) and self.selectedCard == None:
                            card.setDragging(True)
                            self.selectedCard = card
                            for field in self.__world.getBoardFields():
                                if field.getRect().collidepoint(mouse_pos):
                                    if field.getSide() == "Player":
                                        if field.getType() == "MonsterField" and card.getType() == "MonsterCard":
                                            # todo: resize card so that it fits into the card field
                                            card.rect.center = field.rect.center
                                            field.image = card.image.copy()
                                            card.setDragging(False)
                                        elif field.getType() == "EffectField" and card.getType() == "EffectCard" or field.getType() == "EffectField" and card.getType() == "EffectCard":
                                            # todo: resize card so that it fits into the card field
                                            card.rect.center = field.rect.center
                                            field.image = card.image.copy()
                                            card.setDragging(False)


            elif self.__inputHandler.getPressed()[pygame.K_SPACE]:
                print("card spawned")
                self.__world.spawnMonsterCard("Assets/Cards/MonsterCards/testmonstercard/", self.__inputHandler.getMousePos(), self.__inputHandler)
            elif event.type == pygame.MOUSEBUTTONUP:
                mouse_x, mouse_y = pygame.mouse.get_pos()
                if event.button == 1:  # Wenn linke Maustaste losgelassen wird
                    for card in self.__world.getCards():
                        card.setDragging(False)
                        # card.setState("placed")
                        # TODO: send place card event to server
                        # resets the currently selected card in order to prevent it getting moved
                        try:
                            if self.selectedCard == card:
                                print(self.selectedCard)
                                PlaceCard(self.__tcpClient, self.selectedCard, 1) # tells the server that the player placed this card
                        except Exception as e:
                            print(f"failed to place card on server due to error: {e}")

                        if not self.selectedCard == None:
                            self.selectedCard = None 

    # sets the running state for the gameloop
    def setRunning(self, running:bool):
        self.__running = running

    # ensures the gameloop stops running and the pygame instance is stopped properly
    def onCleanup(self):
        self.__running = False
        pygame.quit()