class_name WallRenderer
extends Node2D

## Renders wall textures by sampling segments from the aux_terrain texture atlas
## and compositing them onto tile edges. Each edge is made of two half-segments.

## Source atlas rects (x, y, w, h) from aux_terrain.BMP
## Each edge has two half-segments that together span the full tile edge.

# -- Left edge --
const LEFT_UPPER_RECT := Rect2(0, 103, 20, 50)
const LEFT_LOWER_RECT := Rect2(0, 53, 20, 50)

# -- Right edge --
const RIGHT_UPPER_RECT := Rect2(186, 103, 20, 50)
const RIGHT_LOWER_RECT := Rect2(186, 53, 20, 50)

# -- Top edge --
const TOP_LEFT_RECT := Rect2(103, 0, 50, 20)
const TOP_RIGHT_RECT := Rect2(53, 0, 50, 20)

# -- Bottom edge --
const BOTTOM_LEFT_RECT := Rect2(103, 186, 50, 20)
const BOTTOM_RIGHT_RECT := Rect2(53, 186, 50, 20)

# -- Inner corners (drawn where two perpendicular wall edges meet) --
const INNER_CORNER_UPPER_LEFT_RECT := Rect2(0, 0, 50, 50)
const INNER_CORNER_UPPER_RIGHT_RECT := Rect2(156, 0, 50, 50)
const INNER_CORNER_LOWER_LEFT_RECT := Rect2(0, 156, 50, 50)
const INNER_CORNER_LOWER_RIGHT_RECT := Rect2(156, 156, 50, 50)

# -- Openings (drawn on top of wall segments at doorway edges) --
## Vertical opening: tiles separated on y-axis (north-south doorway through a horizontal wall)
const VERTICAL_OPENING_RECT := Rect2(206, 36, 36, 42)
## Horizontal opening: tiles separated on x-axis (east-west doorway through a vertical wall)
const HORIZONTAL_OPENING_RECT := Rect2(210, 0, 41, 32)

## Wall thickness in game pixels (how far the border extends into the tile)
const WALL_THICKNESS := 20.0
## Inner corner piece size in game pixels (quarter of a tile)
const CORNER_SIZE := 50.0
## Half the tile edge length
var HALF_EDGE: float:
	get:
		return BattleMapHelper.TILE_SIZE / 2.0

@export var atlas_texture: Texture2D

# Each entry is [dest_rect: Rect2, source_rect: Rect2]
var _segments: Array = []


func draw_walls_for_layout(map_layout: MapLayout) -> void:
	_segments.clear()
	if not map_layout or not atlas_texture:
		queue_redraw()
		return

	var tile_edges := _collect_tile_edges(map_layout)
	for tile in tile_edges:
		var edges: Array = tile_edges[tile]
		_build_tile_walls(tile, edges)
	_build_opening_sprites(map_layout)
	queue_redraw()


func _draw() -> void:
	if not atlas_texture:
		return
	for seg in _segments:
		draw_texture_rect_region(atlas_texture, seg[0], seg[1])


func _collect_tile_edges(map_layout: MapLayout) -> Dictionary:
	## Returns {Vector2i: Array[StringName]} mapping each tile to its wall edge directions.
	## Includes both true walls and opening edges, so wall sprites are drawn underneath openings.
	var tile_edges: Dictionary = {}
	for edge_pair in map_layout.get_walls():
		_add_edge_pair(tile_edges, edge_pair, map_layout)
	for edge_pair in map_layout.get_openings():
		_add_edge_pair(tile_edges, edge_pair, map_layout)
	return tile_edges


func _add_edge_pair(tile_edges: Dictionary, edge_pair: Array, map_layout: MapLayout) -> void:
	var tile_a: Vector2i = edge_pair[0]
	var tile_b: Vector2i = edge_pair[1]
	var diff: Vector2i = tile_b - tile_a

	var edge_a := _direction_to_edge(diff)
	if edge_a != &"":
		if not tile_edges.has(tile_a):
			tile_edges[tile_a] = []
		tile_edges[tile_a].append(edge_a)

	var edge_b := _direction_to_edge(-diff)
	if edge_b != &"" and map_layout.is_tile_valid(tile_b):
		if not tile_edges.has(tile_b):
			tile_edges[tile_b] = []
		tile_edges[tile_b].append(edge_b)


