class_name ContentDB
extends RefCounted
## Loads authored world content (/content) and cross-checks origin references.
## Mirrors api/app/content.py so client and api resolve ids identically. This is
## content integrity, distinct from JSON-schema validation.

var locations: Dictionary = {}
var npcs: Dictionary = {}
var quests: Dictionary = {}
var items: Dictionary = {}


static func default_content_root() -> String:
	return ProjectSettings.globalize_path("res://").path_join("../content").simplify_path()


static func origin_path(id: String) -> String:
	return default_content_root().path_join("origins").path_join("%s.json" % id)


static func load_json(abs_path: String) -> Variant:
	var text := FileAccess.get_file_as_string(abs_path)
	return JSON.parse_string(text)


func load_from(content_root: String) -> void:
	var world := content_root.path_join("world")
	locations = _load_dir(world.path_join("locations"))
	npcs = _load_dir(world.path_join("npcs"))
	quests = _load_dir(world.path_join("quests"))
	items = _load_dir(world.path_join("items"))


func _load_dir(dir_path: String) -> Dictionary:
	var out: Dictionary = {}
	var dir := DirAccess.open(dir_path)
	if dir == null:
		push_error("content dir not found: %s" % dir_path)
		return out
	for file in dir.get_files():
		if not file.ends_with(".json"):
			continue
		var data: Variant = load_json(dir_path.path_join(file))
		if typeof(data) != TYPE_DICTIONARY or not data.has("id"):
			push_error("bad content file: %s" % file)
			continue
		out[data["id"]] = data
	return out


func location(id: String) -> Dictionary: return locations.get(id, {})
func npc(id: String) -> Dictionary: return npcs.get(id, {})
func quest(id: String) -> Dictionary: return quests.get(id, {})
func item(id: String) -> Dictionary: return items.get(id, {})
func has_location(id: String) -> bool: return locations.has(id)
func has_npc(id: String) -> bool: return npcs.has(id)
func has_quest(id: String) -> bool: return quests.has(id)
func has_item(id: String) -> bool: return items.has(id)


func companions() -> Array:
	var out: Array = []
	for id in npcs:
		if npcs[id].get("role", "") == "companion":
			out.append(npcs[id])
	return out


func unresolved_refs(origin: Dictionary) -> Array:
	var missing: Array = []
	var loc: String = origin.get("start_location_id", "")
	if not has_location(loc):
		missing.append("location:%s" % loc)
	var q: Variant = origin.get("start_quest_id", null)
	if q != null and not has_quest(q):
		missing.append("quest:%s" % q)
	for grant in origin.get("inventory_grants", []):
		if not has_item(grant.get("item_id", "")):
			missing.append("item:%s" % grant.get("item_id", ""))
	for npc_id in origin.get("disposition_overrides", {}):
		if not has_npc(npc_id):
			missing.append("npc:%s" % npc_id)
	return missing
