<script lang="ts" context="module">
	import type {
		Subscriber,
		Invalidator,
		Unsubscriber,
		Writable
	} from "svelte/store";
	import type { tool } from "../tools/";

	export const TOOL_KEY = Symbol("tool");

	type upload_tool = "bg_webcam" | "bg_upload" | "bg_clipboard" | "bg_color";
	type transform_tool = "crop" | "rotate";
	type brush_tool = "brush_color" | "brush_size";
	type eraser_tool = "eraser_size";

	export interface ToolOptions {
		order: number;
		label: string;
		icon: typeof Image;
		cb: (...args: any[]) => void;
		id: upload_tool | transform_tool | brush_tool | eraser_tool;
	}

	export interface ToolMeta {
		default: upload_tool | transform_tool | brush_tool | eraser_tool | null;
		options: ToolOptions[];
	}

	export interface ToolContext {
		register_tool: (type: tool, opts?: { cb: () => void }) => () => void;
		active_tool: {
			set: (tool: tool) => void;
			subscribe(
				this: void,
				run: Subscriber<tool | null>,
				invalidate?: Invalidator<tool | null>
			): Unsubscriber;
		};

		current_color: Writable<string>;
	}
</script>

<script lang="ts">
	import { Toolbar, IconButton } from "@gradio/atoms";
	import { getContext, setContext } from "svelte";
	import { writable } from "svelte/store";
	import { EDITOR_KEY, type EditorContext } from "../ImageEditor.svelte";
	import { Image, Crop, Brush, Erase } from "@gradio/icons";
	import { type I18nFormatter } from "@gradio/utils";

	const { active_tool, toolbar_box, editor_box } =
		getContext<EditorContext>(EDITOR_KEY);

	export let i18n: I18nFormatter;

	let tools: tool[] = [];

	const cbs: Record<string, () => void> = {};
	let current_color = writable("#000000");
	const tool_context: ToolContext = {
		current_color,
		register_tool: (type: tool, opts?: { cb: () => void }) => {
			tools = [...tools, type];
			if (opts?.cb) {
				cbs[type] = opts.cb;
			}

			return () => {
				tools = tools.filter((tool) => tool !== type);
			};
		},

		active_tool: {
			subscribe: active_tool.subscribe,
			set: active_tool.set
		}
	};

	setContext<ToolContext>(TOOL_KEY, tool_context);

	const tools_meta: Record<
		tool,
		{
			order: number;
			label: string;
			icon: typeof Image;
		}
	> = {
		crop: {
			order: 1,
			label: i18n("Transform"),
			icon: Crop
		},
		draw: {
			order: 2,
			label: i18n("Draw"),
			icon: Brush
		},
		erase: {
			order: 2,
			label: i18n("Erase"),
			icon: Erase
		},
		bg: {
			order: 0,
			label: i18n("Background"),
			icon: Image
		}
	} as const;

	let toolbar_width: number;
	let toolbar_wrap: HTMLDivElement;

	$: toolbar_width, $editor_box, get_dimensions();

	function get_dimensions(): void {
		if (!toolbar_wrap) return;
		$toolbar_box = toolbar_wrap.getBoundingClientRect();
	}

	function handle_click(e: Event, tool: tool): void {
		e.stopPropagation();
		$active_tool = tool;
		cbs[tool] && cbs[tool]();
	}
</script>

<slot />

<div
	class="toolbar-wrap"
	bind:clientWidth={toolbar_width}
	bind:this={toolbar_wrap}
>
	<Toolbar show_border={false}>
		{#each tools as tool (tool)}
			<IconButton
				highlight={$active_tool === tool}
				on:click={(e) => handle_click(e, tool)}
				Icon={tools_meta[tool].icon}
				size="medium"
				padded={false}
				label={tools_meta[tool].label + " button"}
				transparent={true}
				offset={tool === "draw" ? -2 : tool === "erase" ? -6 : 0}
			/>
		{/each}
	</Toolbar>
</div>

<style>
	.toolbar-wrap {
		display: flex;
		justify-content: center;
		align-items: center;
		margin-left: var(--spacing-xl);
		height: 100%;
	}
</style>
