frappe.ui.TagEditor = class TagEditor {
	constructor(opts) {
		/* docs:
		Arguments

		- parent
		- user_tags
		- doctype
		- docname
		*/
		$.extend(this, opts);

		this.setup_tags();

		if (!this.user_tags) {
			this.user_tags = "";
		}
		this.initialized = true;
		this.refresh(this.user_tags);
	}
	update_user_tags(tags_string) {
		this.user_tags = tags_string;
		frappe.model.set_value(this.frm.doctype, this.frm.docname, "_user_tags", this.user_tags);
		this.on_change && this.on_change(this.user_tags);
		frappe.tags.utils.fetch_tags();
	}
	setup_tags() {
		var me = this;

		// hidden form, does not have parent
		if (!this.parent) {
			return;
		}

		this.wrapper = this.parent;
		if (!this.wrapper.length) return;

		this.tags = new frappe.ui.Tags({
			parent: this.wrapper,
			placeholder: '<svg class="es-icon icon-sm"><use href="#es-line-add"></use></svg>',
			onTagAdd: (tag) => {
				if (me.initialized && !me.refreshing) {
					return frappe.call({
						method: "frappe.desk.doctype.tag.tag.add_tag",
						args: me.get_args(tag),
						callback: function (r) {
							var user_tags = me.user_tags ? me.user_tags.split(",") : [];
							user_tags.push(tag);
							me.update_user_tags(user_tags.join(","));
						},
					});
				}
			},
			onTagRemove: (tag) => {
				if (!me.refreshing) {
					return frappe.call({
						method: "frappe.desk.doctype.tag.tag.remove_tag",
						args: me.get_args(tag),
						callback: function (r) {
							var user_tags = me.user_tags.split(",");
							user_tags.splice(user_tags.indexOf(tag), 1);
							me.update_user_tags(user_tags.join(","));
						},
					});
				}
			},
		});
		this.setup_awesomplete();
		this.setup_complete = true;
	}
	setup_awesomplete() {
		var me = this;
		var $input = this.wrapper.find("input.tags-input");
		var input = $input.get(0);
		this.awesomplete = new Awesomplete(input, {
			minChars: 0,
			maxItems: 99,
			list: [],
		});
		$input.on("awesomplete-open", function (e) {
			$input.attr("state", "open");
		});
		$input.on("awesomplete-close", function (e) {
			$input.attr("state", "closed");
		});
		$input.on("input", function (e) {
			var value = e.target.value;
			frappe.call({
				method: "frappe.desk.doctype.tag.tag.get_tags",
				args: {
					doctype: me.frm.doctype,
					txt: value.toLowerCase(),
				},
				callback: function (r) {
					me.awesomplete.list = r.message;
				},
			});
		});
		$input.on("focus", function (e) {
			if ($input.attr("state") != "open") {
				$input.trigger("input");
			}
		});
		$input.on("enter-pressed-in-addtag", function (e) {
			var value = e.target.value;
			// If user typed something, use exactly what they typed
			// Don't override with suggestions - let user create new tags
			if (value && value.trim()) {
				$input.trigger("input-selected");
				return;
			}
			// Only fetch suggestions if input is empty
			frappe.call({
				method: "frappe.desk.doctype.tag.tag.get_tags",
				args: {
					doctype: me.frm.doctype,
					txt: value.toLowerCase(),
				},
				callback: function (r) {
					// Updates input to suggestion value (if any) on <enter>
					if (r.message.length) $input.val(r.message[0]);
					$input.trigger("input-selected");
				},
			});
		});
	}
	get_args(tag) {
		return {
			tag: tag,
			dt: this.frm.doctype,
			dn: this.frm.docname,
		};
	}
	refresh(user_tags) {
		var me = this;
		if (!this.initialized || !this.setup_complete || this.refreshing) return;

		me.refreshing = true;
		try {
			me.tags.clearTags();
			if (user_tags) {
				me.user_tags = user_tags;
				me.tags.addTags(user_tags.split(","));
			}
		} catch (e) {
			me.refreshing = false;
			// wtf bug
			setTimeout(function () {
				me.refresh();
			}, 100);
		}
		me.refreshing = false;
	}
};
