package declarations

import raw "gododin:bindings/raw"
import godot "gododin:bindings/typed/godot"
import gd "gododin:bindings/typed/call"

@(gododin_class="Resource")
Root_Settings :: struct {
	seed: i64 `godot:"property"`,
}

// Curve supplies a real engine Resource base with its own state and methods.
@(gododin_class="Curve")
Region_Settings :: struct {
	seed: i64 `godot:"property"`,
	factory_calls: i64,
}

// The bridge resolves self before the nested engine construction. Growing this
// same class's registry must preserve that already borrowed state pointer.
@(gododin)
region_settings_fork :: proc(self: ^Region_Settings, call: gd.Main_Call, result: gd.Construct(Region_Settings)) -> bool {
	if gd.validate_main_call(call) != .None do return false
	self.factory_calls += 1
	gd.instance(result).seed = self.seed + 1
	return true
}

@(gododin)
region_settings_factory_calls :: proc(self: ^Region_Settings) -> i64 { return self.factory_calls }

// resource_probe resolves the dispatch's engine object through the scoped
// capability, converts it to the declared engine base with the generated
// checked cast, and reads real engine Resource state Godot wrote through the
// Curve API. No binder table, no state-to-engine cast.
@(gododin)
region_settings_resource_probe :: proc(self: ^Region_Settings, call: gd.Main_Call) -> f64 {
	_ = self
	object, ok := gd.self(call)
	if !ok do return -1
	curve, cast_ok := godot.cast_Curve(gd.godot_main_call(call), &object)
	if !cast_ok do return -2
	maximum, read_error := godot.curve_get_max_value(gd.godot_main_call(call), curve)
	if read_error != .None do return -3
	return f64(maximum)
}

@(gododin_class="Node2D")
Native_Region_2D :: struct {
	seed: i64 `godot:"property"`,
	settings: gd.Ref(Region_Settings) `godot:"property"`,
	ready_count: i64,
	process_count: i64,
	engine_checks: i64,
}

@(gododin_virtual="_ready")
native_region_2d_ready :: proc(self: ^Native_Region_2D, call: gd.Main_Call) {
	if gd.validate_main_call(call) == .None do self.ready_count += 1
}

@(gododin_virtual="_process")
native_region_2d_process :: proc(self: ^Native_Region_2D, call: gd.Main_Call, delta: f64) {
	_ = delta
	if gd.validate_main_call(call) == .None do self.process_count += 1
}

@(gododin)
native_region_2d_ready_count :: proc(self: ^Native_Region_2D) -> i64 { return self.ready_count }

@(gododin)
native_region_2d_process_count :: proc(self: ^Native_Region_2D) -> i64 { return self.process_count }

// Vec2 states the locked float_32 Vector2 layout as plain Odin data; the
// transmute is the whole conversion.
Vec2 :: struct #align(4) {
	x, y: f32,
}

// engine_probe is the ordinary engine-call path end to end: scoped self, the
// engine-validated checked cast, a parent lookup through the base handle, and
// a transform read that the body rewrites one unit right. Godot reads the
// moved transform back through its own API afterwards.
@(gododin)
native_region_2d_engine_probe :: proc(self: ^Native_Region_2D, call: gd.Main_Call) -> i64 {
	object, ok := gd.self(call)
	if !ok do return -1
	region, cast_ok := godot.cast_Node2D(gd.godot_main_call(call), &object)
	if !cast_ok do return -2
	parent_value, parent_error := godot.node_get_parent(gd.godot_main_call(call), cast(^godot.Node)region)
	if parent_error != .None do return -3
	if parent_value.ptr == nil do return -4
	siblings, count_error := godot.node_get_child_count(gd.godot_main_call(call), &parent_value, false)
	if count_error != .None do return -5
	storage, read_error := godot.node2d_get_position(gd.godot_main_call(call), region)
	if read_error != .None do return -6
	position := transmute(Vec2)storage
	if position.x != f32(self.seed-1) do return -7
	moved := transmute(raw.Vector2)Vec2{x = position.x + 1, y = position.y}
	if write_error := godot.node2d_set_position(gd.godot_main_call(call), region, moved); write_error != .None do return -8
	self.engine_checks += 1
	return i64(siblings)
}

// settings_probe walks the owned-reference property: the bridge's Ref token
// records the settings' engine ObjectID, the scoped capability resolves it to
// a checked borrow, and the checked cast admits it as the engine Curve base.
@(gododin)
native_region_2d_settings_probe :: proc(self: ^Native_Region_2D, call: gd.Main_Call) -> f64 {
	_ = self
	if self.settings.object_id == 0 do return -1
	settings, ok := gd.instance_borrow_main(call, self.settings.object_id)
	if !ok do return -2
	curve, cast_ok := godot.cast_Curve(gd.godot_main_call(call), &settings)
	if !cast_ok do return -3
	maximum, read_error := godot.curve_get_max_value(gd.godot_main_call(call), curve)
	if read_error != .None do return -4
	points, points_error := godot.curve_get_point_count(gd.godot_main_call(call), curve)
	if points_error != .None do return -5
	if points != 2 do return -6
	point_one, point_error := godot.curve_get_point_position(gd.godot_main_call(call), curve, 1)
	if point_error != .None do return -7
	pos := transmute(Vec2)point_one
	if pos.y != 0.75 do return -8
	return f64(maximum)
}

@(gododin_class="Node3D")
Native_Region_3D :: struct {
	seed: i64 `godot:"property"`,
	ready_count: i64,
	process_count: i64,
	engine_checks: i64,
}

@(gododin_virtual="_ready")
native_region_3d_ready :: proc(self: ^Native_Region_3D, call: gd.Main_Call) {
	if gd.validate_main_call(call) == .None do self.ready_count += 1
}

@(gododin_virtual="_process")
native_region_3d_process :: proc(self: ^Native_Region_3D, call: gd.Main_Call, delta: f64) {
	_ = delta
	if gd.validate_main_call(call) == .None do self.process_count += 1
}

@(gododin)
native_region_3d_ready_count :: proc(self: ^Native_Region_3D) -> i64 { return self.ready_count }

@(gododin)
native_region_3d_process_count :: proc(self: ^Native_Region_3D) -> i64 { return self.process_count }

// Vec3 states the locked float_32 Vector3 layout as plain Odin data.
Vec3 :: struct #align(4) {
	x, y, z: f32,
}

@(gododin)
native_region_3d_engine_probe :: proc(self: ^Native_Region_3D, call: gd.Main_Call) -> i64 {
	object, ok := gd.self(call)
	if !ok do return -1
	region, cast_ok := godot.cast_Node3D(gd.godot_main_call(call), &object)
	if !cast_ok do return -2
	storage, read_error := godot.node3d_get_position(gd.godot_main_call(call), region)
	if read_error != .None do return -3
	position := transmute(Vec3)storage
	if position.x != f32(self.seed-1) do return -4
	moved := transmute(raw.Vector3)Vec3{x = position.x, y = position.y, z = position.z + 1}
	if write_error := godot.node3d_set_position(gd.godot_main_call(call), region, moved); write_error != .None do return -5
	self.engine_checks += 1
	return self.seed
}
