class_name RTSCamera
extends Camera3D

## RTS 스타일 탑다운 3D 카메라 컨트롤러
## 키보드(WASD) 및 마우스 경계 스크롤로 평면을 이동하고 마우스 휠로 줌 조작이 가능합니다.

# 이동 및 줌 속도 설정
@export var move_speed: float = 25.0
@export var zoom_speed: float = 10.0
@export var zoom_step: float = 2.0

# 줌 범위 설정
@export var min_zoom: float = 5.0
@export var max_zoom: float = 15.0

# 화면 가장자리 마우스 감지 여백 (픽셀 단위)
@export var edge_margin: float = 15.0
@export var enable_edge_scroll: bool = true

# 맵 카메라 이동 한계 설정 (바닥 크기 20x20 기준)
@export var limit_min: Vector2 = Vector2(-8.0, -8.0)
@export var limit_max: Vector2 = Vector2(8.0, 8.0)

# 현재 카메라가 바라보고 있는 바닥의 포커스 좌표 (이곳을 중심으로 회전 및 줌이 일어남)
var _target_focus: Vector3 = Vector3.ZERO
var _current_zoom: float = 10.0
var _target_zoom: float = 10.0


func _ready() -> void:
	# 초기 카메라 위치를 기준으로 포커스 좌표 역계산
	# pitch 각도를 60도로 설정 (main.tscn 기본값)
	var angle_rad: float = deg_to_rad(60.0)
	_current_zoom = global_position.y
	_target_zoom = _current_zoom
	
	# Z 오프셋 = Y / tan(60) 이므로, 포커스 타겟 Z = 카메라 Z - Z 오프셋
	var z_offset: float = _current_zoom / tan(angle_rad)
	_target_focus = Vector3(global_position.x, 0.0, global_position.z - z_offset)
	
	# 초기 셋업 적용
	_update_camera_transform(0.0)

func _physics_process(delta: float) -> void:
	# 1. 입력 방향 계산
	var direction: Vector3 = _get_input_direction()
	
	# 줌아웃이 최대치(max_zoom) 근처일 때는 카메라 이동을 차단하고 맵 중앙으로 초점을 부드럽게 복구
	var is_max_zoom: bool = _target_zoom >= (max_zoom - 0.1)
	
	# 2. 포커스 타겟 이동
	if is_max_zoom:
		_target_focus = _target_focus.lerp(Vector3.ZERO, delta * move_speed * 0.2)
	elif direction != Vector3.ZERO:
		_target_focus += direction * move_speed * delta
		_target_focus.x = clampf(_target_focus.x, limit_min.x, limit_max.x)
		_target_focus.z = clampf(_target_focus.z, limit_min.y, limit_max.y)
	
	# 3. 줌 레벨 선형 보간
	if not is_equal_approx(_current_zoom, _target_zoom):
		_current_zoom = lerpf(_current_zoom, _target_zoom, delta * zoom_speed)
	
	# 4. 카메라 위치 및 회전 업데이트
	_update_camera_transform(delta)

func _unhandled_input(event: InputEvent) -> void:
	# 마우스 휠을 통한 줌 조작
	if event is InputEventMouseButton:
		var mouse_event: InputEventMouseButton = event as InputEventMouseButton
		if mouse_event.is_pressed():
			if mouse_event.button_index == MOUSE_BUTTON_WHEEL_UP:
				_target_zoom = clampf(_target_zoom - zoom_step, min_zoom, max_zoom)
			elif mouse_event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
				_target_zoom = clampf(_target_zoom + zoom_step, min_zoom, max_zoom)

## 입력 방향 계산 (키보드 WASD/방향키 + 마우스 경계 스크롤)
func _get_input_direction() -> Vector3:
	var dir: Vector3 = Vector3.ZERO
	
	# 키보드 입력 체크
	if Input.is_key_pressed(KEY_A) or Input.is_action_pressed("ui_left"):
		dir.x -= 1.0
	if Input.is_key_pressed(KEY_D) or Input.is_action_pressed("ui_right"):
		dir.x += 1.0
	if Input.is_key_pressed(KEY_W) or Input.is_action_pressed("ui_up"):
		dir.z -= 1.0
	if Input.is_key_pressed(KEY_S) or Input.is_action_pressed("ui_down"):
		dir.z += 1.0
		
	# 마우스 경계 스크롤 체크
	if enable_edge_scroll:
		var viewport: Viewport = get_viewport()
		if viewport:
			var mouse_pos: Vector2 = viewport.get_mouse_position()
			var viewport_size: Vector2 = viewport.get_visible_rect().size
			
			# 마우스 포인터가 화면 크기 안에 있을 때만 스크롤 수행 (창 밖 이탈 방지)
			if mouse_pos.x >= 0.0 and mouse_pos.y >= 0.0 and mouse_pos.x <= viewport_size.x and mouse_pos.y <= viewport_size.y:
				if mouse_pos.x < edge_margin:
					dir.x -= 1.0
				elif mouse_pos.x > viewport_size.x - edge_margin:
					dir.x += 1.0
				if mouse_pos.y < edge_margin:
					dir.z -= 1.0
				elif mouse_pos.y > viewport_size.y - edge_margin:
					dir.z += 1.0
					
	return dir.normalized()

## 카메라의 Position과 Rotation을 업데이트
func _update_camera_transform(_delta: float) -> void:
	# 피치 각도 60도 고정
	var angle_rad: float = deg_to_rad(60.0)
	var z_offset: float = _current_zoom / tan(angle_rad)
	
	# 카메라 글로벌 좌표 설정
	global_position.x = _target_focus.x
	global_position.y = _current_zoom
	global_position.z = _target_focus.z + z_offset
	
	# 포커스 좌표를 바라보도록 설정
	look_at(_target_focus, Vector3.UP)
