import math
import os
import sys

#"pip install PyOpenGL"
from OpenGL.GL  import *
from OpenGL.GLU import *

#"pip install pygame-ce"
with open( os.devnull, "w" ) as f:
	oldstdout=sys.stdout; sys.stdout=f; import pygame; sys.stdout=oldstdout

from .glbase import gl_font
from .glbase import gl_misc
from .glbase import gl_program
from .glbase import gl_texture

from . import config
from .math_util import *



MENU            = -1
MENU_PLAY       =  0
MENU_QUIT       =  1
MENU_OPTIONS    =  2
MENU_HIGHSCORES =  3
MENU_INFO       =  4
MENU_LVLSELECT  =  5

class Menu:
	def __init__( self:Self ):
		self.selected = 0

		self.rot     = 0.0
		self.rot_vel = 0.0
		self.rot_T0_t_a_b_c = [ 0.0, 0.0, 0.0,0.0,0.0 ]

		self.textures = {}
		try:
			self.textures["bg"] = gl_texture.Texture2D.from_path( config.MAIN_DIR+"data/menu/bg1_lossy.webp" )
			self.textures["bg"].set_nicest()
		except:
			self.textures["bg"] = None
		self.textures["menu"] = [
			gl_texture.Texture2D.from_path( config.MAIN_DIR+"data/menu/play.png"        , GL_RGBA8 ),
			gl_texture.Texture2D.from_path( config.MAIN_DIR+"data/menu/quit.png"        , GL_RGBA8 ),
			gl_texture.Texture2D.from_path( config.MAIN_DIR+"data/menu/options.png"     , GL_RGBA8 ),
			gl_texture.Texture2D.from_path( config.MAIN_DIR+"data/menu/highscores.png"  , GL_RGBA8 ),
			gl_texture.Texture2D.from_path( config.MAIN_DIR+"data/menu/info.png"        , GL_RGBA8 ),
			gl_texture.Texture2D.from_path( config.MAIN_DIR+"data/menu/repeat_level.png", GL_RGBA8 )
		]

		self.font_title = gl_font.Font.create_from_font_file( config.MAIN_DIR+"data/font.ttf", 40 )
		self.font_info  = gl_font.Font.create_from_font_file( config.MAIN_DIR+"data/font.ttf", 20 )

	def _compute_rotate( self:Self ):
		self.rot %= math.tau

		#Difference in angle
		rot_target = self.selected * math.tau / 6.0
		if rot_target >= self.rot:
			delT_above = rot_target - self.rot
			delT_below = delT_above - math.tau
		else:
			delT_below = rot_target - self.rot
			delT_above = delT_below + math.tau

		#Want rotational velocity to follow a parabolic function from ⟨t=0,v=current⟩, arriving at
		#	⟨t=h,v=0⟩, with an area integral `delT_below` or `delT_above`.  Solve for the coefficients
		#	that do that and pick the one with the least maximum absolute velocity.
		h = config.MENU_ROTATE_TIME
		A = [ h*h*h/3.0,h*h*0.5, h*h, h ]
		b_below = ( delT_below-h*self.rot_vel, -self.rot_vel )
		b_above = ( delT_above-h*self.rot_vel, -self.rot_vel )
		below = ( *solve_2x2( A, b_below ), self.rot_vel )
		above = ( *solve_2x2( A, b_above ), self.rot_vel )
		if abs(parabola_extremum_val(above)) < abs(parabola_extremum_val(below)):
			self.rot_T0_t_a_b_c = [ self.rot, 0.0, *above ]
		else:
			self.rot_T0_t_a_b_c = [ self.rot, 0.0, *below ]

	def handle_input( self:Self ):
		for event in pygame.event.get():
			if   event.type == pygame.QUIT: return MENU_QUIT
			elif event.type == pygame.KEYDOWN:
				if   event.key == pygame.K_ESCAPE: return MENU_QUIT
				elif event.key == pygame.K_LEFT :
					self.selected = ( self.selected - 1 ) % 6
					self._compute_rotate()
				elif event.key == pygame.K_RIGHT:
					self.selected = ( self.selected + 1 ) % 6
					self._compute_rotate()
				elif event.key == pygame.K_RETURN:
					#Finish updating menu so when we come back, no motion to potentially resume
					self.rot_T0_t_a_b_c[1] = config.MENU_ROTATE_TIME
					self.update(0.0)

					return self.selected
			elif event.type == pygame.WINDOWRESIZED:
				config.window_res = [ event.x, event.y ]

		return MENU

	def update( self:Self, dt:float ):
		if self.rot_T0_t_a_b_c[1] >= config.MENU_ROTATE_TIME:
			self.rot_T0_t_a_b_c[1] = config.MENU_ROTATE_TIME
		T0, t, a,b,c = self.rot_T0_t_a_b_c

		self.rot_vel = a*t*t + b*t + c
		self.rot     = (a/3.0)*t*t*t + 0.5*b*t*t + c*t + T0

		self.rot_T0_t_a_b_c[1] += dt

		return True

	def render( self:Self ):
		gl_misc.set_gl2_projview_2D(config.window_res)
		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )

		glEnable(GL_TEXTURE_2D)
		if self.textures["bg"]:
			glColor4f( 0.2,0.2,0.2, 1.0 )
			gl_texture.TextureBase.bind( self.textures["bg"] )
			w, h = self.textures["bg"].res
			w, h = (w/h)*config.window_res[1], config.window_res[1]
			gl_misc.render_gl2_quad( (config.window_res[0]/2,config.window_res[1]/2), w/2,h/2 )

		def render_center_text( font:gl_font.Font, text:str, y:int, color ):
			w = font.render_approx_width(text)
			x = config.window_res[0]//2 - w//2
			font.render( text, (x,y), color )

		COLOR = ( 1.0,1.0,0.0, 1.0 )

		render_center_text( self.font_title, "Marble Madness", config.window_res[1]-100, COLOR )

		if   self.selected == MENU_PLAY      : text = "Play Marble Madness from the beginning!"
		elif self.selected == MENU_QUIT      : text = "Quit the Game."
		elif self.selected == MENU_OPTIONS   : text = "Change graphics, sound, and controls options."
		elif self.selected == MENU_HIGHSCORES: text = "View high scores!"
		elif self.selected == MENU_INFO      : text = "View the story, controls, and other info."
		elif self.selected == MENU_LVLSELECT : text = "Play a previous level!"
		render_center_text( self.font_info, text, config.window_res[1]-150, COLOR )

		render_center_text( self.font_info, "<= use arrow keys to browse menu =>", 50, COLOR )

		gl_program.Program.use(None)

		for k, tex in enumerate( self.textures["menu"] ):
			angle = self.rot + math.radians( 90.0 - k*60.0 )
			px = rndint( config.window_res[0]/2.0        + 150.0*math.cos(angle) - 150.0/2.0 )
			py = rndint( config.window_res[1]/2.0 - 50.0 + 150.0*math.sin(angle) - 150.0/2.0 )

			graylvl = 1.0 if self.selected==k else 0.2
			glColor4f( graylvl,graylvl,graylvl, 1.0 )

			gl_misc.render_gl2_blit( tex, (px,py) )

		glColor4f( 1.0,1.0,1.0, 1.0 )

		pygame.display.flip()

def main():
	global clock

	pygame.key.set_repeat( 750, 100 )

	clock = pygame.time.Clock()
	menu = Menu()
	task = MENU
	while task == MENU:
		dt = clock.get_time() * 0.001

		task = menu.handle_input()
		menu.update(dt)
		menu.render()

		clock.tick()

	return task
