import time
from graphic import Graphic
from sound import Sound
from car import Car
from PIL import Image
from pynput import keyboard
import math

class Game:
    def __init__(self, graphic_dict, car_dict, track_map_path, soundfile, start_val, stall=True, overload=True):
        self._car = Car(car_dict["overlay"], car_dict["steering_wheel"], car_dict["stick_shift"], car_dict["acceleration"], car_dict["brakes"])
        self._graphics = Graphic(graphic_dict["map_png"], graphic_dict["screen_width"], graphic_dict["screen_height"], graphic_dict["height"], graphic_dict["distance"], car_dict["overlay"], car_dict["steering_wheel"], car_dict["stick_shift"])
        self._sound = Sound(soundfile)
        self._track_map = Image.open(track_map_path).convert("RGB").load()
        self._speed = 0.0
        self._angle = start_val[2]
        self._px, self._py = start_val[0], start_val[1]
        self._stall = stall
        self._overload = overload
        self._halfway = False
        self._rpm = 0
        self._gear = 1
        self._steering = 0
        
        #pynput Tasteneingaben:
        self._keys_pressed = set()
        def on_press(key):
            self._keys_pressed.add(key)
        def on_release(key):
            self._keys_pressed.remove(key)
        keyboard.Listener(on_press=on_press, on_release=on_release).start()
        
    def start(self):
        start_time = time.time()
        self._sound.start()
        while True:
            
            #Tasteneingaben abfragen
            if keyboard.KeyCode.from_char('a') in self._keys_pressed:
                self._steering = max(-360, self._steering - 5)
            if keyboard.KeyCode.from_char('d') in self._keys_pressed:
                self._steering = min(360, self._steering + 5)
            if keyboard.KeyCode.from_char('w') in self._keys_pressed and keyboard.KeyCode.from_char('q') not in self._keys_pressed:
                self._speed += self._car.acceleration
            if keyboard.KeyCode.from_char('s') in self._keys_pressed:
                self._speed = max(0, self._speed - self._car.brakes)
            if keyboard.KeyCode.from_char('q') in self._keys_pressed:
                for gear_number in range(1, 5):
                    if keyboard.KeyCode.from_char(str(gear_number)) in self._keys_pressed:
                        self._gear = gear_number
                        
            #Spiel updaten
            if keyboard.KeyCode.from_char('q') in self._keys_pressed or keyboard.KeyCode.from_char('s') in self._keys_pressed: self._speed *= 0.95
            else: self._speed = max(5, self._speed*0.95 if self._speed < 20 else self._speed*0.99)
            self._steering *= 0.9
            self._angle += 0.0007*self._steering*min(10, self._speed)
            self._px += math.cos(self._angle) * self._speed
            self._py += math.sin(self._angle) * self._speed
            if keyboard.KeyCode.from_char('q') in self._keys_pressed:
                if keyboard.KeyCode.from_char('w') in self._keys_pressed: self._rpm = 10000
                else: self._rpm = 800
            else: self._rpm = (100*self._speed)/self._gear
            
            self._graphics.px, self._graphics.py = self._px, self._py
            self._graphics.angle = self._angle
            self._graphics.rpm = self._rpm
            self._graphics.speed = self._speed
            self._graphics.steering = self._steering
            self._graphics.gear = self._gear
            self._graphics.time = time.time()-start_time
            self._sound.set_rpm(self._rpm)
            
            #Quiten, falls Drehzahl nicht in Ordnung / Strecke verlassen / gewonnen, sonst update
            r,g,b = self._track_map[self._px, self._py]
            if self._rpm < 400 and self._stall:
                self._graphics.event = "Abgewürgt - zu niedrige Drehzahl!"
                self._graphics.update()
                time.sleep(5)
                break
            elif self._rpm > 9500 and self._overload:
                self._graphics.event = "Motorschaden - zu hohe Drehzahl!"
                self._graphics.update()
                time.sleep(5)
                break
            elif (r,g,b) == (255, 0, 0):
                self._graphics.event = "Unfall - Strecke verlassen!"
                self._graphics.update()
                time.sleep(5)
                break
            elif (r,g,b) == (0, 0, 255) and self._halfway:
                self._graphics.event = "Ziel!"
                self._graphics.update()
                score = int(time.time()-start_time)
                with open("highscore.txt", "r") as f:
                    highscore_before = f.read().strip()
                try:
                    if int(highscore_before) > score:
                        with open("highscore.txt", "w") as f:
                            f.write(str(score))
                except:
                    with open("highscore.txt", "w") as f:
                        f.write(str(score))
                time.sleep(5)
                break
            elif (r,g,b) == (255, 0, 255):
                self._halfway = True
                self._graphics.update()
            else: self._graphics.update()
            
            #Quiten, falls X geklickt
            if self._graphics.IsQuit():
                break
                
            time.sleep(0.1)
        
        self._graphics.quit()
        self._sound.stop()