from ableton.v2.base import listens
from ableton.v2.base import liveobj_valid
from ableton.v2.control_surface.components import ChannelStripComponent
from ableton.v2.control_surface.components.clip_slot import is_button_pressed

from .. import colors
from ..skin import Colors
from ..color import Color, FX
from ..util import track_id

class ColoredChannelStripComponent(ChannelStripComponent):
	"A ChannelStripComponent that takes the color of the track into account, and that allows a track to be set as the explicit note monitor track by long-pressing it"

	def __init__(self, *a, **k):
		super(ColoredChannelStripComponent, self).__init__(*a, **k)
		self._select_button_did_delay = False
		self._mute_button_task = None
		self._mute_button_last = -1
		self._delete_button = None
		self._duplicate_button = None
		self._on_selected_track_changed.subject = self.song.view

	def set_track(self, track):
		super().set_track(track)
		self._on_track_arm_changed.subject = track if track and track.can_be_armed else None
		self._on_track_implicit_arm_changed.subject = track if track and track.can_be_armed else None
		self._update_select_button()

	def set_delete_button(self, button):
		self._delete_button = button

	def set_duplicate_button(self, button):
		self._duplicate_button = button
	
	def update(self):
		super(ColoredChannelStripComponent, self).update()
		self._mute_button_last = None
		self.update_mute_button_color()
	
	def _update_select_button(self):
		color_on = None
		color_off = None
		color = None

		has_track = liveobj_valid(self._track)
		if has_track:
			track_color = colors.color_value(self._track.color) if self._track.color is not None else 3

			is_armed = self._track.can_be_armed and (self._track.arm or self._track.implicit_arm)
			is_note_monitor_track = self.song.get_data("exquis_explicit_note_monitor_track", None) == track_id(self._track)

			if is_note_monitor_track:
				color_on = color_on or Colors.ChannelStrip.NoteMonitor.Armed if is_armed else Color(track_color, FX.pulsate_green)
				color_off = color_off or Color(track_color, FX.pulsate_green)
			
			if is_armed:
				color_on = color_on or Colors.ChannelStrip.Track.ArmedOn
				color_off = color_off or Colors.ChannelStrip.Track.ArmedOff
			
			color_on = color_on or Color(track_color, FX.lighter(25))
			color_off = color_off or Color(track_color, FX.darker(75))
		else:
			if self.empty_color is not None:
				color = self.empty_color

		if color is None:
			color_off = color_off or "DefaultButton.Off"
			color_on = color_on or "DefaultButton.On"

			if self.song.view.selected_track == self._track:
				color = color_on
			else:
				color = color_off
		
		self.select_button.color = color

	def _on_select_button_pressed(self, button):
		self._select_button_did_delay = False

		if not liveobj_valid(self._track):
			return
		
		track = self._track
		
		if is_button_pressed(self._delete_button) and track in self.song.tracks:
			index = list(self.song.tracks).index(track)
			self.song.delete_track(index)
			self._select_button_did_delay = True
			return

		if is_button_pressed(self._duplicate_button) and track in self.song.tracks:
			index = list(self.song.tracks).index(track)
			self.song.duplicate_track(index)
			self._select_button_did_delay = True

	def _on_select_button_released(self, button):
		if self._select_button_did_delay:
			return

		# Shortcuts for mode check
		parent = getattr(self, "parent", None)
		if not (parent and getattr(parent, "canonical_parent", None)):
			return
		modes = getattr(parent.canonical_parent, "modes", None)
		selected_mode = getattr(modes, "selected_mode", None) 
		
		current_track = self.song.view.selected_track
		same_track = current_track == self._track
		
		# Manage group track folding/unfolding
		if getattr(self._track, "is_foldable", False):
			if same_track:
				self._track.fold_state = not self._track.fold_state
				self._update_select_button()
				return
			else:
				self.song.view.selected_track = self._track
				self._update_select_button()
				return

		# Manage Harming of midi tracks in tracks mode 
		if self._track.has_midi_input and self._track.can_be_armed:
			if selected_mode == "tracks" : 
				self.song.view.selected_track = self._track
				#for t in self.song.tracks:
				#	if getattr(t, "can_be_armed", False):
				#		if t.has_midi_input and t != self._track:
				#			t.implicit_arm = False
				#			if self.song.exclusive_arm:
				#				t.arm = False
						#  unarm audio tracks if in exlusive arm mode
				#		elif t.has_audio_input and getattr(t, "arm", False) and self.song.exclusive_arm:
				#			t.arm = False
				
				# If already implicit armed : convert to hard arm 
				if getattr(self._track, "implicit_arm", False) and not getattr(self._track, "arm", False): 
					if same_track:
						if getattr(self._track, "can_be_armed", False):
							self._track.arm = True
					return
				# If already hard armed: revert to implicit arm
				elif getattr(self._track, "arm", False):
					if same_track:
						self._track.arm = False
					return 
				# If neither, make implicit arm
				else:
					if getattr(self._track, "can_be_armed", False):
						self._track.implicit_arm = True
						self._track.arm = False
				#self._update_select_button() normally useless 
				return

		#if self._track.has_audio_input:
		#	if selected_mode == "tracks":
		#		# Manage audio and midi exclusive mode and midi implicit exclusivity
		#		for t in self.song.tracks:
		#			if t.has_midi_input and getattr(t, "can_be_armed", False):
		#				t.implicit_arm = False

		# Handles all tracks behaviour besides midi tracks in track mode 

		# if the track has not been selected yet we want to : 
		# - select it 
		# - in case of Tracks mode we want to 
		# return and will do something if another click comes
		# for this track
		if not same_track:
			self.song.view.selected_track = self._track
			return

		if not liveobj_valid(self._track) or not self._track.can_be_armed:
			return

		# if this track is already selected, we want to arm/disarm it: 
		#should_update_parent = False
		if same_track:
			if current_track.can_be_armed:
				if not self._track.arm and self.song.exclusive_arm:
					for t in self.song.tracks:
						if getattr(t, "can_be_armed", False):
							t.arm = False
					if self.parent:
						should_update_parent = True
				self._track.arm = not self._track.arm

		#if should_update_parent:
		#	if hasattr(self.parent, "_channel_strips"):
		#		for strip in self.parent._channel_strips:
		#			strip._update_select_button()
		#else:
		#	self._update_select_button()



	def _on_select_button_pressed_delayed(self, button):
		if not liveobj_valid(self._track) or self._track not in self.song.tracks:
			return
		
		self._select_button_did_delay = True

		if self.song.get_data("exquis_explicit_note_monitor_track", None) == track_id(self._track):
			self.song.set_data("exquis_explicit_note_monitor_track", None)
		else:
			self.song.set_data("exquis_explicit_note_monitor_track", track_id(self._track))
		
		if hasattr(self.parent, "_channel_strips"):
			for strip in self.parent._channel_strips:
				strip._update_select_button()
		else:
			self._update_select_button()

	def update_mute_button_color(self):
		if self._mute_button is None:
			return
		if self._track is None:
			return
		
		track = self._track
		
		if len(track.clip_slots) > 0:
			mute = track.mute or track.muted_via_solo or track.solo
			if mute:
				if self._mute_button_last is not None:
					self._mute_button.set_light(Color(127, FX.darker(75)))
					self._mute_button_last = None
				return
		
		if track.has_midi_output:
			v = track.output_meter_level
		else:
			v = (track.output_meter_left + track.output_meter_right) * 0.5
		
		vi = int(v * 10)
		if vi == self._mute_button_last:
			return
		self._mute_button_last = vi
		
		# v is from 0 to 1 but follows a dB curve, let's uncurve it
		v = 50 ** (v * 1.5 - 1)
		if v < 0:
			v = 0
		elif v > 1:
			v = 1
		percent = int(v * 100)
		self._mute_button.set_light(Color(13, FX.lighter(percent * 0.4)))

	def _on_mute_changed(self):
		self.update_mute_button_color()

	@listens('arm')
	def _on_track_arm_changed(self):
		# Appelé quand une piste arm/disarm change (depuis n’importe où !)
		parent = getattr(self, "parent", None)
		if parent and getattr(parent, "canonical_parent", None):
			parent.canonical_parent.schedule_message(0, self._update_arm_logic)
		#self.schedule_message(0, self._update_arm_logic())
		self._update_select_button()

	@listens('implicit_arm')
	def _on_track_implicit_arm_changed(self):
		# Appelé quand une piste arm/disarm change (depuis n’importe où !)
		parent = getattr(self, "parent", None)
		if parent and getattr(parent, "canonical_parent", None):
			parent.canonical_parent.schedule_message(0, self._update_arm_logic)
		self._update_select_button()

	@listens('selected_track')
	def _on_selected_track_changed(self):
		# Appelé quand une piste arm/disarm change (depuis n’importe où !)
		parent = getattr(self, "parent", None)
		if parent and getattr(parent, "canonical_parent", None):
			parent.canonical_parent.schedule_message(0, self._update_arm_logic_from_select)
		self._update_select_button()

	def _update_arm_logic_from_select(self):
		# Shortcuts for mode check
		parent = getattr(self, "parent", None)
		if not (parent and getattr(parent, "canonical_parent", None)):
			return
		modes = getattr(parent.canonical_parent, "modes", None)
		selected_mode = getattr(modes, "selected_mode", None) 
		exclusive_arm = self.song.exclusive_arm	
		track_is_midi = self.song.view.selected_track.has_midi_input

		
		if selected_mode == "tracks" or selected_mode == "notes":
			if self.song.view.selected_track.has_audio_input:
				for t in self.song.tracks:
					if getattr(t, "can_be_armed", False):
						if t.has_midi_input and getattr(t, "implicit_arm", False):
							t.implicit_arm = False
			if self.song.view.selected_track.has_midi_input: 
				for t in self.song.tracks:
					if getattr(t, "can_be_armed", False):
						if t.has_midi_input and t != self.song.view.selected_track and exclusive_arm:
							t.implicit_arm = False
							t.arm = False 
						elif t.has_midi_input and t != self.song.view.selected_track and not exclusive_arm:
							t.implicit_arm = False
				if not self.song.view.selected_track.arm:
					self.song.view.selected_track.implicit_arm = True
				else: 
					self.song.view.selected_track.implicit_arm = True
					self.song.view.selected_track.arm = True

	def _update_arm_logic(self):
		# Shortcuts for mode check
		parent = getattr(self, "parent", None)
		if not (parent and getattr(parent, "canonical_parent", None)):
			return
		modes = getattr(parent.canonical_parent, "modes", None)
		selected_mode = getattr(modes, "selected_mode", None) 
		
		current_track = self.song.view.selected_track
		same_track = current_track == self._track

		exclusive_arm = self.song.exclusive_arm
		track_is_midi = self._track.has_midi_input
		track_is_implicit_armed = getattr(self._track, "implicit_arm", False)
		track_is_armed = getattr(self._track, "arm", False)
		# todo selection : 
		# the track should be selected if => armed or implicit armed 

		if selected_mode == "tracks" or selected_mode == "notes" :
			if exclusive_arm:
				if track_is_midi:
					if (track_is_implicit_armed and not track_is_armed) or (track_is_implicit_armed and track_is_armed): 
						for t in self.song.tracks:
							if getattr(t, "can_be_armed", False):
								if t.has_midi_input and t != self.song.view.selected_track:
									t.implicit_arm = False
									t.arm = False
								if t.has_audio_input:
									t.arm = False
				else: # track is audio 
					if track_is_armed: 
						for t in self.song.tracks:
							if getattr(t, "can_be_armed", False):
								if t.has_midi_input:
									t.implicit_arm = False
									t.arm = False
								if t.has_audio_input and t != self.song.view.selected_track:
									t.arm = False
					#else # audio track not armed
						# do nothing for now 
			#else: # not exclusive mode 
			#	if track_is_midi: # implicit is always exclusive for midi 
			#		if (track_is_implicit_armed and track_is_armed) or (track_is_implicit_armed and not track_is_armed): 
			#			for t in self.song.tracks:
			#				if getattr(t, "can_be_armed", False):
			#					if t.has_midi_input and t != self.song.view.selected_track and not self.song.view.selected_track.arm :
			#						t.implicit_arm = False
									#t.arm = False
				#else # track is audio 
					#if  track_is_armed => nothing for now 

		if selected_mode == "session":
			if exclusive_arm:
				if track_is_midi:
					if track_is_armed: 
						for t in self.song.tracks:
							if getattr(t, "can_be_armed", False):
								if t.has_midi_input and t != self.song.view.selected_track:
									t.implicit_arm = False
									t.arm = False
								if t.has_audio_input:
									t.arm = False
				else: 
					if track_is_armed: 
						for t in self.song.tracks:
							if getattr(t, "can_be_armed", False):
								if t.has_midi_input: 
									t.implicit_arm = False
									t.arm = False
								if t.has_audio_input and t != self.song.view.selected_track:
									t.arm = False
			# else # not exclusive mode nothing to do...