extends Node

## CardDatabase - Singleton for managing card data
## Loads card definitions from JSON and provides lookup methods

const CARDS_PATH = "res://data/cards.json"

# Loaded card data
var _cards: Dictionary = {}  # id -> CardData
var _cards_by_element: Dictionary = {}  # Element -> Array[CardData]
var _cards_by_type: Dictionary = {}  # CardType -> Array[CardData]
var _card_textures: Dictionary = {}  # id -> Texture2D

# Signals
signal database_loaded
signal load_error(message: String)

func _ready() -> void:
	_load_database()

func _load_database() -> void:
	var file = FileAccess.open(CARDS_PATH, FileAccess.READ)
	if not file:
		push_error("Failed to open cards database: " + CARDS_PATH)
		load_error.emit("Failed to open cards database")
		return

	var json_text = file.get_as_text()
	file.close()

	var json = JSON.new()
	var error = json.parse(json_text)
	if error != OK:
		push_error("Failed to parse cards JSON: " + json.get_error_message())
		load_error.emit("Failed to parse cards JSON")
		return

	var data = json.get_data()
	if not data.has("cards"):
		push_error("Cards database missing 'cards' array")
		load_error.emit("Invalid database format")
		return

	# Initialize element and type dictionaries
	for element in Enums.Element.values():
		_cards_by_element[element] = []
	for card_type in Enums.CardType.values():
		_cards_by_type[card_type] = []

	# Parse cards
	for card_data in data["cards"]:
		var card = _parse_card(card_data)
		if card:
			_cards[card.id] = card

			# Index by element(s)
			for element in card.elements:
				_cards_by_element[element].append(card)

			# Index by type
			_cards_by_type[card.type].append(card)

	print("CardDatabase: Loaded ", _cards.size(), " cards")
	database_loaded.emit()

func _parse_card(data: Dictionary) -> CardData:
	var card = CardData.new()

	# Required fields
	if not data.has("id") or not data.has("name") or not data.has("type") or not data.has("element") or not data.has("cost"):
		push_error("Card missing required fields: " + str(data))
		return null

	card.id = data["id"]
	card.name = data["name"]
	card.type = Enums.card_type_from_string(data["type"])
	card.cost = data["cost"]

	# Parse element (can be string or array)
	if data["element"] is Array:
		for elem_str in data["element"]:
			card.elements.append(Enums.element_from_string(elem_str))
	else:
		card.elements.append(Enums.element_from_string(data["element"]))

	# Optional fields
	card.power = data.get("power", 0) if data.get("power") != null else 0
	card.job = data.get("job", "") if data.get("job") != null else ""
	card.category = data.get("category", "") if data.get("category") != null else ""
	card.is_generic = data.get("is_generic", false) if data.get("is_generic") != null else false
	card.has_ex_burst = data.get("has_ex_burst", false) if data.get("has_ex_burst") != null else false
	card.image_path = data.get("image", "") if data.get("image") != null else ""

	# Parse abilities
	if data.has("abilities"):
		for ability_data in data["abilities"]:
			var ability = _parse_ability(ability_data)
			if ability:
				card.abilities.append(ability)

	return card

func _parse_ability(data: Dictionary) -> AbilityData:
	var ability = AbilityData.new()

	if not data.has("type") or not data.has("effect"):
		push_error("Ability missing required fields")
		return null

	match data["type"].to_lower():
		"field": ability.type = Enums.AbilityType.FIELD
		"auto": ability.type = Enums.AbilityType.AUTO
		"action": ability.type = Enums.AbilityType.ACTION
		"special": ability.type = Enums.AbilityType.SPECIAL

	ability.effect = data["effect"]
	ability.name = data.get("name", "")
	ability.trigger = data.get("trigger", "")
	ability.is_ex_burst = data.get("is_ex_burst", false)

	# Parse cost if present
	if data.has("cost"):
		ability.cost = _parse_cost(data["cost"])

	return ability

