import Widget from "./base_widget.js";

jingrow.provide("jingrow.widget.utils");
jingrow.provide("jingrow.dashboards");
jingrow.provide("jingrow.dashboards.chart_sources");

export default class ChartWidget extends Widget {
	constructor(opts) {
		opts.shadow = true;
		super(opts);
		this.height = this.height || 240;
	}

	get_config() {
		return {
			name: this.name,
			chart_name: this.chart_name,
			label: this.label,
			hidden: this.hidden,
			width: this.width,
		};
	}

	refresh() {
		delete this.dashboard_chart;
		this.set_body();
		this.make_chart();
	}

	set_chart_title() {
		const max_chars = this.widget.width() < 600 ? 40 : 60;
		this.set_title(max_chars);
	}

	set_body() {
		this.widget.addClass("dashboard-widget-box");
		if (this.width == "Full") {
			this.widget.addClass("full-width");
		}
	}

	setup_container() {
		this.body.empty();

		if (this.chart_pg.type == "Heatmap") {
			this.setup_heatmap_container();
		}

		this.loading = $(
			`<div class="chart-loading-state text-muted" style="height: ${this.height}px;">${__(
				"Loading..."
			)}</div>`
		);
		this.loading.appendTo(this.body);

		this.empty = $(
			`<div class="chart-loading-state text-muted" style="height: ${this.height}px;">${__(
				"No Data"
			)}</div>`
		);
		this.empty.hide().appendTo(this.body);

		this.chart_wrapper = $(`<div></div>`);
		this.chart_wrapper.appendTo(this.body);

		this.$heatmap_legend = null;
		this.set_chart_title();
	}

	setup_heatmap_container() {
		this.widget.addClass("heatmap-chart");
		this.widget.removeClass("full-width").addClass("full-width");
		this.width = "Full";
	}

	set_summary() {
		if (!this.$summary) {
			this.$summary = $(`<div class="report-summary"></div>`).hide();
			this.head.after(this.$summary);
		} else {
			this.$summary.empty();
		}

		this.summary.forEach((summary) => {
			jingrow.utils.build_summary_item(summary).appendTo(this.$summary);
		});
		this.summary.length && this.$summary.show();
	}

	make_chart() {
		this.get_settings().then(() => {
			if (!this.settings) {
				this.deleted = true;
				this.widget.remove();
				return;
			}

			if (!this.chart_settings) {
				this.chart_settings = {};
			}
			this.setup_container();
			if (!this.in_customize_mode) {
				this.action_area.empty();
				this.prepare_chart_actions();

				if (this.chart_pg.timeseries) {
					this.render_time_series_filters();
				}
			}
			jingrow.run_serially([
				() => this.prepare_chart_object(),
				() => this.setup_filter_button(),
				() => this.fetch_and_update_chart(),
			]);
		});
	}

	render_time_series_filters() {
		let filters = this.get_time_series_filters();
		jingrow.dashboard_utils.render_chart_filters(filters, "chart-actions", this.action_area, 0);
	}

