from enum import Enum
from typing import Self

from .. import config
from ..math_util import *



class MARBLE(Enum):
	SELF=1; EVIL_HENCH=2; EVIL_KING=3

class Marble:
	def __init__( self:Self, type:MARBLE, coord:Vector2, radius:float, health:float, top_rot_speed:float ):
		self.type = type

		self.center = Vector3( coord.x, coord.y, radius )
		self.radius = radius

		self.rot     = Quaternion( Vector3(0.0), 0.0 )
		self.rot_vel = Vector3(0.0)
		self.top_rot_speed = top_rot_speed #rad/s
		self.vel = Vector3(0.0)

		self.health = health

		self.target:Marble|None = None

	@staticmethod
	def make_self( coord:Vector2 ):
		return Marble( MARBLE.SELF, coord,
			config.radius_self, config.health_self, config.top_rot_speed_self
		)
	@staticmethod
	def make_hench( coord:Vector2 ):
		return Marble( MARBLE.EVIL_HENCH, coord,
			config.radius_hench, config.health_hench, config.top_rot_speed_hench
		)
	@staticmethod
	def make_king( coord:Vector2 ):
		return Marble( MARBLE.EVIL_KING, coord,
			config.radius_king, config.health_king, config.top_rot_speed_king
		)

	@staticmethod
	def collide( marble0:Self, marble1:Self ):
		delta:Vector3 = marble1.center - marble0.center
		min_r:float = marble0.radius + marble1.radius
		return delta.get_length_sq() < min_r*min_r

	def apply_rot_accel( self:Self, rot_accel:Vector3, dt:float ):
		# I = ⅖ m r² (for solid sphere)
		# τ = I α
		# ω += Δt α (Euler step)
		#print(f"{self.rot_vel} + {dt}*{rot_accel} = {self.rot_vel+dt*rot_accel}")
		self.rot_vel += dt * rot_accel
	def apply_rot_brake( self:Self, max_strength:float, dt:float ):
		rot_speed = self.rot_vel.get_length()
		if rot_speed < 1.0e-6:
			self.rot_vel = Vector3(0.0)
		else:
			strength = min( max_strength, rot_speed/dt )
			rot_accel = -strength * self.rot_vel/rot_speed
			self.apply_rot_accel( rot_accel, dt )

	def update( self:Self, dt:float ):
		if self.type != MARBLE.SELF:
			if self.target != None:
				delta = self.center - self.target.center
				#axis = ( delta ^ Vector3(0,0,1) ).normalized( Vector3(1,0,0) )
				axis = Vector3( delta.y, -delta.x, 0.0 ).normalized( Vector3(1,0,0) )
				self.apply_rot_accel( config.rot_accel_evil*axis, dt )
			else:
				self.apply_rot_brake( config.rot_accel_evil_brake, dt )

		#forward = self.rot_vel ^ Vector3(0,0,1)
		forward = Vector3( self.rot_vel.y, -self.rot_vel.x, 0.0 )
		self.vel = self.radius * forward
		self.center += dt * self.vel

		rot_speed = self.rot_vel.get_length()
		if rot_speed > self.top_rot_speed:
			self.rot_vel = self.rot_vel * (self.top_rot_speed/rot_speed)
		#self.rot_vel *= math.exp( math.log(0.05) * dt )

		self.rot += (dt*0.5) * Quaternion( 0.0, self.rot_vel.x,self.rot_vel.y,self.rot_vel.z ) * self.rot

		self.rot = self.rot.normalized()
