#scope_file

// @ToDo do a config tweak file thing like jblow has and add this there.
CAMERA_INACTIVE_TIME_TO_ORBIT :: 200000000.0;
MAX_CAMERA_DIST               :: 25.0;
MIN_CAMERA_DIST               :: 2.0;
DIST_SCROLL_SPEED             :: 0.8;

mouse2Active             : bool;
mouse2ActivationPosition : Vector2;
mouse3Active             : bool;
mouse3ActivationPosition : Vector2;

cameraTilt        : float = 0.2;
cameraDist        : float = 10.0;
cameraRotation    : float;
oldCameraRotation : float;
oldCameraTilt     : float;
cameraCenter      : Vector2;

trile_preview_disabled : bool = false;

#scope_export

toggle_preview :: () {
	trile_preview_disabled = !trile_preview_disabled;
} @Command

set_dist :: (dist: float) {
	cameraDist = dist;
} @Command

#scope_file

tacomaSamples    : s32   = 100;
tacomaResolution : s32   = 500;
tacomaExposure   : float = 1.0;
tacomaContrast   : float = 1.0;
tacomaSaturation : float = 1.0;

lastInputTime : float64;

editY : s32;

pointerHit : bool;
pointerX   : s32;
pointerY   : s32;

show_trile_preview : bool = true;
trile_preview_x    : int  = 0;
trile_preview_y    : int  = 0;
trile_preview_z    : int  = 0;

Level_Editor_Tab :: enum {
    TACOMA;
    TOOLS;
    INFO;  
};

current_tab : Level_Editor_Tab = .TOOLS;
get_level_editor_camera :: () -> Camera {
    camera: Camera;
    camera.near = 0.1;
    camera.far  = 5000;
	camera.target = .{cameraCenter.x, xx editY, cameraCenter.y};
	cameraDir : Vector3    = .{1, 0, 0};
    qrotation : Quaternion = .{cos(-cameraRotation/2.0),0,sin(-cameraRotation/2.0),0};
    qtilt     : Quaternion = .{cos(-cameraTilt/2.0),sin(-cameraTilt/2.0), 0, 0};

	rotate(*cameraDir, qrotation * qtilt);

	camera.position  = camera.target;
	camera.position += cameraDir * cameraDist;

	if is_in_reflection_pass {
		camera.position.y *= -1;
		camera.target.y *= -1;
	}
	
    return camera;
}


tick_level_editor_camera :: () {
    if console_open_ignore_input then return;

	if get_time() - lastInputTime > CAMERA_INACTIVE_TIME_TO_ORBIT { // idle rotating camera
		cameraRotation += cast(float) delta_time;
	}

	cameraSpeed :: 150;

	forward   : Vector3    = .{1, 0, 0};
    qrotation : Quaternion = .{cos(-cameraRotation/2.0),0,sin(-cameraRotation/2.0),0};
	
	rotate(*forward, qrotation);
	forward2d := Vector2.{forward.x, forward.z};

	left           : Vector3    = .{0, 0, 1};
    qrotation_left : Quaternion = .{cos(-cameraRotation/2.0),0,sin(-cameraRotation/2.0),0};
	rotate(*left, qrotation_left);
	left2d := Vector2.{left.x, left.z};
	
	cameraDist = clamp(cameraDist - mouse_delta_z * DIST_SCROLL_SPEED, 0.0, MAX_CAMERA_DIST);

	distRange : float = MAX_CAMERA_DIST - MIN_CAMERA_DIST;
	zoomCameraMovementMultiplier := 0.03 + ((cameraDist - MIN_CAMERA_DIST) / distRange) * 0.15; 
	 
	if input_button_states[#char "W"] & .DOWN {
		lastInputTime = get_time();
		cameraCenter += -cameraSpeed * zoomCameraMovementMultiplier * (xx delta_time) * forward2d;
	}
	if input_button_states[#char "S"] & .DOWN {
		lastInputTime = get_time();
		cameraCenter += cameraSpeed * zoomCameraMovementMultiplier * (xx delta_time) * forward2d;
	}

	if input_button_states[#char "A"] & .DOWN {
		lastInputTime = get_time();
		cameraCenter += -cameraSpeed * zoomCameraMovementMultiplier * (xx delta_time) * left2d;
	}
	if input_button_states[#char "D"] & .DOWN {
		lastInputTime = get_time();
		cameraCenter += cameraSpeed * zoomCameraMovementMultiplier * (xx delta_time) * left2d;
	}
	
	if input_button_states[Key_Code.ARROW_UP] & .START {
		lastInputTime = get_time();
		editY = min(editY + 1, 100);
	}

	if input_button_states[Key_Code.ARROW_DOWN] & .START {
		lastInputTime = get_time();
		editY = max(editY - 1, 0);
	}
	
	if get_mouse_state(Key_Code.MOUSE_BUTTON_MIDDLE) & .DOWN {
		if mouse2Active {
			lastInputTime = get_time();
			diff := mouse2ActivationPosition - Vector2.{input_mouse_x, input_mouse_y};
			diff *= 0.5;
			cameraRotation = oldCameraRotation + diff.x / 100;
			cameraTilt = oldCameraTilt - diff.y / 100;
			cameraTilt = max(0.1, cameraTilt);
			cameraTilt = min(PI/2.2, cameraTilt);
		} else {
			mouse2Active = true;
			mouse2ActivationPosition = Vector2.{input_mouse_x, input_mouse_y};
			oldCameraRotation = cameraRotation;
			oldCameraTilt = cameraTilt;
		}
	} else {
		mouse2Active = false;
	}


	if get_mouse_state(Key_Code.MOUSE_BUTTON_RIGHT) & .DOWN {
		if mouse3Active {
			lastInputTime = get_time();
			diff := mouse3ActivationPosition - Vector2.{input_mouse_x, input_mouse_y};
			cameraCenter = cameraCenter + forward2d * -diff.y * cast(float) delta_time * zoomCameraMovementMultiplier;
			cameraCenter = cameraCenter + left2d    * -diff.x * cast(float) delta_time * zoomCameraMovementMultiplier;
		} else {
			mouse3Active = true;
			mouse3ActivationPosition = Vector2.{input_mouse_x, input_mouse_y};
		}
	} else {
		mouse3Active = false;
	}

	
}

