// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.ui.form.AssignTo = class AssignTo {
	constructor(opts) {
		$.extend(this, opts);
		this.btn = this.parent.find(".add-assignment-btn").on("click", () => this.add());
		this.parent.find(".add-assignment-label").on("click", () => this.add());
		this.btn_wrapper = this.btn.parent();

		this.refresh();
	}
	refresh() {
		if (this.frm.doc.__islocal) {
			this.parent.toggle(false);
			return;
		}

		let docinfo = this.frm.get_docinfo?.();
		if (!docinfo || !docinfo.assignments) {
			this.parent.toggle(false);
			return;
		}

		this.parent.toggle(true);
		this.render(this.frm.get_docinfo().assignments);
	}
	render(assignments) {
		this.frm.get_docinfo().assignments = assignments;

		let assignments_wrapper = this.parent.find(".assignments");

		assignments_wrapper.empty();
		let assigned_users = assignments.map((d) => d.owner);

		if (!assigned_users.length) {
			assignments_wrapper.hide();
			return;
		}

		let assignment_group = new frappe.ui.form.AssignmentClass({
			assignments: assigned_users,
			assignment_details: assignments,
			frm: this.frm,
		});

		assignment_group = assignment_group.make_assignment_section();

		assignments_wrapper.show();
		assignments_wrapper.append(assignment_group);
		assignment_group.find(".view-all-assignment").click(() => {
			new frappe.ui.form.AssignmentDialog({
				assignments: assigned_users,
				assignment_details: assignments,
				frm: this.frm,
			});
		});
	}
	add() {
		var me = this;

		if (this.frm.is_new()) {
			frappe.throw(__("Please save the document before assignment"));
			return;
		}

		if (!me.assign_to) {
			me.assign_to = new frappe.ui.form.AssignToDialog({
				method: "frappe.desk.form.assign_to.add",
				doctype: me.frm.doctype,
				docname: me.frm.docname,
				frm: me.frm,
				callback: function (r) {
					me.render(r.message);
				},
			});
		}
		me.assign_to.dialog.clear();
		me.assign_to.dialog.show();
	}
	remove(owner) {
		if (this.frm.is_new()) {
			frappe.throw(__("Please save the document before removing assignment"));
			return;
		}

		return frappe
			.xcall("frappe.desk.form.assign_to.remove", {
				doctype: this.frm.doctype,
				name: this.frm.docname,
				assign_to: owner,
			})
			.then((assignments) => {
				this.render(assignments);
			});
	}
};

frappe.ui.form.AssignToDialog = class AssignToDialog {
	constructor(opts) {
		$.extend(this, opts);

		this.make();
		this.set_description_from_doc();
	}
	make() {
		let me = this;

		me.dialog = new frappe.ui.Dialog({
			title: __("Add to ToDo"),
			fields: me.get_fields(),
			primary_action_label: __("Add"),
			primary_action: function () {
				let args = me.dialog.get_values();

				if (args && args.assign_to) {
					return frappe.call({
						method: me.method,
						args: $.extend(args, {
							doctype: me.doctype,
							name: me.docname,
							assign_to: args.assign_to,
							bulk_assign: me.bulk_assign || false,
							re_assign: me.re_assign || false,
						}),
						callback: function (r) {
							if (!r.exc) {
								if (me.callback) {
									me.callback(r);
								}
								me.dialog && me.dialog.hide();
							}
						},
					});
				}
			},
		});
	}
	assign_to_me() {
		let me = this;
		let assign_to = [];

		if (me.dialog.get_value("assign_to_me")) {
			assign_to.push(frappe.session.user);
		}

		me.dialog.set_value("assign_to", assign_to);
	}
	user_group_list() {
		let me = this;
		let user_group = me.dialog.get_value("assign_to_user_group");
		me.dialog.set_value("assign_to_me", 0);

		if (user_group) {
			let user_group_members = [];
			frappe.db
				.get_list("User Group Member", {
					parent_doctype: "User Group",
					filters: { parent: user_group },
					fields: ["user"],
				})
				.then((response) => {
					user_group_members = response.map((group_member) => group_member.user);
					me.dialog.set_value("assign_to", user_group_members);
				});
		}
	}
	set_description_from_doc() {
		let me = this;

		if (me.frm && me.frm.meta.title_field) {
			me.dialog.set_value("description", me.frm.doc[me.frm.meta.title_field]);
		}
	}
	get_fields() {
		let me = this;

		return [
			{
				label: __("Assign to me"),
				fieldtype: "Check",
				fieldname: "assign_to_me",
				default: 0,
				onchange: () => me.assign_to_me(),
			},
			{
				fieldtype: "MultiSelectPills",
				fieldname: "assign_to",
				label: __("Assign To"),
				reqd: true,
				get_data: function (txt) {
					return frappe.db.get_link_options("User", txt, {
						user_type: "System User",
						enabled: 1,
					});
				},
			},
			{
				label: __("Assign To User Group"),
				fieldtype: "Link",
				fieldname: "assign_to_user_group",
				options: "User Group",
				onchange: () => me.user_group_list(),
			},
			{
				fieldtype: "Section Break",
			},
			{
				label: __("Complete By"),
				fieldtype: "Date",
				fieldname: "date",
			},
			{
				fieldtype: "Column Break",
			},
			{
				label: __("Priority"),
				fieldtype: "Select",
				fieldname: "priority",
				options: [
					{
						value: "Low",
						label: __("Low"),
					},
					{
						value: "Medium",
						label: __("Medium"),
					},
					{
						value: "High",
						label: __("High"),
					},
				],
				// Pick up priority from the source document, if it exists and is available in ToDo
				default: ["Low", "Medium", "High"].includes(
					me.frm && me.frm.doc.priority ? me.frm.doc.priority : "Medium"
				),
			},
			{
				fieldtype: "Section Break",
			},
			{
				label: __("Comment"),
				fieldtype: "Text Editor",
				fieldname: "description",
			},
		];
	}
};

