<template>
	<view
		class="cl-textarea"
		:class="[
			pt.className,
			{
				'is-dark': isDark,
				'cl-textarea--border': border,
				'cl-textarea--focus': isFocus,
				'cl-textarea--disabled': isDisabled,
				'cl-textarea--error': isError
			}
		]"
		@tap="onTap"
	>
		<textarea
			class="cl-textarea__inner"
			:class="[
				{
					'is-disabled': isDisabled,
					'is-dark': isDark
				},
				ptClassName
			]"
			:style="textareaStyle"
			:value="value"
			:name="name"
			:disabled="readonly ?? isDisabled"
			:placeholder="placeholder"
			:placeholder-class="`text-surface-400 ${placeholderClass}`"
			:maxlength="maxlength"
			:auto-focus="isFocus"
			:cursor="cursor"
			:cursor-spacing="cursorSpacing"
			:cursor-color="cursorColor"
			:show-confirm-bar="showConfirmBar"
			:confirm-hold="confirmHold"
			:auto-height="autoHeight"
			:fixed="fixed"
			:adjust-position="adjustPosition"
			:hold-keyboard="holdKeyboard"
			:inputmode="inputmode"
			:disable-default-padding="disableDefaultPadding"
			:adjust-keyboard-to="adjustKeyboardTo"
			@confirm="onConfirm"
			@input="onInput"
			@linechange="onLineChange"
			@blur="onBlur"
			@focus="onFocus"
			@keyboardheightchange="onKeyboardheightchange"
		/>

		<cl-text
			:pt="{ className: 'absolute right-2 bottom-2 !text-xs !text-surface-400' }"
			v-if="showWordLimit"
			>{{ value.length }} / {{ maxlength }}</cl-text
		>
	</view>
</template>

<script setup lang="ts">
import { computed, nextTick, ref, watch, type PropType } from "vue";
import { parsePt, parseRpx } from "@/cool";
import type { PassThroughProps } from "../../types";
import { isDark } from "@/cool";
import { t } from "@/locale";
import { useForm, useFormItem, useSize } from "../../hooks";

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

// 组件属性定义
const props = defineProps({
	// 透传样式
	pt: {
		type: Object,
		default: () => ({})
	},
	// 绑定值
	modelValue: {
		type: String,
		default: ""
	},
	// 是否显示边框
	border: {
		type: Boolean,
		default: true
	},
	// 是否禁用
	disabled: {
		type: Boolean,
		default: false
	},
	// 是否只读
	readonly: {
		type: Boolean,
		default: null
	},
	// 是否显示字数统计
	showWordLimit: {
		type: Boolean,
		default: true
	},
	// 名称
	name: {
		type: String,
		default: ""
	},
	// 占位符
	placeholder: {
		type: String,
		default: () => t("请输入")
	},
	// 占位符样式类
	placeholderClass: {
		type: String,
		default: ""
	},
	// 最大输入长度
	maxlength: {
		type: Number,
		default: 140
	},
	// 是否自动聚焦
	autofocus: {
		type: Boolean,
		default: false
	},
	// 设置键盘右下角按钮的文字
	confirmType: {
		type: String as PropType<"done" | "go" | "next" | "search" | "send">,
		default: "done"
	},
	// 指定focus时的光标位置
	cursor: {
		type: Number,
		default: 0
	},
	// 点击键盘确认按钮时是否保持键盘不收起
	confirmHold: {
		type: Boolean,
		default: false
	},
	// 高度
	height: {
		type: [Number, String],
		default: 120
	},
	// 是否自动增高
	autoHeight: {
		type: Boolean,
		default: false
	},
	// 如果 textarea 是在一个 position:fixed 的区域，需要显示指定属性 fixed 为 true
	fixed: {
		type: Boolean,
		default: false
	},
	// 光标与键盘的距离
	cursorSpacing: {
		type: Number,
		default: 5
	},
	// 指定光标颜色
	cursorColor: {
		type: String,
		default: ""
	},
	// 是否显示键盘上方带有”完成“按钮那一栏
	showConfirmBar: {
		type: Boolean,
		default: true
	},
	// 光标起始位置
	selectionStart: {
		type: Number,
		default: -1
	},
	// 光标结束位置
	selectionEnd: {
		type: Number,
		default: -1
	},
	// 盘弹起时，是否自动上推页面
	adjustPosition: {
		type: Boolean,
		default: true
	},
	// 它提供了用户在编辑元素或其内容时可能输入的数据类型的提示。
	inputmode: {
		type: String as PropType<
			"none" | "text" | "decimal" | "numeric" | "tel" | "search" | "email" | "url"
		>,
		default: "text"
	},
	// focus时，点击页面的时候不收起键盘
	holdKeyboard: {
		type: Boolean,
		default: false
	},
	// 是否禁用默认内边距
	disableDefaultPadding: {
		type: Boolean,
		default: true
	},
	// 键盘对齐位置
	adjustKeyboardTo: {
		type: String as PropType<"cursor" | "bottom">,
		default: "cursor"
	}
});

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

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

// cl-form-item 上下文
const { isError } = useFormItem();

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

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

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

// 字号
const { ptClassName, getSize } = useSize(() => pt.value.inner?.className ?? "");

// 文本框样式
const textareaStyle = computed(() => {
	const style = {
		height: parseRpx(props.height)
	};

	// 字号
	const fontSize = getSize(null);
	if (fontSize != null) {
		style["fontSize"] = fontSize;
	}

	return style;
});

// 绑定值
const value = ref(props.modelValue);

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

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

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

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

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

	value.value = v1;

	emit("update:modelValue", v1);
	emit("input", e);

	if (v1 != v2) {
		emit("change", v1);
	}
}

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

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

// 行数变化事件
function onLineChange(e: UniTextareaLineChangeEvent) {
	emit("linechange", e);
}

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

	isFocus.value = true;
}

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

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

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

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

<style lang="scss" scoped>
.cl-textarea {
	@apply flex flex-row items-center bg-white;
	@apply rounded-lg;
	padding: 16rpx 20rpx;
	transition-property: border-color, background-color;
	transition-duration: 0.2s;

	:deep(.uni-textarea-compute) {
		opacity: 0;
	}

	&__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;
	}

	&--focus {
		@apply border-primary-500;
	}

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

	&--error {
		@apply border-red-500;
	}

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

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

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

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