<template>
	<view
		class="cl-input"
		:class="[
			pt.className,
			{
				'is-dark': isDark,
				'cl-input--border': border,
				'cl-input--focus': isFocus,
				'cl-input--disabled': isDisabled
			}
		]"
		@tap="onTap"
	>
		<slot name="prepend"></slot>

		<view class="cl-input__icon !pl-0 pr-[12rpx]" v-if="prefixIcon">
			<cl-icon
				:name="prefixIcon"
				:size="pt.prefixIcon?.size ?? 32"
				:pt="{ className: parseClass([pt.prefixIcon?.className]) }"
			></cl-icon>
		</view>

		<input
			class="cl-input__inner"
			:class="[
				{
					'is-disabled': isDisabled,
					'is-dark': isDark
				},
				pt.inner?.className
			]"
			:value="value"
			:disabled="readonly ?? isDisabled"
			:type="type"
			:password="isPassword"
			:focus="isFocus"
			:placeholder="placeholder"
			:placeholder-class="`text-surface-400 ${placeholderClass}`"
			:maxlength="maxlength"
			:cursor-spacing="cursorSpacing"
			:confirm-type="confirmType"
			:confirm-hold="confirmHold"
			:adjust-position="adjustPosition"
			:hold-keyboard="holdKeyboard"
			@input="onInput"
			@focus="onFocus"
			@blur="onBlur"
			@confirm="onConfirm"
			@keyboardheightchange="onKeyboardheightchange"
		/>

		<view class="cl-input__icon" v-if="suffixIcon">
			<cl-icon
				:name="suffixIcon"
				:size="pt.suffixIcon?.size ?? 32"
				:pt="{ className: parseClass([pt.prefixIcon?.className]) }"
			></cl-icon>
		</view>

		<view class="cl-input__icon" @tap="clear" v-if="showClear">
			<cl-icon
				name="close-circle-fill"
				:size="32"
				:pt="{ className: '!text-surface-400' }"
			></cl-icon>
		</view>

		<view class="cl-input__icon" @tap="showPassword" v-if="password">
			<cl-icon
				:name="isPassword ? 'eye-line' : 'eye-off-line'"
				:size="32"
				:pt="{ className: '!text-surface-300' }"
			></cl-icon>
		</view>

		<slot name="append"></slot>
	</view>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, ref, watch, type PropType } from "vue";
import type { ClInputType, PassThroughProps } from "../../types";
import { isDark, parseClass, parsePt } from "@/cool";
import type { ClIconProps } from "../cl-icon/props";
import { t } from "@/locale";
import { useForm } from "../../hooks";

defineOptions({
	name: "cl-input"
});

// 组件属性定义
const props = defineProps({
	// 透传样式
	pt: {
		type: Object,
		default: () => ({})
	},
	// 绑定值
	modelValue: {
		type: String,
		default: ""
	},
	// 输入框类型
	type: {
		type: String as PropType<ClInputType>,
		default: "text"
	},
	// 前缀图标
	prefixIcon: {
		type: String,
		default: ""
	},
	// 后缀图标
	suffixIcon: {
		type: String,
		default: ""
	},
	// 是否密码框
	password: {
		type: Boolean,
		default: false
	},
	// 是否自动聚焦
	autofocus: {
		type: Boolean,
		default: false
	},
	// 是否禁用
	disabled: {
		type: Boolean,
		default: false
	},
	// 是否只读
	readonly: {
		type: Boolean,
		default: null
	},
	// 占位符
	placeholder: {
		type: String,
		default: () => t("请输入")
	},
	// 占位符样式类
	placeholderClass: {
		type: String,
		default: ""
	},
	// 是否显示边框
	border: {
		type: Boolean,
		default: true
	},
	// 是否可清除
	clearable: {
		type: Boolean,
		default: false
	},
	// 光标与键盘的距离
	cursorSpacing: {
		type: Number,
		default: 5
	},
	// 点击键盘确认按钮时是否保持键盘不收起
	confirmHold: {
		type: Boolean,
		default: false
	},
	// 设置键盘右下角按钮的文字
	confirmType: {
		type: String as PropType<"done" | "go" | "next" | "search" | "send">,
		default: "done"
	},
	// 键盘弹起时，是否自动上推页面
	adjustPosition: {
		type: Boolean,
		default: true
	},
	// 最大输入长度
	maxlength: {
		type: Number,
		default: 140
	},
	// 是否保持键盘不收起
	holdKeyboard: {
		type: Boolean,
		default: false
	}
});

