<template>
	<div v-if="visible" class="tui-editor-search" @mousedown.stop>
		<div class="row">
			<t-button
				class="toggle-btn"
				shape="square"
				size="small"
				type="button"
				variant="outline"
				:title="expanded ? '收起替换' : '展开替换'"
				@click="emit('update:expanded', !expanded)"
			>
				<t-icon :name="expanded ? 'chevron-down-s' : 'chevron-right-s'" />
			</t-button>
			<t-input
				ref="keywordInputRef"
				:value="keyword"
				class="text-input"
				placeholder="查找"
				size="small"
				@change="onKeywordChange"
				@enter="onKeywordEnter"
				@keydown="onKeywordKeydown"
			>
				<template #suffix-icon>
					<t-button
						shape="square"
						size="small"
						type="button"
						variant="text"
						:theme="caseSensitive ? 'primary' : 'default'"
						title="大小写匹配"
						@click="emit('update:case-sensitive', !caseSensitive)"
					>
						Aa
					</t-button>
					<t-button
						shape="square"
						size="small"
						type="button"
						variant="text"
						:theme="useRegex ? 'primary' : 'default'"
						title="正则搜索"
						@click="emit('update:use-regex', !useRegex)"
					>
						.*
					</t-button>
				</template>
			</t-input>
			<span class="status" v-text="resolvedStatusText" />
			<t-button shape="square" size="small" type="button" variant="text" title="上一个" @click="emit('previous')">
				<t-icon name="arrow-up" />
			</t-button>
			<t-button shape="square" size="small" type="button" variant="text" title="下一个" @click="emit('next', false)">
				<t-icon name="arrow-down" />
			</t-button>
			<t-button shape="square" size="small" type="button" variant="text" title="关闭" @click="emit('close')">
				<t-icon name="close" />
			</t-button>
		</div>
		<div v-if="expanded" class="row replace-row">
			<div class="toggle-holder" />
			<t-input
				ref="replaceInputRef"
				:value="replaceValue"
				class="text-input"
				placeholder="替换"
				size="small"
				@change="onReplaceChange"
				@enter="emit('replace')"
				@keydown="onReplaceKeydown"
			/>
			<div class="replace-actions">
				<t-button size="small" type="button" theme="primary" @click="emit('replace')">替换</t-button>
				<t-button size="small" type="button" variant="outline" @click="emit('replace-all')">全部替换</t-button>
			</div>
		</div>
	</div>
</template>

<script lang="ts" setup>
import type { ComponentPublicInstance } from "vue";

defineOptions({
	name: "EditorSearchBar"
});

const props = withDefaults(defineProps<{
	visible?: boolean;
	expanded?: boolean;
	keyword?: string;
	replaceValue?: string;
	statusText?: string;
	statusError?: string;
	matchIndex?: number;
	matchCount?: number;
	caseSensitive?: boolean;
	useRegex?: boolean;
}>(), {
	visible: false,
	expanded: false,
	keyword: "",
	replaceValue: "",
	statusText: undefined,
	statusError: "",
	matchIndex: -1,
	matchCount: 0,
	caseSensitive: false,
	useRegex: false
});

const emit = defineEmits<{
	(event: "update:expanded", value: boolean): void;
	(event: "update:keyword", value: string): void;
	(event: "update:replace-value", value: string): void;
	(event: "update:case-sensitive", value: boolean): void;
	(event: "update:use-regex", value: boolean): void;
	(event: "previous"): void;
	(event: "next", shiftKey: boolean): void;
	(event: "replace"): void;
	(event: "replace-all"): void;
	(event: "close"): void;
}>();

type InputInstance = ComponentPublicInstance & {
	$el: HTMLElement;
};

type InputKeyboardContext = {
	e: KeyboardEvent;
};

const keywordInputRef = ref<InputInstance>();
const replaceInputRef = ref<InputInstance>();

const resolvedStatusText = computed(() => {
	if (undefined !== props.statusText) {
		return props.statusText;
	}
	if (props.statusError) {
		return props.statusError;
	}
	if (!props.keyword) {
		return "无结果";
	}
	if (1 > props.matchCount) {
		return "未找到";
	}
	return `${props.matchIndex + 1} / ${props.matchCount}`;
});

const onKeywordChange = (value: string | number) => {
	emit("update:keyword", `${value}`);
};

const onReplaceChange = (value: string | number) => {
	emit("update:replace-value", `${value}`);
};

const onKeywordEnter = (_value: string | number, context: InputKeyboardContext) => {
	emit("next", context.e.shiftKey);
};

const onKeywordKeydown = (_value: string | number, context: InputKeyboardContext) => {
	if ("Escape" !== context.e.key) {
		return;
	}
	context.e.preventDefault();
	emit("close");
};

const onReplaceKeydown = (_value: string | number, context: InputKeyboardContext) => {
	if ("Escape" !== context.e.key) {
		return;
	}
	context.e.preventDefault();
	emit("close");
};

const getNativeInput = (instance?: InputInstance) => instance?.$el.querySelector("input") || undefined;

const focusKeyword = (selectAll = false) => {
	const input = getNativeInput(keywordInputRef.value);
	input?.focus();
	if (selectAll && input) {
		input.selectionStart = 0;
		input.selectionEnd = input.value.length;
	}
};

const focusReplace = (selectAll = false) => {
	const input = getNativeInput(replaceInputRef.value);
	input?.focus();
	if (selectAll && input) {
		input.selectionStart = 0;
		input.selectionEnd = input.value.length;
	}
};

defineExpose({
	focusKeyword,
	focusReplace,
	keywordInputRef,
	replaceInputRef
});
</script>

<style lang="less" scoped>
.tui-editor-search {
	top: .5rem;
	right: .5rem;
	gap: .375rem;
	z-index: 3;
	display: flex;
	padding: .5rem;
	position: absolute;
	min-width: 20rem;
	max-width: calc(100% - 1rem);
	box-sizing: border-box;
	border-radius: var(--td-radius-default, .375rem);
	background: var(--td-bg-color-container, #fff);
	border: 1px solid var(--td-component-stroke, #B8BBC9);
	box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .12);
	flex-direction: column;

	.row {
		gap: .375rem;
		display: flex;
		min-width: 0;
		align-items: center;

		.toggle-holder {
			flex: none;
			width: 24px;
		}

		.toggle-btn {
			flex: none;
		}

		.text-input {
			width: 12rem;

			:deep(.t-input) {
				padding-right: 0;
			}
		}

		.status {
			width: 3rem;
			color: var(--td-text-color-secondary, #666);
			font-size: .875rem;
			white-space: nowrap;
		}
	}

	.replace-actions {
		gap: .375rem;
		display: flex;
		align-items: center;
	}
}

@media (prefers-color-scheme: dark) {
	.tui-editor-search {
		background: var(--td-bg-color-container, #1f1f1f);
		border-color: var(--td-component-stroke, #434343);
		box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .28);
	}
}
</style>