draw_tacoma_tab :: (theme: *GR.Overall_Theme, total_r: GR.Rect) {
	curworld := get_current_world();
	r := total_r;
	r.h = ui_h(3,0);
	#if HAS_TACOMA {
		if GR.button(r, "Render with Tacoma", *theme.button_theme) {
			cam := get_level_editor_camera();
			gen_reference(tacomaResolution, tacomaResolution, cam.position, cam.target, tacomaSamples, true, curworld.world);
		}
		r.y += r.h;
		if GR.button(r, "Render a RDM", *theme.button_theme) {
			gen_rdm(tacomaSamples, true, curworld.world);
		}
		r.y += r.h;
		if GR.button(r, "Bake all chunk RDMs", *theme.button_theme) {
			if curworld.valid then rdm_bake_all_chunks(curworld.world, tacomaSamples, true);
		}
		r.y += r.h;
		if rdm_bake.active {
			total := cast(s32) rdm_bake.jobs.count;
			done  := rdm_bake.current_job;
			pct   := ifx total > 0 then done * 100 / total else 0;
			GR.label(r, tprint("Baking RDMs: %/% (\%%)", done, total, pct), *t_label_left(theme));
			r.y += r.h;
		}
		if current_screenshot.valid {
			aspect := cast(float)current_screenshot.width / cast(float)current_screenshot.height;
			
			r.h = r.w / aspect;
			uiTex := New(Ui_Texture,, temp);
			uiTex.tex = current_screenshot.image;
			set_shader_for_images(uiTex);
		    immediate_quad(.{r.x, r.y}, .{r.x + r.w, r.y}, .{r.x + r.w, r.y + r.h}, .{r.x, r.y + r.h});
			set_shader_for_color();
			r.y += r.h;
		}
		r.h = ui_h(4,0);

	    GR.label(r, "Samples", *t_label_left(theme));
	    r.y += r.h;
	    GR.slider(r, *tacomaSamples, 10, 10000, 10, *theme.slider_theme);
		r.y += r.h;
	    GR.label(r, "Resolution", *t_label_left(theme));
	    r.y += r.h;
	    GR.slider(r, *tacomaResolution, 10, 5000, 10, *theme.slider_theme);
		r.y += r.h;
	    GR.label(r, "Exposure", *t_label_left(theme));
	    r.y += r.h;
	    GR.slider(r, *tacomaExposure, 0.5, 3.0, 0.1, *theme.slider_theme);
		r.y += r.h;
	    GR.label(r, "Contrast", *t_label_left(theme));
	    r.y += r.h;
	    GR.slider(r, *tacomaContrast, 0.5, 3.0, 0.1, *theme.slider_theme);
		r.y += r.h;
	    GR.label(r, "Saturation", *t_label_left(theme));
	    r.y += r.h;
	    GR.slider(r, *tacomaSaturation, 0.5, 3.0, 0.1, *theme.slider_theme);
		r.y += r.h;

		
	} else {
		GR.label(r, "Tacoma is not enabled in this build.", *theme.label_theme);
	}
}

