import sdl2
import sdl2.ext
from OpenGL.GL import *
import time
from sdl2 import SDL_GL_SetSwapInterval
from .key import Key
import numpy as np
import OpenGL.GL

class Vector3:
    def __init__(self, x=0, y=0, z=0):
        self.x = float(x)
        self.y = float(y)
        self.z = float(z)

    def __add__(self, other):
        return Vector3(self.x + other.x, self.y + other.y, self.z + other.z)

    def __sub__(self, other):
        return Vector3(self.x - other.x, self.y - other.y, self.z - other.z)

    def __mul__(self, scalar):
        return Vector3(self.x * scalar, self.y * scalar, self.z * scalar)

    def to_list(self):
        return [self.x, self.y, self.z]

    def __repr__(self):
        return f"Vector3({self.x}, {self.y}, {self.z})"

def debug_init():
    @staticmethod
    def init():
        # Włącz przezroczystość (alpha blending)
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        # Włącz test głębokości (żeby obiekty były dobrze rysowane w 3D)
        glEnable(GL_DEPTH_TEST)
        glDepthFunc(GL_LESS)  # Domyślnie można zostawić, ale warto jawnie ustawić

        # Włącz odrzucanie tylnych ścianek (culling)
        glEnable(GL_CULL_FACE)
        glCullFace(GL_BACK)  # Możesz też użyć GL_FRONT, jeśli robisz np. odbicia
        glFrontFace(GL_CCW)  # Counter-clockwise - domyślnie standard OpenGL

        # Głębia na 1.0 - domyślnie, ale dobrze ustawić jawnie
        glClearDepth(1.0)

        # V-Sync
        SDL_GL_SetSwapInterval(1)  # 1 = włączony VSync, 0 = wyłączony (lepszy FPS, może tearing)

        # Gładkie linie i wielokąty (opcjonalne, zależnie od potrzeb)
        glEnable(GL_LINE_SMOOTH)
        glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)

        glEnable(GL_POLYGON_SMOOTH)
        glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST)

        # Antyaliasing multisampling (jeśli masz MSAA ustawione w SDL_GL)
        glEnable(GL_MULTISAMPLE)

def normalize(v):
    norm = np.linalg.norm(v)
    if norm == 0:
        return v
    return v / norm

@staticmethod
def init():
    glEnable(GL_BLEND)
    glEnable(GL_DEPTH_TEST)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glEnable(GL_CULL_FACE)
    glFrontFace(GL_CCW)
    glClearDepth(1.0)
    SDL_GL_SetSwapInterval(1)

@staticmethod
def get_fullscreen():
    sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)  # upewniamy się że SDL wystartował
    mode = sdl2.SDL_DisplayMode()
    if sdl2.SDL_GetDesktopDisplayMode(0, mode) != 0:
        raise RuntimeError("Nie udało się pobrać trybu ekranu")
    return mode.w, mode.h

class Window:
    def __init__(self, title, width, height):
        sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
        self.width = width
        self.height = height
        self.window = sdl2.SDL_CreateWindow(
            title.encode("utf-8"),
            sdl2.SDL_WINDOWPOS_CENTERED,
            sdl2.SDL_WINDOWPOS_CENTERED,
            width,
            height,
            sdl2.SDL_WINDOW_OPENGL | sdl2.SDL_WINDOW_SHOWN,
        )
        self.context = sdl2.SDL_GL_CreateContext(self.window)

        glViewport(0, 0, width, height)

        self.mouse_locked = True
        sdl2.SDL_SetRelativeMouseMode(sdl2.SDL_TRUE)
        sdl2.SDL_ShowCursor(sdl2.SDL_DISABLE)

    def is_key_pressed(self, key: Key) -> bool:
        keys = sdl2.SDL_GetKeyboardState(None)
        return keys[key] != 0

    def toggle_mouse_lock(self):
        self.mouse_locked = not self.mouse_locked
        if self.mouse_locked:
            sdl2.SDL_SetRelativeMouseMode(sdl2.SDL_TRUE)
            sdl2.SDL_ShowCursor(sdl2.SDL_DISABLE)
        else:
            sdl2.SDL_SetRelativeMouseMode(sdl2.SDL_FALSE)
            sdl2.SDL_ShowCursor(sdl2.SDL_ENABLE)

    def prepare_frame(self):
        glViewport(0, 0, self.width, self.height)
        glClearColor(0.1, 0.1, 0.1, 1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glEnable(GL_DEPTH_TEST)

    def run(self, update_callback=None, cameras=[]):
        last_time = time.time()
        event = sdl2.SDL_Event()
        running = True
        while running:
            while sdl2.SDL_PollEvent(event):
                if event.type == sdl2.SDL_QUIT:
                    running = False
                elif event.type == sdl2.SDL_KEYDOWN:
                    if event.key.keysym.scancode == sdl2.SDL_SCANCODE_ESCAPE:
                        self.toggle_mouse_lock()

            now = time.time()
            dt = now - last_time
            last_time = now

            self.prepare_frame()
            if update_callback:
                update_callback(dt, self)

            sdl2.SDL_GL_SwapWindow(self.window)
            glFlush()

        sdl2.SDL_DestroyWindow(self.window)
        sdl2.SDL_Quit()