func _parse_cost(data: Dictionary) -> CostData:
	var cost = CostData.new()

	cost.generic = data.get("generic", 0)
	cost.fire = data.get("fire", 0)
	cost.ice = data.get("ice", 0)
	cost.wind = data.get("wind", 0)
	cost.lightning = data.get("lightning", 0)
	cost.water = data.get("water", 0)
	cost.earth = data.get("earth", 0)
	cost.light = data.get("light", 0)
	cost.dark = data.get("dark", 0)
	cost.requires_dull = data.get("dull", false)
	cost.discard_count = data.get("discard", 0)
	cost.specific_discard = data.get("specific_discard", "")

	return cost

## Get a card by ID
func get_card(id: String) -> CardData:
	return _cards.get(id)

## Get all cards
func get_all_cards() -> Array:
	return _cards.values()

## Get cards by element
func get_cards_by_element(element: Enums.Element) -> Array:
	return _cards_by_element.get(element, [])

## Get cards by type
func get_cards_by_type(card_type: Enums.CardType) -> Array:
	return _cards_by_type.get(card_type, [])

## Get or load a card texture
func get_card_texture(card: CardData) -> Texture2D:
	if card.id in _card_textures:
		return _card_textures[card.id]

	if card.image_path.is_empty():
		return null

	var texture_path = "res://assets/cards/" + card.image_path
	if ResourceLoader.exists(texture_path):
		var texture = load(texture_path)
		_card_textures[card.id] = texture
		return texture

	return null

## Create a list of card IDs for a deck (for testing)
func create_test_deck(_player_index: int) -> Array[String]:
	var deck: Array[String] = []

	# Get all cards and create a 50-card deck
	var all_cards = get_all_cards()

	# Add 3 copies of each card until we have 50
	for card in all_cards:
		if deck.size() >= 50:
			break
		# Add up to 3 copies
		for i in range(3):
			if deck.size() >= 50:
				break
			deck.append(card.id)

	# Fill remaining slots if needed
	while deck.size() < 50 and all_cards.size() > 0:
		deck.append(all_cards[0].id)

	return deck


## Data Classes

class CardData:
	var id: String = ""
	var name: String = ""
	var type: Enums.CardType = Enums.CardType.FORWARD
	var elements: Array[Enums.Element] = []
	var cost: int = 0
	var power: int = 0
	var job: String = ""
	var category: String = ""
	var is_generic: bool = false
	var has_ex_burst: bool = false
	var image_path: String = ""
	var abilities: Array[AbilityData] = []

	func get_primary_element() -> Enums.Element:
		if elements.size() > 0:
			return elements[0]
		return Enums.Element.FIRE

	func is_multi_element() -> bool:
		return elements.size() > 1

class AbilityData:
	var type: Enums.AbilityType = Enums.AbilityType.FIELD
	var name: String = ""
	var effect: String = ""
	var trigger: String = ""
	var is_ex_burst: bool = false
	var cost: CostData = null

class CostData:
	var generic: int = 0
	var fire: int = 0
	var ice: int = 0
	var wind: int = 0
	var lightning: int = 0
	var water: int = 0
	var earth: int = 0
	var light: int = 0
	var dark: int = 0
	var requires_dull: bool = false
	var discard_count: int = 0
	var specific_discard: String = ""

	func get_total_cp() -> int:
		return generic + fire + ice + wind + lightning + water + earth + light + dark

	func get_element_requirements() -> Dictionary:
		var reqs = {}
		if fire > 0: reqs[Enums.Element.FIRE] = fire
		if ice > 0: reqs[Enums.Element.ICE] = ice
		if wind > 0: reqs[Enums.Element.WIND] = wind
		if lightning > 0: reqs[Enums.Element.LIGHTNING] = lightning
		if water > 0: reqs[Enums.Element.WATER] = water
		if earth > 0: reqs[Enums.Element.EARTH] = earth
		if light > 0: reqs[Enums.Element.LIGHT] = light
		if dark > 0: reqs[Enums.Element.DARK] = dark
		return reqs