	get_time_series_filters() {
		let filters;
		if (this.chart_pg.type == "Heatmap") {
			filters = [
				{
					label: __(this.chart_settings.heatmap_year) || __(this.chart_pg.heatmap_year),
					options: jingrow.dashboard_utils.get_years_since_creation(
						jingrow.boot.user.creation
					),
					action: (selected_item) => {
						this.selected_heatmap_year = selected_item;
						this.save_chart_config_for_user({
							heatmap_year: this.selected_heatmap_year,
						});
						this.fetch_and_update_chart();
					},
				},
			];
		} else {
			filters = [
				{
					label:
						__(this.chart_settings.time_interval) || __(this.chart_pg.time_interval),
					options: ["Yearly", "Quarterly", "Monthly", "Weekly", "Daily"],
					icon: "calendar",
					class: "time-interval-filter",
					action: (selected_item) => {
						this.selected_time_interval = selected_item;
						this.save_chart_config_for_user({
							time_interval: this.selected_time_interval,
						});
						this.fetch_and_update_chart();
					},
				},
				{
					label: __(this.chart_settings.timespan) || __(this.chart_pg.timespan),
					options: [
						"Select Date Range",
						"Last Year",
						"Last Quarter",
						"Last Month",
						"Last Week",
					],
					class: "timespan-filter",
					action: (selected_item) => {
						this.selected_timespan = selected_item;

						if (this.selected_timespan === "Select Date Range") {
							this.render_date_range_field();
						} else {
							this.selected_from_date = null;
							this.selected_to_date = null;
							if (this.date_field_wrapper) {
								this.date_field_wrapper.hide();

								// Title maybe hidden becuase of date range fields
								// in half width chart
								this.title_field.show();
								this.subtitle_field.show();
								this.head.css("flex-direction", "row");
							}

							this.save_chart_config_for_user({
								timespan: this.selected_timespan,
								from_date: null,
								to_date: null,
							});
							this.fetch_and_update_chart();
						}
					},
				},
			];
		}
		return filters;
	}

	fetch_and_update_chart() {
		this.args = {
			timespan: this.selected_timespan || this.chart_settings.timespan,
			time_interval: this.selected_time_interval || this.chart_settings.time_interval,
			from_date: this.selected_from_date || this.chart_settings.from_date,
			to_date: this.selected_to_date || this.chart_settings.to_date,
			heatmap_year: this.selected_heatmap_year || this.chart_settings.heatmap_year,
		};

		this.fetch(this.filters, true, this.args).then((data) => {
			if (this.chart_pg.chart_type == "Report") {
				this.report_result = data;
				this.summary = data.report_summary;
				data = this.get_report_chart_data(data);
			}

			this.update_chart_object();
			this.data = data;
			this.render();
		});
	}

	render_date_range_field() {
		if (!this.date_field_wrapper || !this.date_field_wrapper.is(":visible")) {
			this.date_field_wrapper = $(
				`<div class="dashboard-date-field pull-right"></div>`
			).insertAfter(this.action_area.find(".timespan-filter"));

			if (this.width !== "Full" && this.widget.width() < 700) {
				this.title_field.hide();
				this.subtitle_field.hide();
				this.head.css("flex-direction", "row-reverse");
			}

			this.date_range_field = jingrow.ui.form.make_control({
				df: {
					fieldtype: "DateRange",
					fieldname: "from_date",
					placeholder: __("Date Range"),
					input_class: "input-xs",
					default: [this.chart_settings.from_date, this.chart_settings.to_date],
					value: [this.chart_settings.from_date, this.chart_settings.to_date],
					reqd: 1,
					change: () => {
						let selected_date_range = this.date_range_field.get_value();
						this.selected_from_date = selected_date_range[0];
						this.selected_to_date = selected_date_range[1];

						if (selected_date_range && selected_date_range.length == 2) {
							this.save_chart_config_for_user({
								timespan: this.selected_timespan,
								from_date: this.selected_from_date,
								to_date: this.selected_to_date,
							});
							this.fetch_and_update_chart();
						}
					},
				},
				parent: this.date_field_wrapper,
				render_input: 1,
			});

			this.date_range_field.$input.focus();
		}
	}

	get_report_chart_data(result) {
		if (result.chart && this.chart_pg.use_report_chart) {
			return result.chart.data;
		} else {
			let y_fields = [];
			this.chart_pg.y_axis.map((field) => {
				y_fields.push(field.y_field);
			});

			let chart_fields = {
				y_fields: y_fields,
				x_field: this.chart_pg.x_field,
				chart_type: this.chart_pg.type,
				color: this.chart_pg.color,
			};
			let columns = result.columns.map((col) => {
				return jingrow.report_utils.prepare_field_from_column(col);
			});

			return jingrow.report_utils.make_chart_options(columns, result, chart_fields).data;
		}
	}

