# Copyright (c) 2022, Xhive Global Ltd. and Contributors
# License: MIT. See LICENSE

from contextlib import suppress

import xhiveframework
from xhiveframework import _
from xhiveframework.query_builder.functions import DateFormat, Function
from xhiveframework.query_builder.utils import DocType
from xhiveframework.utils.data import add_to_date, cstr, flt, now_datetime
from xhiveframework.utils.formatters import format_value


def get_monthly_results(
	goal_doctype: str,
	goal_field: str,
	date_col: str,
	filters: dict,
	aggregation: str = "sum",
) -> dict:
	"""Get monthly aggregation values for given field of doctype"""

	Table = DocType(goal_doctype)
	date_format = "%m-%Y" if xhiveframework.db.db_type != "postgres" else "MM-YYYY"

	return dict(
		xhiveframework.qb.engine.build_conditions(table=goal_doctype, filters=filters)
		.select(
			DateFormat(Table[date_col], date_format).as_("month_year"),
			Function(aggregation, goal_field),
		)
		.groupby("month_year")
		.run()
	)


@xhiveframework.whitelist()
def get_monthly_goal_graph_data(
	title: str,
	doctype: str,
	docname: str,
	goal_value_field: str,
	goal_total_field: str,
	goal_history_field: str,
	goal_doctype: str,
	goal_doctype_link: str,
	goal_field: str,
	date_field: str,
	filter_str: str = None,
	aggregation: str = "sum",
	filters: dict | None = None,
) -> dict:
	"""
	Get month-wise graph data for a doctype based on aggregation values of a field in the goal doctype

	:param title: Graph title
	:param doctype: doctype of graph doc
	:param docname: of the doc to set the graph in
	:param goal_value_field: goal field of doctype
	:param goal_total_field: current month value field of doctype
	:param goal_history_field: cached history field
	:param goal_doctype: doctype the goal is based on
	:param goal_doctype_link: doctype link field in goal_doctype
	:param goal_field: field from which the goal is calculated
	:param filter_str: [DEPRECATED] where clause condition. Use filters.
	:param aggregation: a value like 'count', 'sum', 'avg'
	:param filters: optional filters

	:return: dict of graph data
	"""
	if isinstance(filter_str, str):
		xhiveframework.throw(
			"String filters have been deprecated. Pass Dict filters instead.", exc=DeprecationWarning
		)  # nosemgrep

	doc = xhiveframework.get_doc(doctype, docname)
	doc.check_permission()

	meta = doc.meta
	goal = doc.get(goal_value_field)
	today_date = now_datetime().date()

	current_month_value = doc.get(goal_total_field)
	current_month_year = today_date.strftime("%m-%Y")  # eg: "02-2022"
	formatted_value = format_value(current_month_value, meta.get_field(goal_total_field), doc)
	history = doc.get(goal_history_field)

	month_to_value_dict = None
	if history and "{" in cstr(history):
		with suppress(ValueError):
			month_to_value_dict = xhiveframework.parse_json(history)

	if month_to_value_dict is None:  # nosemgrep
		doc_filter = {}
		with suppress(ValueError):
			doc_filter = xhiveframework.parse_json(filters or "{}")
		if doctype != goal_doctype:
			doc_filter[goal_doctype_link] = docname

		month_to_value_dict = get_monthly_results(
			goal_doctype, goal_field, date_field, doc_filter, aggregation
		)

	month_to_value_dict[current_month_year] = current_month_value

	month_labels = []
	dataset_values = []
	values_formatted = []
	y_markers = {}

	summary_values = [
		{"title": _("This month"), "color": "#ffa00a", "value": formatted_value},
	]

	if flt(goal) > 0:
		formatted_goal = format_value(goal, meta.get_field(goal_value_field), doc)
		summary_values += [
			{"title": _("Goal"), "color": "#5e64ff", "value": formatted_goal},
			{
				"title": _("Completed"),
				"color": "#28a745",
				"value": f"{int(round(flt(current_month_value) / flt(goal) * 100))}%",
			},
		]
		y_markers = {"yMarkers": [{"label": _("Goal"), "lineType": "dashed", "value": flt(goal)}]}

	for i in range(12):
		date_value = add_to_date(today_date, months=-i, as_datetime=True)
		month_word = date_value.strftime("%b %y")  # eg: "Feb 22"
		month_labels.insert(0, month_word)

		month_value = date_value.strftime("%m-%Y")  # eg: "02-2022"
		val = month_to_value_dict.get(month_value, 0)
		dataset_values.insert(0, val)
		values_formatted.insert(0, format_value(val, meta.get_field(goal_total_field), doc))

	return {
		"title": title,
		"data": {
			"datasets": [{"values": dataset_values, "formatted": values_formatted}],
			"labels": month_labels,
			**y_markers,
		},
		"summary": summary_values,
	}