func _direction_to_edge(dir: Vector2i) -> StringName:
	match dir:
		Vector2i.RIGHT:
			return &"right"
		Vector2i.LEFT:
			return &"left"
		Vector2i.UP:
			return &"top"
		Vector2i.DOWN:
			return &"bottom"
	return &""


func _build_tile_walls(tile: Vector2i, edges: Array) -> void:
	var tile_origin := Vector2(tile) * BattleMapHelper.TILE_SIZE

	for edge in edges:
		_build_edge_segments(tile_origin, edge)

	# TODO: Outer corner segments
	_build_outer_corners(tile, tile_origin, edges)

	# Inner corner segments (for non-rectangular room support)
	_build_inner_corners(tile, tile_origin, edges)


func _build_edge_segments(tile_origin: Vector2, edge: StringName) -> void:
	var seg_a_rect: Rect2
	var seg_b_rect: Rect2
	var seg_a_offset: Vector2
	var seg_b_offset: Vector2
	var seg_a_size: Vector2
	var seg_b_size: Vector2

	match edge:
		&"left":
			seg_a_rect = LEFT_UPPER_RECT
			seg_b_rect = LEFT_LOWER_RECT
			seg_a_size = Vector2(WALL_THICKNESS, HALF_EDGE)
			seg_b_size = Vector2(WALL_THICKNESS, HALF_EDGE)
			seg_a_offset = Vector2(0, 0)
			seg_b_offset = Vector2(0, HALF_EDGE)
		&"right":
			seg_a_rect = RIGHT_UPPER_RECT
			seg_b_rect = RIGHT_LOWER_RECT
			seg_a_size = Vector2(WALL_THICKNESS, HALF_EDGE)
			seg_b_size = Vector2(WALL_THICKNESS, HALF_EDGE)
			seg_a_offset = Vector2(BattleMapHelper.TILE_SIZE - WALL_THICKNESS, 0)
			seg_b_offset = Vector2(BattleMapHelper.TILE_SIZE - WALL_THICKNESS, HALF_EDGE)
		&"top":
			seg_a_rect = TOP_LEFT_RECT
			seg_b_rect = TOP_RIGHT_RECT
			seg_a_size = Vector2(HALF_EDGE, WALL_THICKNESS)
			seg_b_size = Vector2(HALF_EDGE, WALL_THICKNESS)
			seg_a_offset = Vector2(0, 0)
			seg_b_offset = Vector2(HALF_EDGE, 0)
		&"bottom":
			seg_a_rect = BOTTOM_LEFT_RECT
			seg_b_rect = BOTTOM_RIGHT_RECT
			seg_a_size = Vector2(HALF_EDGE, WALL_THICKNESS)
			seg_b_size = Vector2(HALF_EDGE, WALL_THICKNESS)
			seg_a_offset = Vector2(0, BattleMapHelper.TILE_SIZE - WALL_THICKNESS)
			seg_b_offset = Vector2(HALF_EDGE, BattleMapHelper.TILE_SIZE - WALL_THICKNESS)

	_queue_segment(tile_origin + seg_a_offset, seg_a_size, seg_a_rect)
	_queue_segment(tile_origin + seg_b_offset, seg_b_size, seg_b_rect)


func _queue_segment(pos: Vector2, target_size: Vector2, source_rect: Rect2) -> void:
	_segments.append([Rect2(pos, target_size), source_rect])


func _build_opening_sprites(map_layout: MapLayout) -> void:
	## Composites opening (doorway) sprites on top of the wall segments at opening edges.
	## Each opening is split in half across the shared edge, half drawn on each tile.
	for opening in map_layout.get_openings():
		var tile_a: Vector2i = opening[0]
		var tile_b: Vector2i = opening[1]
		var diff: Vector2i = tile_b - tile_a

		# Normalize so the pair is ordered along the positive axis (tile_a < tile_b).
		if diff == Vector2i.LEFT or diff == Vector2i.UP:
			var swap := tile_a
			tile_a = tile_b
			tile_b = swap
			diff = -diff

		var origin_a := Vector2(tile_a) * BattleMapHelper.TILE_SIZE
		var origin_b := Vector2(tile_b) * BattleMapHelper.TILE_SIZE

		if diff == Vector2i.DOWN:
			_queue_vertical_opening(origin_a, origin_b)
		elif diff == Vector2i.RIGHT:
			_queue_horizontal_opening(origin_a, origin_b)