	prepare_chart_actions() {
		let actions = [
			{
				label: __("Refresh"),
				action: "action-refresh",
				handler: () => {
					delete this.dashboard_chart;
					this.make_chart();
				},
			},
			{
				label: __("Edit"),
				action: "action-edit",
				handler: () => {
					jingrow.set_route("Form", "Dashboard Chart", this.chart_pg.name);
				},
			},
			{
				label: __("Reset Chart"),
				action: "action-reset",
				handler: () => {
					this.reset_chart();
					delete this.dashboard_chart;
					this.make_chart();
				},
			},
		];

		if (this.chart_pg.document_type) {
			actions.push({
				label: __("{0} List", [__(this.chart_pg.document_type)]),
				action: "action-list",
				handler: () => {
					jingrow.set_route("List", this.chart_pg.document_type);
				},
			});
		} else if (this.chart_pg.chart_type === "Report") {
			actions.push({
				label: __("{0} Report", [__(this.chart_pg.report_name)]),
				action: "action-list",
				handler: () => {
					jingrow.set_route("query-report", this.chart_pg.report_name, this.filters);
				},
			});
		}
		this.set_chart_actions(actions);
	}

	setup_filter_button() {
		if (this.in_customize_mode) return;

		this.is_document_type =
			this.chart_pg.chart_type !== "Report" && this.chart_pg.chart_type !== "Custom";

		this.filter_button = $(
			`<div class="filter-chart btn btn-xs pull-right">
				${jingrow.utils.icon("filter", "sm")}
			</div>`
		);

		this.filter_button.appendTo(this.action_area);

		if (this.is_document_type) {
			if (this.filter_group) {
				this.filters = this.filter_group.get_filters();
			}
			this.create_filter_group_and_add_filters();
		} else {
			this.filter_button.on("click", () => {
				let fields;

				jingrow.dashboard_utils
					.get_filters_for_chart_type(this.chart_pg)
					.then((filters) => {
						if (!this.is_document_type) {
							if (!filters) {
								fields = [
									{
										fieldtype: "HTML",
										options: __("No Filters Set"),
									},
								];
							} else {
								fields = filters
									.filter((df) => df.fieldname)
									.map((df) => {
										Object.assign(df, df.dashboard_config || {});
										return df;
									});
							}
						} else {
							fields = [
								{
									fieldtype: "HTML",
									fieldname: "filter_area",
								},
							];
						}

						this.setup_filter_dialog(fields);
					});
			});
		}
	}

	setup_filter_dialog(fields) {
		let me = this;
		let dialog = new jingrow.ui.Dialog({
			title: __("Set Filters for {0}", [__(this.chart_pg.chart_name)]),
			fields: fields,
			primary_action: function () {
				let values = this.get_values();
				if (values) {
					this.hide();
					me.filters = values;
					me.save_chart_config_for_user({ filters: me.filters });
					me.fetch_and_update_chart();
				}
			},
			primary_action_label: __("Set"),
		});

		dialog.show();

		if (this.chart_pg.chart_type == "Report") {
			//Set query report object so that it can be used while fetching filter values in the report
			jingrow.query_report = new jingrow.views.QueryReport({ filters: dialog.fields_list });
			jingrow.query_reports[this.chart_pg.report_name].onload &&
				jingrow.query_reports[this.chart_pg.report_name].onload(jingrow.query_report);
		}
		dialog.set_values(this.filters);
	}

	reset_chart() {
		this.save_chart_config_for_user(null, 1);
		this.chart_settings = {};
		this.filters = null;
		this.selected_time_interval = null;
		this.selected_timespan = null;
		this.selected_heatmap_year = null;
	}