// 事件定义
const emit = defineEmits([
	"update:modelValue",
	"input",
	"change",
	"focus",
	"blur",
	"confirm",
	"clear",
	"keyboardheightchange"
]);

// cl-form 上下文
const { disabled } = useForm();

// 是否禁用
const isDisabled = computed(() => {
	return disabled.value || props.disabled;
});

// 透传样式类型定义
type PassThrough = {
	className?: string;
	inner?: PassThroughProps;
	prefixIcon?: ClIconProps;
	suffixIcon?: ClIconProps;
};

// 解析透传样式
const pt = computed(() => parsePt<PassThrough>(props.pt));

// 绑定值
const value = ref<string>("");

// 是否聚焦
const isFocus = ref<boolean>(props.autofocus);

// 是否显示清除按钮
const showClear = computed(() => {
	return isFocus.value && props.clearable && value.value != "";
});

// 是否显示密码
const isPassword = ref(props.password);

// 切换密码显示状态
function showPassword() {
	isPassword.value = !isPassword.value;
}

// 获取焦点事件
function onFocus() {
	isFocus.value = true;
	emit("focus");
}

// 失去焦点事件
function onBlur() {
	emit("blur");

	setTimeout(() => {
		isFocus.value = false;
	}, 0);
}

// 输入事件
function onInput(e: UniInputEvent) {
	const val = e.detail.value;
	value.value = val;

	emit("update:modelValue", val);
	emit("input", val);

	if (val != value.value) {
		emit("change", val);
	}
}

// 点击确认按钮事件
function onConfirm(e: UniInputConfirmEvent) {
	emit("confirm", e);
}

// 键盘高度变化事件
function onKeyboardheightchange(e: UniInputKeyboardHeightChangeEvent) {
	emit("keyboardheightchange", e);
}

// 点击事件
function onTap() {
	if (isDisabled.value) {
		return;
	}

	isFocus.value = true;
}

// 聚焦方法
function focus() {
	setTimeout(() => {
		isFocus.value = false;

		nextTick(() => {
			isFocus.value = true;
		});
	}, 0);
}

// 清除方法
function clear() {
	value.value = "";

	emit("update:modelValue", "");
	emit("change", "");
	emit("clear");

	// #ifdef H5
	focus();
	// #endif
}

watch(
	computed(() => props.modelValue),
	(val: string) => {
		value.value = val;
	},
	{
		immediate: true
	}
);

defineExpose({
	isFocus,
	focus,
	clear
});
</script>

<style lang="scss" scoped>
.cl-input {
	@apply flex flex-row items-center bg-white duration-200;
	@apply rounded-lg;
	height: 66rpx;
	padding: 0 20rpx;
	transition-property: background-color, border-color;

	&__inner {
		@apply h-full text-surface-700;
		flex: 1;
		font-size: 28rpx;

		&.is-dark {
			@apply text-white;
		}
	}

	&__icon {
		@apply flex items-center justify-center h-full;
		padding-left: 20rpx;
	}

	&--border {
		@apply border border-solid border-surface-200;
	}

	&--disabled {
		@apply bg-surface-100 opacity-70;
	}

	&--focus {
		&.cl-input--border {
			@apply border-primary-500;
		}
	}

	&.is-dark {
		@apply bg-surface-800;

		&.cl-input--border {
			@apply border-surface-700;

			&.cl-input--focus {
				@apply border-primary-500;
			}
		}

		&.cl-input--disabled {
			@apply bg-surface-700;
		}
	}
}
</style>