frappe.ui.form.AssignmentClass = class AssignmentClass {
	constructor(opts) {
		this.frm = opts.frm;
		this.assignments = opts.assignments;
		this.assignment_details = opts.assignment_details;
	}

	make_assignment_section() {
		let $assignment_html = $("<div></div>");
		let count = 0;

		for (const assignment of this.assignments) {
			if (count === 3) {
				$assignment_html.append(
					$(
						'<a href="javascript:void(0)" class="text-muted view-all-assignment">View All</div>'
					)
				);
				break;
			}

			$assignment_html.append(this.get_assignment_row(assignment));
			count++;
		}

		return $assignment_html;
	}

	get_assignment_row(assignment, in_dialogue = false) {
		const row = $(`
			<div class="dialog-assignment-row" data-user="${assignment}">
				<div class="assignee">
					${frappe.avatar(assignment, "avatar-smaller")}
					<span>${frappe.user.full_name(assignment)}</span>
				</div>
				<div class="btn-group btn-group-sm" role="group" aria-label="Actions">
				</div>
			</div>
		`);

		const btn_group = row.find(".btn-group");

		if (assignment === frappe.session.user) {
			btn_group.append(`
				<button type="button" class="btn btn-xs complete-btn" title="${__("Done")}">
					${frappe.utils.icon("check")}
				</button>
			`);
			btn_group.find(".complete-btn").click(() => {
				this.close_assignment(assignment).then((assignments) => {
					row.remove();
					this.render(assignments);
				});
			});

			if (in_dialogue) {
				const html = this.assignment_details
					.filter((x) => x.owner === assignment && strip_html(x.description))
					.map((x) => x.description)
					.join("<hr>");
				if (html) {
					let description = $(
						"<div class='small text-muted' style='margin-left: 45px;max-height: 100px;'></div>"
					).html(html);
					row.find(".assignee").append(description);
				}
			}
		}

		if (assignment === frappe.session.user || this.frm.perm[0].write) {
			btn_group.append(`
				<button type="button" class="btn btn-xs remove-btn" title="${__("Cancel")}">
				${frappe.utils.icon("x")}
				</button>
			`);
			btn_group.find(".remove-btn").click(() => {
				this.remove_assignment(assignment).then((assignments) => {
					row.remove();
					this.render(assignments);
				});
			});
		}
		return row;
	}

	remove_assignment(assignment) {
		return frappe.xcall("frappe.desk.form.assign_to.remove", {
			doctype: this.frm.doctype,
			name: this.frm.docname,
			assign_to: assignment,
		});
	}

	close_assignment(assignment) {
		return frappe.xcall("frappe.desk.form.assign_to.close", {
			doctype: this.frm.doctype,
			name: this.frm.docname,
			assign_to: assignment,
		});
	}

	render(assignments) {
		this.frm && this.frm.assign_to.render(assignments);
	}
};

frappe.ui.form.AssignmentDialog = class extends frappe.ui.form.AssignmentClass {
	constructor(opts) {
		super(opts);
		this.make();
	}

	make() {
		this.dialog = new frappe.ui.Dialog({
			title: __("Assignments"),
			size: "small",
			no_focus: true,
			fields: [
				{
					label: __("Assign a user"),
					fieldname: "user",
					fieldtype: "Link",
					options: "User",
					change: () => {
						let value = this.dialog.get_value("user");
						if (value && !this.assigning) {
							this.assigning = true;
							this.dialog.set_df_property("user", "read_only", 1);
							this.dialog.set_df_property("user", "description", __("Assigning..."));
							this.add_assignment(value)
								.then(() => {
									this.dialog.set_value("user", null);
								})
								.finally(() => {
									this.dialog.set_df_property("user", "description", null);
									this.dialog.set_df_property("user", "read_only", 0);
									this.assigning = false;
								});
						}
					},
				},
				{
					fieldtype: "HTML",
					fieldname: "assignment_list",
				},
			],
		});

		this.assignment_list = $(this.dialog.get_field("assignment_list").wrapper);
		this.assignment_list.removeClass("frappe-control");

		this.assignments.forEach((assignment) => {
			this.update_assignment(assignment);
		});
		this.dialog.show();
	}
	add_assignment(assignment) {
		return frappe
			.xcall("frappe.desk.form.assign_to.add", {
				doctype: this.frm.doctype,
				name: this.frm.docname,
				assign_to: [assignment],
			})
			.then((assignments) => {
				this.update_assignment(assignment);
				this.render(assignments);
			});
	}
	update_assignment(assignment) {
		const in_the_list = this.assignment_list.find(`[data-user="${assignment}"]`).length;
		if (!in_the_list) {
			this.assignment_list.append(this.get_assignment_row(assignment, true));
		}
	}
};