	save_chart_config_for_user(config, reset = 0) {
		Object.assign(this.chart_settings, config);
		jingrow.xcall(
			"jingrow.desk.pagetype.dashboard_settings.dashboard_settings.save_chart_config",
			{
				reset: reset,
				config: this.chart_settings,
				chart_name: this.chart_pg.chart_name,
			}
		);
	}

	create_filter_group_and_add_filters() {
		this.filter_group = new jingrow.ui.FilterGroup({
			pagetype: this.chart_pg.document_type,
			parent_pagetype: this.chart_pg.parent_document_type,
			filter_button: this.filter_button,
			on_change: () => {
				this.filters = this.filter_group.get_filters();
				this.save_chart_config_for_user({
					filters: this.filters,
				});
				this.fetch_and_update_chart();
			},
		});

		this.filters &&
			jingrow.model.with_pagetype(this.chart_pg.document_type, () => {
				this.filter_group.add_filters_to_filter_group(this.filters);
			});
	}

	set_chart_actions(actions) {
		this.chart_actions = $(`<div class="chart-actions dropdown pull-right">
			<button data-toggle="dropdown"
				aria-haspopup="true"aria-expanded="false"
				class="btn btn-xs btn-secondary chart-menu"
			>
				<svg class="icon icon-sm">
					<use href="#icon-dot-horizontal">
					</use>
				</svg>
			</button>
			<ul class="dropdown-menu dropdown-menu-right">
				${actions
					.map(
						(action) =>
							`<li><a class="dropdown-item" data-action="${action.action}">${__(
								action.label
							)}</a></li>`
					)
					.join("")}
			</ul>
		</div>
		`);
		/* eslint-enable indent */

		this.chart_actions.find("a[data-action]").each((i, o) => {
			const action = o.dataset.action;
			$(o).click(actions.find((a) => a.action === action));
		});
		this.chart_actions.appendTo(this.action_area);
	}

	fetch(filters, refresh = false, args) {
		let method = this.settings.method;

		if (this.chart_pg.chart_type == "Report") {
			args = {
				report_name: this.chart_pg.report_name,
				filters: filters,
				ignore_prepared_report: 1,
			};
		} else {
			args = {
				chart_name: this.chart_pg.name,
				filters: filters,
				refresh: refresh ? 1 : 0,
				time_interval: args && args.time_interval ? args.time_interval : null,
				timespan: args && args.timespan ? args.timespan : null,
				from_date: args && args.from_date ? args.from_date : null,
				to_date: args && args.to_date ? args.to_date : null,
				heatmap_year: args && args.heatmap_year ? args.heatmap_year : null,
			};
		}
		return jingrow.xcall(method, args);
	}

	async get_source_pagetype() {
		if (this.chart_pg.document_type) {
			return this.chart_pg.document_type;
		}
		if (this.chart_pg.chart_type == "Report" && this.chart_pg.report_name) {
			return await jingrow.db
				.get_value("Report", this.chart_pg.report_name, "ref_pagetype")
				.then((r) => r.message.ref_pagetype);
		}
	}

	async render() {
		let setup_dashboard_chart = () => {
			const chart_args = this.get_chart_args();

			if (!this.dashboard_chart) {
				this.dashboard_chart = jingrow.utils.make_chart(this.chart_wrapper[0], chart_args);
			} else {
				this.dashboard_chart.update(this.data);
			}
		};

		if (!this.data || !this.data.labels || !Object.keys(this.data).length) {
			this.chart_wrapper.hide();
			this.loading.hide();
			this.$summary && this.$summary.hide();
			this.empty.show();
		} else {
			this.loading.hide();
			this.empty.hide();
			this.chart_wrapper.show();
			this.chart_pg.document_type = await this.get_source_pagetype();

			if (this.chart_pg.document_type) {
				jingrow.model.with_pagetype(this.chart_pg.document_type, setup_dashboard_chart);
			} else {
				setup_dashboard_chart();
			}

			this.width == "Full" && this.summary && this.set_summary();
			this.chart_pg.type == "Heatmap" && this.render_heatmap_legend();
		}
	}

