<script setup lang="ts">
import { computed, ref, useCssModule } from 'vue';
import { useI18n } from '@n8n/i18n';
import { useCanvasNode } from '../../../composables/useCanvasNode';
import { CanvasNodeRenderType } from '../../../canvas.types';
import { useCanvas } from '../../../composables/useCanvas';
import { useEditorContext } from '@/app/composables/useEditorContext';
import { useNodeTypesStore } from '@/app/stores/nodeTypes.store';
import { injectWorkflowDocumentStore } from '@/app/stores/workflowDocument.store';
import { useExperimentalNdvStore } from '../../../experimental/experimentalNdv.store';
import { useFocusedNodesStore } from '@/features/ai/assistant/focusedNodes.store';
import CanvasNodeStatusIcons from './render-types/parts/CanvasNodeStatusIcons.vue';

import { N8nIconButton, N8nTooltip } from '@n8n/design-system';
import CanvasNodeStickyColorSelector from './toolbar/CanvasNodeStickyColorSelector.vue';

const emit = defineEmits<{
	delete: [];
	toggle: [];
	run: [];
	update: [parameters: Record<string, unknown>];
	'open:contextmenu': [event: MouseEvent];
	focus: [id: string];
	'add:ai': [id: string];
}>();

const props = withDefaults(
	defineProps<{
		readOnly?: boolean;
		canExecute?: boolean;
		showStatusIcons: boolean;
		itemsClass: string;
	}>(),
	{
		canExecute: false,
	},
);

const $style = useCssModule();
const i18n = useI18n();

const { isExecuting, isExperimentalNdvActive } = useCanvas();
const { isDisabled, render, name } = useCanvasNode();

const workflowDocumentStore = injectWorkflowDocumentStore();
const nodeTypesStore = useNodeTypesStore();
const experimentalNdvStore = useExperimentalNdvStore();
const focusedNodesStore = useFocusedNodesStore();

// Per-editor host overrides — e.g. the Instance AI artifact preview supersedes
// the AI capabilities of its embedded editor, which must hide this entry point.
const { aiAssistant, aiBuilder, instanceAi } = useEditorContext();

const node = computed(() =>
	name.value ? workflowDocumentStore?.value?.getNodeByName(name.value) : null,
);
const isToolNode = computed(() => !!node.value && nodeTypesStore.isToolNode(node.value.type));

const nodeDisabledTitle = computed(() => {
	return isDisabled.value ? i18n.baseText('node.enable') : i18n.baseText('node.disable');
});

const isStickyColorSelectorOpen = ref(false);
const isHovered = ref(false);

const classes = computed(() => ({
	[$style.canvasNodeToolbar]: true,
	[$style.readOnly]: props.readOnly,
	[$style.forceVisible]: isHovered.value || isStickyColorSelectorOpen.value,
	[$style.isExperimentalNdvActive]: isExperimentalNdvActive.value,
}));

const isExecuteNodeVisible = computed(() => {
	return (
		(!props.readOnly || props.canExecute) &&
		render.value.type === CanvasNodeRenderType.Default &&
		'configuration' in render.value.options &&
		(!render.value.options.configuration || isToolNode.value)
	);
});

const isDisableNodeVisible = computed(() => {
	return !props.readOnly && render.value.type === CanvasNodeRenderType.Default;
});

const isDeleteNodeVisible = computed(() => !props.readOnly);

const isFocusNodeVisible = computed(() => experimentalNdvStore.isZoomedViewEnabled);

// Feeds the builder side panel, so mirror the context menu's
// assistant-or-builder semantics on top of the focused-nodes experiment.
// Hidden when Instance AI supersedes the legacy builder/assistant.
const isAddToAiVisible = computed(
	() =>
		!props.readOnly &&
		focusedNodesStore.isFeatureEnabled &&
		(aiAssistant.value || aiBuilder.value) &&
		!instanceAi.value,
);

const isStickyNoteChangeColorVisible = computed(
	() => !props.readOnly && render.value.type === CanvasNodeRenderType.StickyNote,
);

function executeNode() {
	emit('run');
}

function onToggleNode() {
	emit('toggle');
}

