import useXComponentConfig from "../_utils/hooks/use-x-component-config.js";
import { hasRenderableNode } from "../_utils/vue.js";
import { EditableContent } from "./EditableContent.js";
import loading_default from "./loading.js";
import style_default from "./style/index.js";
import { TypingContent } from "./TypingContent.js";
import { Fragment, computed, createVNode, defineComponent, mergeProps, ref, toRefs, useAttrs, watch } from "vue";
//#region components/bubble/Bubble.tsx
function renderBubbleSlot(slot, content, info) {
	if (!slot) return null;
	return typeof slot === "function" ? slot(content, info) : slot;
}
var XBubble = /* @__PURE__ */ defineComponent({
	name: "AxBubble",
	inheritAttrs: false,
	props: {
		prefixCls: {
			type: String,
			default: "antd-bubble"
		},
		rootClass: {
			type: String,
			default: ""
		},
		style: {
			type: [
				String,
				Object,
				Array
			],
			default: void 0
		},
		class: {
			type: [
				String,
				Array,
				Object
			],
			default: void 0
		},
		styles: {
			type: Object,
			default: () => ({})
		},
		classes: {
			type: Object,
			default: () => ({})
		},
		placement: {
			type: String,
			default: "start"
		},
		content: {
			type: [
				String,
				Number,
				Object,
				Array
			],
			required: true
		},
		contentRender: {
			type: Function,
			default: void 0
		},
		editable: {
			type: [Boolean, Object],
			default: false
		},
		typing: {
			type: [
				Boolean,
				Object,
				Function
			],
			default: false
		},
		streaming: {
			type: Boolean,
			default: false
		},
		variant: {
			type: String,
			default: "filled"
		},
		shape: {
			type: String,
			default: "default"
		},
		header: {
			type: [
				String,
				Number,
				Object,
				Array,
				Function
			],
			default: void 0
		},
		footer: {
			type: [
				String,
				Number,
				Object,
				Array,
				Function
			],
			default: void 0
		},
		avatar: {
			type: [
				String,
				Number,
				Object,
				Array,
				Function
			],
			default: void 0
		},
		extra: {
			type: [
				String,
				Number,
				Object,
				Array,
				Function
			],
			default: void 0
		},
		footerPlacement: {
			type: String,
			default: void 0
		},
		loading: {
			type: Boolean,
			default: false
		},
		loadingRender: {
			type: Function,
			default: void 0
		},
		onTyping: {
			type: Function,
			default: void 0
		},
		onTypingComplete: {
			type: Function,
			default: void 0
		},
		onEditConfirm: {
			type: Function,
			default: void 0
		},
		onEditCancel: {
			type: Function,
			default: void 0
		},
		info: {
			type: Object,
			default: () => ({})
		}
	},
	setup(props, { expose, slots }) {
		const attrs = useAttrs();
		const contextConfig = useXComponentConfig("bubble");
		const rootRef = ref();
		const [hashId, cssVarCls] = style_default(computed(() => props.prefixCls));
		expose({ get nativeElement() {
			return rootRef.value;
		} });
		const domAttrs = computed(() => {
			const { class: _class, style: _style, ...rest } = attrs;
			return rest;
		});
		const fallbackContent = computed(() => {
			return props.contentRender ? props.contentRender(props.content, props.info) : props.content;
		});
		const resolveMainContent = () => {
			if (slots.content) {
				const slotNode = slots.content({
					content: props.content,
					info: props.info
				});
				if (hasRenderableNode(slotNode)) return slotNode;
			}
			return fallbackContent.value;
		};
		const mergedTyping = computed(() => {
			if (typeof props.typing === "function") return props.typing(props.content, props.info);
			return props.typing;
		});
		const usingInnerAnimation = computed(() => {
			return Boolean(mergedTyping.value) && typeof fallbackContent.value === "string";
		});
		watch(() => [
			fallbackContent.value,
			usingInnerAnimation.value,
			props.streaming
		], () => {
			if (usingInnerAnimation.value) return;
			if (props.streaming) return;
			if (typeof fallbackContent.value === "string") props.onTypingComplete?.(fallbackContent.value);
		}, { immediate: true });
		const footerPlacement = computed(() => {
			if (props.footerPlacement) return props.footerPlacement;
			return props.placement === "start" ? "outer-start" : "outer-end";
		});
		const isEditing = computed(() => {
			return typeof props.editable === "boolean" ? props.editable : props.editable?.editing;
		});
		const isFooterInner = computed(() => footerPlacement.value.includes("inner"));
		const getSlotClassName = (slot) => {
			return [
				`${props.prefixCls}-${slot}`,
				contextConfig.value.classes?.[slot],
				props.classes?.[slot]
			];
		};
		const getSlotStyle = (slot) => {
			return {
				...contextConfig.value.styles?.[slot],
				...props.styles?.[slot]
			};
		};
		const renderSlotNode = (name, propSlot) => {
			const slot = slots[name];
			if (slot) return slot({
				content: props.content,
				info: props.info
			});
			return renderBubbleSlot(propSlot, props.content, props.info);
		};
		const renderHeader = () => {
			const node = renderSlotNode("header", props.header);
			if (!node) return null;
			return createVNode("div", {
				"class": getSlotClassName("header"),
				"style": getSlotStyle("header")
			}, [node]);
		};
		const renderFooter = () => {
			const node = renderSlotNode("footer", props.footer);
			if (!node) return null;
			return createVNode("div", {
				"class": [getSlotClassName("footer"), {
					[`${props.prefixCls}-footer-start`]: footerPlacement.value.includes("start"),
					[`${props.prefixCls}-footer-end`]: footerPlacement.value.includes("end")
				}],
				"style": getSlotStyle("footer")
			}, [node]);
		};
		const renderMainContent = (mainContent, usingInnerAnimationInRender) => {
			if (isEditing.value) {
				if (typeof props.content !== "string") throw new Error("[Bubble] Editable mode only supports string content.");
				return createVNode(EditableContent, {
					"prefixCls": props.prefixCls,
					"content": props.content,
					"okText": props.editable?.okText,
					"cancelText": props.editable?.cancelText,
					"onEditConfirm": props.onEditConfirm,
					"onEditCancel": props.onEditCancel
				}, null);
			}
			return usingInnerAnimationInRender && typeof mainContent === "string" ? createVNode(TypingContent, {
				"prefixCls": props.prefixCls,
				"streaming": props.streaming,
				"typing": mergedTyping.value,
				"content": mainContent,
				"onTyping": props.onTyping,
				"onTypingComplete": props.onTypingComplete
			}, null) : mainContent;
		};
		const renderContent = () => {
			if (props.loading) {
				if (slots.loading) {
					const slotNode = slots.loading({
						content: props.content,
						info: props.info
					});
					if (hasRenderableNode(slotNode)) return slotNode;
				}
				if (props.loadingRender) return props.loadingRender(props.content, props.info);
				return createVNode(loading_default, { "prefixCls": props.prefixCls }, null);
			}
			const mainContent = resolveMainContent();
			const usingInnerAnimationInRender = Boolean(mergedTyping.value) && typeof mainContent === "string";
			return createVNode("div", {
				"class": getSlotClassName("body"),
				"style": getSlotStyle("body")
			}, [
				renderHeader(),
				createVNode("div", {
					"class": [
						`${prefixCls.value}-content`,
						`${prefixCls.value}-content-${variant.value}`,
						`${prefixCls.value}-content-${shape.value}`,
						contextConfig.value.classes?.content,
						props.classes?.content,
						{
							[`${prefixCls.value}-content-string`]: typeof mainContent === "string",
							[`${prefixCls.value}-content-editing`]: isEditing.value,
							[`${prefixCls.value}-content-${props.info.status}`]: props.info.status
						}
					],
					"style": {
						...contextConfig.value.styles?.content,
						...props.styles?.content
					}
				}, [isFooterInner.value ? createVNode(Fragment, null, [createVNode("div", { "class": `${prefixCls.value}-content-with-footer` }, [renderMainContent(mainContent, usingInnerAnimationInRender)]), !isEditing.value ? renderFooter() : null]) : renderMainContent(mainContent, usingInnerAnimationInRender)]),
				!isEditing.value && !isFooterInner.value ? renderFooter() : null
			]);
		};
		const { prefixCls, placement, variant, shape } = toRefs(props);
		return () => {
			const avatarNode = renderSlotNode("avatar", props.avatar);
			const extraNode = renderSlotNode("extra", props.extra);
			return createVNode("div", mergeProps({ "ref": rootRef }, domAttrs.value, {
				"class": [
					prefixCls.value,
					`${prefixCls.value}-${placement.value}`,
					contextConfig.value.classes?.root,
					props.rootClass,
					props.classes?.root,
					hashId.value,
					cssVarCls.value,
					attrs.class,
					props.class,
					{
						[`${prefixCls.value}-loading`]: props.loading,
						[`${prefixCls.value}-${props.info.status}`]: props.info.status
					}
				],
				"style": [
					contextConfig.value.style,
					contextConfig.value.styles?.root,
					props.styles?.root,
					attrs.style,
					props.style
				]
			}), [
				avatarNode ? createVNode("div", {
					"class": getSlotClassName("avatar"),
					"style": getSlotStyle("avatar")
				}, [avatarNode]) : null,
				renderContent(),
				!isEditing.value && !props.loading && extraNode ? createVNode("div", {
					"class": getSlotClassName("extra"),
					"style": getSlotStyle("extra")
				}, [extraNode]) : null
			]);
		};
	}
});
//#endregion
export { XBubble, XBubble as default };