	get_chart_args() {
		let colors = this.get_chart_colors();
		let fieldtype, options;

		const chart_type_map = {
			Line: "line",
			Bar: "bar",
			Percentage: "percentage",
			Pie: "pie",
			Donut: "donut",
			Heatmap: "heatmap",
		};

		let max_slices = ["Pie", "Donut"].includes(this.chart_pg.type) ? 6 : 9;
		let chart_args = {
			data: this.data,
			type: chart_type_map[this.chart_pg.type],
			colors: colors,
			height: this.height,
			maxSlices: this.chart_pg.number_of_groups || max_slices,
			axisOptions: {
				xIsSeries: this.chart_pg.timeseries,
				shortenYAxisNumbers: 1,
			},
		};

		if (this.chart_pg.document_type) {
			let pagetype_meta = jingrow.get_meta(this.chart_pg.document_type);
			let field = pagetype_meta.fields.find(
				(x) => x.fieldname == this.chart_pg.value_based_on
			);
			fieldtype = field?.fieldtype;
			options = field?.options;
		}

		if (this.chart_pg.chart_type == "Report" && this.report_result?.chart?.fieldtype) {
			fieldtype = this.report_result.chart.fieldtype;
			options = this.report_result.chart.options;
		}

		if (this.chart_pg.chart_type == "Custom" && this.chart_pg.custom_options) {
			let chart_options = JSON.parse(this.chart_pg.custom_options);
			fieldtype = chart_options.fieldtype;
			options = chart_options.options;
		}

		if (this.chart_pg.currency) {
			chart_args.tooltipOptions = {
				formatTooltipY: (value) => format_currency(value, this.chart_pg.currency),
			};
		} else {
			chart_args.tooltipOptions = {
				formatTooltipY: (value) =>
					jingrow.format(
						value,
						{ fieldtype, options },
						{ always_show_decimals: true, inline: true }
					),
			};
		}

		if (this.chart_pg.type == "Heatmap") {
			const heatmap_year = parseInt(
				this.selected_heatmap_year ||
					this.chart_settings.heatmap_year ||
					this.chart_pg.heatmap_year
			);
			chart_args.data.start = new Date(`${heatmap_year}-01-01`);
			chart_args.data.end = new Date(`${heatmap_year + 1}-01-01`);
		}

		let set_options = (options) => {
			let custom_options = JSON.parse(options);
			for (let key in custom_options) {
				if (
					typeof chart_args[key] === "object" &&
					typeof custom_options[key] === "object"
				) {
					chart_args[key] = Object.assign(chart_args[key], custom_options[key]);
				} else {
					chart_args[key] = custom_options[key];
				}
			}
		};

		if (this.custom_options) {
			set_options(this.custom_options);
		}

		if (this.chart_pg.custom_options) {
			set_options(this.chart_pg.custom_options);
		}

		return chart_args;
	}

	get_chart_colors() {
		let colors = [];
		if (this.chart_pg.y_axis.length) {
			this.chart_pg.y_axis.map((field) => {
				colors.push(field.color);
			});
		} else if (["Line", "Bar"].includes(this.chart_pg.type)) {
			colors = [this.chart_pg.color || []];
		} else if (this.chart_pg.type == "Heatmap") {
			colors = [];
		}

		return colors;
	}