#scope_file

Edit_Mode :: enum {
	TRILES;
}

editMode : Edit_Mode;

#scope_export

draw_tools_tab :: (theme: *GR.Overall_Theme, total_r: GR.Rect) {
	r := total_r;
	r.h = ui_h(3,0);
}

handle_tool_click :: (x: int, y: int, z: int, delete: bool = false) {
	curworld := get_current_world();
	if delete {
		remove_trile(cast(s32)x, cast(s32)y, cast(s32)z);
	} else {
		if editor_current_trile != null then add_trile(editor_current_trile.name, cast(s32)x, cast(s32)y, cast(s32)z);
	}
}

add_trile :: (name: string, x: s32, y: s32, z: s32, orientation: u8 = 0) {
	curworld := get_current_world();

	// Remove any existing trile at this position first.
	remove_trile(x, y, z);

	// Find or create the chunk.
	key := world_to_chunk_coord(x, y, z);
	chunk := table_find_pointer(*curworld.world.chunks, key);
	if !chunk {
		new_chunk: Chunk;
		new_chunk.coord = key;
		table_set(*curworld.world.chunks, key, new_chunk);
		chunk = table_find_pointer(*curworld.world.chunks, key);
	}

	lx, ly, lz := world_to_local(x, y, z);
	inst := Trile_Instance.{x = lx, y = ly, z = lz, orientation = orientation};

	// Find existing group for this trile type, or create one.
	for *group: chunk.groups {
		if group.trile_name == name {
			array_add(*group.instances, inst);
			return;
		}
	}
	group: Chunk_Trile_Group;
	group.trile_name = sprint("%", name);
	array_add(*group.instances, inst);
	array_add(*chunk.groups, group);
} @Command

remove_trile :: (x: s32, y: s32, z: s32) {
	curworld := get_current_world();

	key := world_to_chunk_coord(x, y, z);
	chunk := table_find_pointer(*curworld.world.chunks, key);
	if !chunk then return;

	lx, ly, lz := world_to_local(x, y, z);

	for *group: chunk.groups {
		for inst, idx: group.instances {
			if inst.x == lx && inst.y == ly && inst.z == lz {
				array_unordered_remove_by_index(*group.instances, idx);
				return;
			}
		}
	}
} @Command



tick_level_editor :: () {
	#if HAS_TACOMA { rdm_bake_tick(); }
	tick_level_editor_camera();
	ray := get_mouse_ray(*get_level_editor_camera());
	hit, point := ray_plane_collision_point(ray, xx editY, 20);
	
	show_trile_preview = false;
	if hit {
		show_trile_preview = true;
		trile_preview_x = xx floor(point.x);
		trile_preview_y = editY;
		trile_preview_z = xx floor(point.y);

		if get_mouse_state(Key_Code.MOUSE_BUTTON_LEFT) & .START {
			handle_tool_click(xx floor(point.x), xx editY, xx floor(point.y));
		}
		if get_mouse_state(Key_Code.MOUSE_BUTTON_RIGHT) & .START {
			handle_tool_click(xx floor(point.x), xx editY, xx floor(point.y), true);
		}
	}
}

draw_level_editor :: () {
	curworld := get_current_world();
	if !curworld.valid then return;
	create_set_cam_rendering_task(get_level_editor_camera(), curworld.world.conf.planeHeight);
	create_world_rendering_tasks(*curworld.world);
}

draw_level_editor_ui :: (theme: *GR.Overall_Theme) {
    r := GR.get_rect(0, ui_h(5,0), ui_w(20, 20), ui_h(95, 0));
	ui_add_mouse_occluder(r);
    draw_bg_rectangle(r, theme);
    tab_r := r;
    tab_r.h = ui_h(3,0);
    tab_r.w = ui_w(20, 20) / 3;

    if GR.button(tab_r, "Tools", *t_button_tab(theme, current_tab == .TOOLS)) {
		current_tab = .TOOLS;
    }
    tab_r.x += tab_r.w;
    if GR.button(tab_r, "Info", *t_button_tab(theme, current_tab == .INFO)) {
		current_tab = .INFO;
    }
    tab_r.x += tab_r.w;
    if GR.button(tab_r, "Tacoma", *t_button_tab(theme, current_tab == .TACOMA)) {
        current_tab = .TACOMA;
    }
    r.y += tab_r.h;

	curworld := get_current_world();
    if current_tab == {
		case .TOOLS;
			draw_tools_tab(theme, r);
        case .TACOMA;
			draw_tacoma_tab(theme, r);
		case .INFO;
			if curworld.valid then autoedit(r, *curworld.world.conf, theme);
    }
	draw_picker(theme);
}