function onDeleteNode() {
	emit('delete');
}

function onChangeStickyColor(color: number | string) {
	emit('update', {
		color,
	});
}

function onOpenContextMenu(event: MouseEvent) {
	emit('open:contextmenu', event);
}

function onMouseEnter() {
	isHovered.value = true;
}

function onMouseLeave() {
	isHovered.value = false;
}

function onFocusNode() {
	if (node.value) {
		emit('focus', node.value.id);
	}
}

function onAddToAi() {
	if (node.value) {
		emit('add:ai', node.value.id);
	}
}
</script>

<template>
	<div
		data-test-id="canvas-node-toolbar"
		:class="classes"
		@mouseenter="onMouseEnter"
		@mouseleave="onMouseLeave"
		@mousedown.stop
		@click.stop
	>
		<div :class="[$style.canvasNodeToolbarItems, itemsClass]">
			<N8nTooltip
				v-if="isExecuteNodeVisible"
				placement="top"
				:disabled="!isDisabled"
				:content="i18n.baseText('ndv.execute.deactivated')"
			>
				<N8nIconButton
					variant="ghost"
					data-test-id="execute-node-button"
					size="small"
					icon="node-play"
					:disabled="isExecuting || isDisabled"
					:title="i18n.baseText('node.testStep')"
					@click.stop="executeNode"
				/>
			</N8nTooltip>
			<N8nIconButton
				variant="ghost"
				v-if="isDisableNodeVisible"
				data-test-id="disable-node-button"
				size="small"
				icon="node-power"
				:title="nodeDisabledTitle"
				@click.stop="onToggleNode"
			/>
			<N8nIconButton
				variant="ghost"
				v-if="isDeleteNodeVisible"
				data-test-id="delete-node-button"
				size="small"
				icon="node-trash"
				:title="i18n.baseText('node.delete')"
				@click.stop="onDeleteNode"
			/>
			<N8nIconButton
				variant="ghost"
				v-if="isFocusNodeVisible"
				size="small"
				icon="crosshair"
				:aria-label="i18n.baseText('node.focusNode')"
				@click.stop="onFocusNode"
			/>
			<CanvasNodeStickyColorSelector
				v-if="isStickyNoteChangeColorVisible"
				v-model:visible="isStickyColorSelectorOpen"
				@update="onChangeStickyColor"
			/>
			<N8nTooltip v-if="isAddToAiVisible" placement="top" :content="i18n.baseText('node.addToAi')">
				<N8nIconButton
					data-test-id="add-to-ai-button"
					variant="ghost"
					size="small"
					text
					icon="sparkles"
					:aria-label="i18n.baseText('node.addToAi')"
					@click.stop="onAddToAi"
				/>
			</N8nTooltip>
			<N8nIconButton
				variant="ghost"
				data-test-id="overflow-node-button"
				size="small"
				icon="node-ellipsis"
				:aria-label="i18n.baseText('node.moreActions')"
				@click.stop="onOpenContextMenu"
			/>
		</div>
		<CanvasNodeStatusIcons
			v-if="showStatusIcons"
			:class="$style.statusIcons"
			spinner-layout="static"
		/>
	</div>
</template>

<style lang="scss" module>
.canvasNodeToolbar {
	padding-bottom: var(--spacing--xs);
	display: flex;
	justify-content: center;
	width: 100%;
	cursor: default;
	pointer-events: none;

	&.isExperimentalNdvActive {
		justify-content: space-between;
		align-items: center;
		padding-bottom: var(--spacing--3xs);
		/* stylelint-disable-next-line @n8n/css-var-naming */
		zoom: var(--canvas-zoom-compensation-factor, 1);
		margin-bottom: var(--spacing--2xs);
	}
}

.canvasNodeToolbarItems {
	display: flex;
	align-items: center;
	justify-content: center;
	background-color: var(--canvas--color--background);
	border-radius: var(--radius);
	pointer-events: auto;

	:global(.button) {
		--button--color--text: var(--color--text--tint-1);
	}
}

.forceVisible {
	opacity: 1 !important;
}

.statusIcons {
	margin-inline-end: var(--spacing--3xs);
}
</style>