	render_heatmap_legend() {
		let legend_colors;

		let set_legend_color = (options) => {
			legend_colors = JSON.parse(options).colors;
		};

		if (this.custom_options) {
			set_legend_color(this.custom_options);
		}

		if (this.chart_pg.custom_options) {
			set_legend_color(this.chart_pg.custom_options);
		}

		if (!this.$heatmap_legend && this.widget.width() > 991) {
			this.$heatmap_legend = $(`
				<div class="heatmap-legend">
					<ul class="legend-colors">
						<li style="background-color: ${legend_colors[0] || "#ebedf0"}"></li>
						<li style="background-color: ${legend_colors[1] || "#c6e48b"}"></li>
						<li style="background-color: ${legend_colors[2] || "#7bc96f"}"></li>
						<li style="background-color: ${legend_colors[3] || "#239a3b"}"></li>
						<li style="background-color: ${legend_colors[4] || "#196127"}"></li>
					</ul>
					<div class="legend-label">
						<div style="margin-bottom: 45px">${__("Less")}</div>
						<div>${__("More")}</div>
					</div>
				</div>
				`);
			this.body.append(this.$heatmap_legend);
		}
	}

	update_last_synced() {
		if (!this.chart_pg.last_synced_on) {
			return;
		}
		let last_synced_text = __("Last synced {0}", [
			comment_when(this.chart_pg.last_synced_on),
		]);
		this.subtitle_field.html(last_synced_text);
	}

	update_chart_object() {
		jingrow.db.get_pg("Dashboard Chart", this.chart_pg.name).then((pg) => {
			this.chart_pg = pg;
			this.update_last_synced();
		});
	}

	prepare_chart_object() {
		if (this.chart_pg.type == "Heatmap" && !this.chart_pg.heatmap_year) {
			this.chart_pg.heatmap_year = jingrow.dashboard_utils.get_year(
				jingrow.datetime.now_date()
			);
		}

		return this.set_chart_filters();
	}

	set_chart_filters() {
		let user_saved_filters = this.chart_settings.filters || null;
		let chart_saved_filters = jingrow.dashboard_utils.get_all_filters(this.chart_pg);

		if (this.chart_pg.chart_type == "Report") {
			return jingrow.dashboard_utils
				.get_filters_for_chart_type(this.chart_pg)
				.then((filters) => {
					chart_saved_filters = this.update_default_date_filters(
						filters,
						chart_saved_filters
					);
					this.filters =
						jingrow.utils.parse_array(user_saved_filters) ||
						jingrow.utils.parse_array(this.filters) ||
						jingrow.utils.parse_array(chart_saved_filters);
				});
		} else {
			this.filters =
				jingrow.utils.parse_array(user_saved_filters) ||
				jingrow.utils.parse_array(this.filters) ||
				jingrow.utils.parse_array(chart_saved_filters);
			return Promise.resolve();
		}
	}

	update_default_date_filters(report_filters, chart_filters) {
		if (report_filters) {
			report_filters.map((f) => {
				if (["Date", "DateRange"].includes(f.fieldtype) && f.default) {
					if (f.reqd || chart_filters[f.fieldname]) {
						chart_filters[f.fieldname] = f.default;
					}
				}
			});
		}
		return chart_filters;
	}

	get_settings() {
		return jingrow.model.with_pg("Dashboard Chart", this.chart_name).then((chart_pg) => {
			if (chart_pg) {
				this.chart_pg = chart_pg;
				if (this.chart_pg.chart_type == "Custom") {
					// custom source
					if (jingrow.dashboards.chart_sources[this.chart_pg.source]) {
						this.settings = jingrow.dashboards.chart_sources[this.chart_pg.source];
						return Promise.resolve();
					} else {
						const method =
							"jingrow.desk.pagetype.dashboard_chart_source.dashboard_chart_source.get_config";
						return jingrow
							.xcall(method, { name: this.chart_pg.source })
							.then((config) => {
								jingrow.dom.eval(config);
								this.settings =
									jingrow.dashboards.chart_sources[this.chart_pg.source];
							});
					}
				} else if (this.chart_pg.chart_type == "Report") {
					this.settings = {
						method: "jingrow.desk.query_report.run",
					};
					return Promise.resolve();
				} else {
					this.settings = {
						method: "jingrow.desk.pagetype.dashboard_chart.dashboard_chart.get",
					};
					return Promise.resolve();
				}
			}
		});
	}
}
