extends Node3D
class_name Combo

@onready var character = (get_owner() as Character)
@onready var status = (%Status as Status)
@onready var skill = (%Skill as Skill)
@onready var move = (%Move as Move)

class InputData:
	var action:String
	var alive_time:float

var skill_map = {} #input -> skill[] 
var input_list = [] #指令缓存

func _ready():
	# test
	add_weapon(load("res://config/weapon/long.tres"))
	add_weapon(load("res://config/weapon/short.tres"))
	add_weapon(load("res://config/weapon/fist.tres"))
	add_weapon(load("res://config/weapon/chain.tres"))

func _process(delta):
	update_input_alive(delta)
	update_break()
	update_move()

func update_input_alive(delta):
	var input_list_new = []
	for input in input_list:
		input.alive_time -= delta
		if input.alive_time > 0:
			input_list_new.append(input)
	input_list = input_list_new
	
func update_break():
	for break_level_name in Enum.EBreakLevel:
		var break_level = Enum.EBreakLevel[break_level_name]
		if break_level <= status.break_level:
			match break_level:
				Enum.EBreakLevel.None: pass
				Enum.EBreakLevel.Cancel: update_break_cancel()
				Enum.EBreakLevel.Jump: update_break_jump()
				Enum.EBreakLevel.Break: update_break_break()
				Enum.EBreakLevel.Walk: update_break_walk()

func update_break_cancel():
	update_break_by_level(Enum.EBreakLevel.Cancel)
		
func update_break_jump():
	for i in range(0,len(input_list)):
		var input = input_list[i]
		if input.action == "jump" and not status.is_jumped:
			refresh_input(i)
			skill.cancel_skill()
			move.jump()
			return
	
func update_break_break():
	update_break_by_level(Enum.EBreakLevel.Break)
	
func update_break_walk():
	if status.is_skill_running and status.input_dir.length() > 0:
		refresh_input(len(input_list))
		skill.cancel_skill()
	
func update_break_by_level(break_level:Enum.EBreakLevel):
	for i in range(0,len(input_list)):
		var input = input_list[i]
		if not input.action in skill_map:
			continue
		for skill_cfg in skill_map[input.action]:
			var skill_player_weapon_cfg = skill_cfg as SkillPlayerCfg
			if skill_player_weapon_cfg.break_level != break_level:
				continue
			var stance_from = skill_player_weapon_cfg.stance_from
			if stance_from != status.stance and stance_from != Enum.EStance.Any:
				continue
			if skill_player_weapon_cfg.weapon:
				if skill_player_weapon_cfg.weapon != status.weapon_list[status.weapon_index]:
					continue
			skill.cast_skill(skill_cfg,status.input_dir)
			status.stance = skill_player_weapon_cfg.stance_to
			refresh_input(i)
			return
	
func refresh_input(index:int):
	if index >= len(input_list)-1:
		input_list = []
	else:
		input_list = input_list.slice(index+1)

func update_move():
	status.move_dir = status.input_dir
	if status.is_skill_running:
		pass
	else:
		status.stance = Enum.EStance.Idle if status.is_on_floor else Enum.EStance.AirIdle
		status.break_level = Enum.EBreakLevel.Walk
		
func add_input_action(action:String):
	var new_input = InputData.new()
	new_input.action = action
	new_input.alive_time = Setting.input_alive_time
	input_list.append(new_input)
	
func add_skill(action:String,skillCfg:SkillPlayerCfg):
	if not action in skill_map:
		skill_map[action] = []
	skill_map[action].append(skillCfg)

func remove_skill(action:String,skillCfg:SkillPlayerCfg):
	if not action in skill_map:
		return
	skill_map[action].filter(func(cfg): return cfg != skillCfg)

func add_weapon(weapon:WeaponCfg):
	status.weapon_list.append(weapon)
	for skill_player_weapon_res in Util.get_skill_player_weapon_by_weapon(weapon):
		var skill_player_weapon = skill_player_weapon_res as SkillPlayerCfg
		add_skill(skill_player_weapon.action,skill_player_weapon_res)
	status.emit_status("weapon_list")
	status.set_status("weapon_index",0)

func weapon_index_change(dir:int):
	if not status.weapon_list:
		return
	if status.weapon_index_change_dir:
		return
	if abs(dir) != 1:
		return
	status.set_status("weapon_index_change_dir",dir)
	character.add_buff("weapon_index_change",Setting.weapon_anime_duration)