func _queue_vertical_opening(origin_upper: Vector2, origin_lower: Vector2) -> void:
	# Vertical opening: tiles vertically adjacent; horizontal wall edge between them.
	var src := VERTICAL_OPENING_RECT
	var w: float = src.size.x
	var h_total: float = src.size.y
	var h_upper: float = floorf(h_total / 2.0)  # 14
	var h_lower: float = h_total - h_upper       # 15
	var x_offset := (BattleMapHelper.TILE_SIZE - w) / 2.0
	var src_upper := Rect2(src.position, Vector2(w, h_upper))
	var src_lower := Rect2(src.position + Vector2(0, h_upper), Vector2(w, h_lower))
	_queue_segment(origin_upper + Vector2(x_offset, BattleMapHelper.TILE_SIZE - h_upper), Vector2(w, h_upper), src_upper)
	_queue_segment(origin_lower + Vector2(x_offset, 0), Vector2(w, h_lower), src_lower)


func _queue_horizontal_opening(origin_left: Vector2, origin_right: Vector2) -> void:
	# Horizontal opening: tiles horizontally adjacent; vertical wall edge between them.
	var src := HORIZONTAL_OPENING_RECT
	var w_total: float = src.size.x
	var h: float = src.size.y
	var w_left: float = floorf(w_total / 2.0)  # 14
	var w_right: float = w_total - w_left       # 14
	var y_offset := (BattleMapHelper.TILE_SIZE - h) / 2.0
	var src_left := Rect2(src.position, Vector2(w_left, h))
	var src_right := Rect2(src.position + Vector2(w_left, 0), Vector2(w_right, h))
	_queue_segment(origin_left + Vector2(BattleMapHelper.TILE_SIZE - w_left, y_offset), Vector2(w_left, h), src_left)
	_queue_segment(origin_right + Vector2(0, y_offset), Vector2(w_right, h), src_right)


func _build_outer_corners(_tile: Vector2i, _tile_origin: Vector2, _edges: Array) -> void:
	# TODO: Implement outer corner segments
	# Check pairs of adjacent edges (e.g., "top" + "left" → top-left outer corner)
	# and draw the corner piece from the atlas.
	pass


func _build_inner_corners(_tile: Vector2i, tile_origin: Vector2, edges: Array) -> void:
	## Draws decorative corner pieces wherever two perpendicular wall edges meet
	## on the same tile (e.g., a top wall + left wall produces an upper-left corner).
	var has_top := edges.has(&"top")
	var has_bottom := edges.has(&"bottom")
	var has_left := edges.has(&"left")
	var has_right := edges.has(&"right")
	var corner_size := Vector2(CORNER_SIZE, CORNER_SIZE)

	if has_top and has_left:
		_queue_segment(
			tile_origin + Vector2(0, 0),
			corner_size,
			INNER_CORNER_UPPER_LEFT_RECT
		)
	if has_top and has_right:
		_queue_segment(
			tile_origin + Vector2(BattleMapHelper.TILE_SIZE - CORNER_SIZE, 0),
			corner_size,
			INNER_CORNER_UPPER_RIGHT_RECT
		)
	if has_bottom and has_left:
		_queue_segment(
			tile_origin + Vector2(0, BattleMapHelper.TILE_SIZE - CORNER_SIZE),
			corner_size,
			INNER_CORNER_LOWER_LEFT_RECT
		)
	if has_bottom and has_right:
		_queue_segment(
			tile_origin + Vector2(BattleMapHelper.TILE_SIZE - CORNER_SIZE, BattleMapHelper.TILE_SIZE - CORNER_SIZE),
			corner_size,
			INNER_CORNER_LOWER_RIGHT_RECT
		)
