<template>
	<div class="code-editor-wrap" />
</template>

<script>
import ace from 'ace-builds';
import 'ace-builds/src-min-noconflict/theme-chrome';
import 'ace-builds/src-min-noconflict/mode-javascript';
import 'ace-builds/src-min-noconflict/mode-json'; //
import 'ace-builds/src-min-noconflict/mode-css'; //
import { capitalize, defineComponent, markRaw } from 'vue';
const Events = ['blur', 'input', 'change', 'changeSelectionStyle', 'changeSession', 'copy', 'focus', 'paste'];

export default defineComponent({
	props: {
		modelValue: {
			type: String,
			required: true,
		},
		lang: {
			type: String,
			default: 'text',
		},
		theme: {
			type: String,
			default: 'chrome',
		},
		options: Object,
		placeholder: String,
		readonly: Boolean,
		wrap: Boolean,
		printMargin: {
			type: [Boolean, Number],
			default: true,
		},
		minLines: Number,
		maxLines: Number,
	},
	emits: ['update:modelValue', 'init', ...Events],
	watch: {
		modelValue(val) {
			if (this._contentBackup !== val) {
				try {
					this._isSettingContent = true;
					this._editor.setValue(val, 1);
				} finally {
					this._isSettingContent = false;
				}
				this._contentBackup = val;
			}
		},
		theme(val) {
			this._editor.setTheme(`ace/theme/${val}`);
		},
		options(val) {
			this._editor.setOptions(val);
		},
		readonly(val) {
			this._editor.setReadOnly(val);
		},
		placeholder(val) {
			this._editor.setOption('placeholder', val);
		},
		wrap(val) {
			this._editor.setWrapBehavioursEnabled(val);
		},
		printMargin(val) {
			this._editor.setOption('printMargin', val);
		},
		lang(val) {
			this._editor.setOption('mode', `ace/mode/${val}`);
		},
		minLines(val) {
			this._editor.setOption('minLines', val);
		},
		maxLines(val) {
			this._editor.setOption('maxLines', val);
		},
	},
	mounted() {
		const editor = (this._editor = markRaw(
			ace.edit(this.$el, {
				placeholder: this.placeholder,
				readOnly: this.readonly,
				value: this.modelValue,
				mode: `ace/mode/${this.lang}`,
				theme: `ace/theme/${this.theme}`,
				wrap: this.wrap,
				printMargin: this.printMargin,
				useWorker: false,
				minLines: this.minLines,
				maxLines: this.maxLines,
				...this.options,
			})
		));
		this._contentBackup = this.modelValue;
		this._isSettingContent = false;
		editor.on('change', () => {
			if (this._isSettingContent) return;
			const content = editor.getValue();
			this._contentBackup = content;
			this.$emit('update:modelValue', content);
		});
		Events.forEach((x) => {
			const eventName = `on${capitalize(x)}`;
			if (typeof this.$.vnode.props[eventName] === 'function') {
				editor.on(x, this.$emit.bind(this, x));
			}
		});
		this.$emit('init', editor);
	},
	beforeUnmount() {
		let _b;
			// eslint-disable-next-line no-void
		(_b = this._editor) === null || _b === void 0 ? void 0 : _b.destroy();
	},
	methods: {
		focus() {
			this._editor.focus();
		},
		blur() {
			this._editor.blur();
		},
		selectAll() {
			this._editor.selectAll();
		},
	},
});
</script>

<style lang="scss"></style>
