class_name GeneratorBuffData
extends Resource

enum BuffKind {
	AUTO_PRODUCTION_MULTIPLIER,
	MANUAL_CLICK_MULTIPLIER,
	RESOURCE_PURCHASE,
}

const HUGE_EXPONENT: int = 1000000

@export var id: StringName = &""
@export var target_ids: Array[StringName] = []
@export var kind: BuffKind = BuffKind.AUTO_PRODUCTION_MULTIPLIER
@export_multiline var text: String = ""
@export var icon: Texture2D
@export var max_level: int = -1

@export_group("Unlock")
@export var unlocked: bool = false
@export var unlock_goal: GoalData

@export_group("Effect")
@export var base_effect: float = 1.0
@export var effect_increment: float = 0.1

@export_group("Cost")
@export var cost_currency: Currency
@export var base_cost_mantissa: float = 10.0
@export var base_cost_exponent: int = 0
@export var cost_multiplier: float = 1.5

@export_group("Resource Purchase")
@export var resource_target_currency: Currency
@export var resource_purchase_base_mantissa: float = 10.0
@export var resource_purchase_base_exponent: int = 0
@export var resource_purchase_increment_multiplier: float = 1.2

func targets_generator(generator_id: StringName) -> bool:
	if target_ids.is_empty():
		return false
	
	if target_ids.has("*"):
		return true
	
	return target_ids.has(generator_id)

func get_target_generators() -> Array[StringName]:
	return target_ids.duplicate()

func has_unlock_goal() -> bool:
	if unlock_goal == null:
		return false

	return bool(unlock_goal.is_valid())

func get_unlock_goal_amount() -> BigNumber:
	if unlock_goal == null:
		return BigNumber.from_float(0.0)

	var valid_requirements: Array[GoalRequirementData] = unlock_goal.get_valid_requirements()
	if valid_requirements.is_empty():
		return BigNumber.from_float(0.0)
	var requirement_resource: GoalRequirementData = valid_requirements[0]
	if requirement_resource == null:
		return BigNumber.from_float(0.0)

	var required_amount: Variant = requirement_resource.get_amount()
	if required_amount is BigNumber:
		return required_amount

	return BigNumber.from_float(0.0)

func get_unlock_goal_currency() -> Currency:
	if unlock_goal == null:
		return null

	var valid_requirements: Array[GoalRequirementData] = unlock_goal.get_valid_requirements()
	if valid_requirements.is_empty():
		return null
	var requirement_resource: GoalRequirementData = valid_requirements[0]
	if requirement_resource == null:
		return null

	return requirement_resource.currency

func can_purchase_next_level(current_level: int) -> bool:
	if max_level < 0:
		return true
	return maxi(current_level, 0) < max_level

func get_effect_multiplier(level: int) -> float:
	var safe_level: int = maxi(level, 0)
	return maxf(base_effect + (effect_increment * float(safe_level)), 0.0)

func get_cost_for_level(level: int) -> BigNumber:
	var safe_level: int = maxi(level, 0)
	var base_cost: BigNumber = BigNumber.new(base_cost_mantissa, base_cost_exponent)
	if base_cost.mantissa <= 0.0:
		return BigNumber.from_float(0.0)

	if cost_multiplier <= 0.0:
		return BigNumber.new(1.0, HUGE_EXPONENT)

	var growth: float = 1.0
	if not is_equal_approx(cost_multiplier, 1.0):
		growth = pow(cost_multiplier, float(safe_level))
	if not is_finite(growth):
		return BigNumber.new(1.0, HUGE_EXPONENT)

	return _scale_big_number(base_cost, growth)

func get_resource_purchase_amount_for_level(level: int) -> BigNumber:
	var safe_level: int = maxi(level, 0)
	var base_amount: BigNumber = BigNumber.new(resource_purchase_base_mantissa, resource_purchase_base_exponent)
	if base_amount.mantissa <= 0.0:
		return BigNumber.from_float(0.0)

	if resource_purchase_increment_multiplier <= 0.0:
		return BigNumber.from_float(0.0)

	var growth: float = 1.0
	if not is_equal_approx(resource_purchase_increment_multiplier, 1.0):
		growth = pow(resource_purchase_increment_multiplier, float(safe_level))
	if not is_finite(growth):
		return BigNumber.new(1.0, HUGE_EXPONENT)

	return _scale_big_number(base_amount, growth)

func get_effect_description(level: int) -> String:
	var safe_level: int = maxi(level, 0)
	match kind:
		BuffKind.AUTO_PRODUCTION_MULTIPLIER, BuffKind.MANUAL_CLICK_MULTIPLIER:
			return "x%.2f" % get_effect_multiplier(safe_level)
		BuffKind.RESOURCE_PURCHASE:
			return "+%s" % get_resource_purchase_amount_for_level(safe_level).to_string_suffix(2)
		_:
			return "-"

func _scale_big_number(base_amount: BigNumber, scale: float) -> BigNumber:
	if base_amount.mantissa <= 0.0:
		return BigNumber.from_float(0.0)
	if scale <= 0.0:
		return BigNumber.from_float(0.0)
	if not is_finite(scale):
		return BigNumber.new(1.0, HUGE_EXPONENT)

	return base_amount.multiply(BigNumber.from_float(scale))
