from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import glfw
import numpy as np
from datos.Config import ConfigManager

config = ConfigManager()

# v: vertex x,y,z
#
class Mesh:
    def __init__(self, malla) -> None:
        self.malla = malla
        self.vertices, self.colors, self.faces = self.load_mesh()

        self.vertices = np.array(self.vertices, dtype=np.float32)
        self.colors = np.array(self.colors, dtype=np.float32)
        self.faces = np.array(self.faces, dtype=np.uint32)

        # Crear búferes de vértices y colores
        self.vbo_vertices = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, self.vbo_vertices)
        glBufferData(GL_ARRAY_BUFFER, self.vertices.nbytes, self.vertices, GL_STATIC_DRAW)

        self.vbo_colors = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, self.vbo_colors)
        glBufferData(GL_ARRAY_BUFFER, self.colors.nbytes, self.colors, GL_STATIC_DRAW)

        # Liberar el búfer activo
        glBindBuffer(GL_ARRAY_BUFFER, 0)

    def load_mesh(self):
        vertices = []
        faces = []
        colors = []

        with open(self.malla, 'r') as file:
            for line in file:
                if line.startswith('v '):
                    data = line.strip().split()[1:]
                    vertices.append(list(map(float, data[:3])))
                    if len(data) == 6:  # Si hay información de color
                        colors.append(list(map(float, data[3:])))
                    else:
                        colors.append([1.0, 1.0, 1.0])
                elif line.startswith('f '):
                    face = [int(vertex.split('/')[0]) - 1 for vertex in line.strip().split()[1:]]
                    faces.append(face)

        return vertices, colors, faces
        
    def draw(self):
        # Activar los búferes y configurar los atributos de vértices y colores
        glBindBuffer(GL_ARRAY_BUFFER, self.vbo_vertices)
        glVertexPointer(3, GL_FLOAT, 0, None)

        glBindBuffer(GL_ARRAY_BUFFER, self.vbo_colors)
        glColorPointer(3, GL_FLOAT, 0, None)

        glEnableClientState(GL_VERTEX_ARRAY)
        glEnableClientState(GL_COLOR_ARRAY)

        # Dibujar el objeto utilizando los búferes
        glDrawElements(GL_TRIANGLES, len(self.faces) * 3, GL_UNSIGNED_INT, self.faces)

        # Desactivar los búferes y los atributos
        glDisableClientState(GL_VERTEX_ARRAY)
        glDisableClientState(GL_COLOR_ARRAY)
        glBindBuffer(GL_ARRAY_BUFFER, 0)
        

def display():
    global camera_distance, camera_pitch, camera_yaw
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glLoadIdentity()

    # Aplicar transformaciones de la cámara
    glTranslatef(0, 0, -camera_distance)
    glRotatef(camera_pitch, 1, 0, 0)  # Aplicar rotación vertical
    glRotatef(camera_yaw, 0, 1, 0)     # Aplicar rotación horizontal

    mesh.draw()
    glfw.swap_buffers(window)

def reshape(window, width, height):
    glViewport(0, 0, width, height)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()  # Cargar la matriz de identidad
    gluPerspective(45, (width / height), 0.1, 100.0)  # Crear la matriz de proyección
    glMatrixMode(GL_MODELVIEW)  # Volver al modo de matriz de modelo-vista

def key_callback(window, key, scancode, action, mods):
    global camera_distance, camera_pitch, camera_yaw
    speed = 1

    if key == glfw.KEY_UP:
        camera_pitch -= speed
    elif key == glfw.KEY_DOWN:
        camera_pitch += speed
    elif key == glfw.KEY_LEFT:
        camera_yaw -= speed
    elif key == glfw.KEY_RIGHT:
        camera_yaw += speed
    elif key == glfw.KEY_W:
        camera_distance += speed
    elif key == glfw.KEY_S:
        camera_distance -= speed

def scroll_callback(window, xoffset, yoffset):
    global camera_distance
    speed = 0.1
    camera_distance += yoffset * speed

def main_view(malla):
    global window, mesh, camera_distance, camera_pitch, camera_yaw
    camera_distance = 5
    camera_pitch = 0
    camera_yaw = 0

    if not glfw.init():
        return "Error: could not initialize GLFW"
    width, height = config.SCREEN_WIDTH, config.SCREEN_HEIGHT
    window = glfw.create_window(width, height, "OpenGL Window", None, None)
    if not window:
        glfw.terminate()
        return "Error: GLFW window could not be created."

    glfw.make_context_current(window)
    glfw.set_window_size_callback(window, reshape)
    glfw.set_key_callback(window, key_callback)
    glfw.set_scroll_callback(window, scroll_callback)

    glEnable(GL_DEPTH_TEST)

    mesh = Mesh(malla)

    while not glfw.window_should_close(window):
        glfw.poll_events()
        display()

        if glfw.get_key(window, glfw.KEY_ESCAPE) == glfw.PRESS:
            glfw.set_window_should_close(window, True)

    glfw.terminate()