# Copyright (c) 2020, JINGROW
# License: MIT. See LICENSE

import jingrow
from jingrow import _
from jingrow.boot import get_allowed_report_names
from jingrow.config import get_modules_from_all_apps_for_user
from jingrow.model.page import Page
from jingrow.model.naming import append_number_if_name_exists
from jingrow.modules.export_file import export_to_files
from jingrow.query_builder import Criterion
from jingrow.query_builder.utils import PageType
from jingrow.utils import cint, flt


class NumberCard(Page):
	# begin: auto-generated types
	# This code is auto-generated. Do not modify anything in this block.

	from typing import TYPE_CHECKING

	if TYPE_CHECKING:
		from jingrow.types import DF

		aggregate_function_based_on: DF.Literal[None]
		color: DF.Color | None
		currency: DF.Link | None
		document_type: DF.Link | None
		dynamic_filters_json: DF.Code | None
		filters_config: DF.Code | None
		filters_json: DF.Code | None
		function: DF.Literal["Count", "Sum", "Average", "Minimum", "Maximum"]
		is_public: DF.Check
		is_standard: DF.Check
		label: DF.Data
		method: DF.Data | None
		module: DF.Link | None
		parent_document_type: DF.Link | None
		report_field: DF.Literal[None]
		report_function: DF.Literal["Sum", "Average", "Minimum", "Maximum"]
		report_name: DF.Link | None
		show_percentage_stats: DF.Check
		stats_time_interval: DF.Literal["Daily", "Weekly", "Monthly", "Yearly"]
		type: DF.Literal["Page Type", "Report", "Custom"]

	# end: auto-generated types
	def autoname(self):
		if not self.name:
			self.name = self.label

		if jingrow.db.exists("Number Card", self.name):
			self.name = append_number_if_name_exists("Number Card", self.name)

	def validate(self):
		if self.type == "Page Type":
			if not (self.document_type and self.function):
				jingrow.throw(_("Page Type and Function are required to create a number card"))

			if self.function != "Count" and not self.aggregate_function_based_on:
				jingrow.throw(_("Aggregate Field is required to create a number card"))

			if jingrow.get_meta(self.document_type).istable and not self.parent_document_type:
				jingrow.throw(_("Parent Page Type is required to create a number card"))

		elif self.type == "Report":
			if not (self.report_name and self.report_field and self.function):
				jingrow.throw(_("Report Name, Report Field and Fucntion are required to create a number card"))

		elif self.type == "Custom":
			if not self.method:
				jingrow.throw(_("Method is required to create a number card"))

	def on_update(self):
		if jingrow.conf.developer_mode and self.is_standard:
			export_to_files(record_list=[["Number Card", self.name]], record_module=self.module)


def get_permission_query_conditions(user=None):
	if not user:
		user = jingrow.session.user

	if user == "Administrator":
		return

	roles = jingrow.get_roles(user)
	if "System Manager" in roles:
		return None

	pagetype_condition = False
	module_condition = False

	allowed_pagetypes = [jingrow.db.escape(pagetype) for pagetype in jingrow.permissions.get_pagetypes_with_read()]
	allowed_modules = [
		jingrow.db.escape(module.get("module_name")) for module in get_modules_from_all_apps_for_user()
	]

	if allowed_pagetypes:
		pagetype_condition = "`tabNumber Card`.`document_type` in ({allowed_pagetypes})".format(
			allowed_pagetypes=",".join(allowed_pagetypes)
		)
	if allowed_modules:
		module_condition = """`tabNumber Card`.`module` in ({allowed_modules})
			or `tabNumber Card`.`module` is NULL""".format(allowed_modules=",".join(allowed_modules))

	return f"""
		{pagetype_condition}
		and
		{module_condition}
	"""


def has_permission(pg, ptype, user):
	roles = jingrow.get_roles(user)
	if "System Manager" in roles:
		return True

	if pg.type == "Report":
		if pg.report_name in get_allowed_report_names():
			return True
	else:
		allowed_pagetypes = tuple(jingrow.permissions.get_pagetypes_with_read())
		if pg.document_type in allowed_pagetypes:
			return True

	return False


@jingrow.whitelist()
def get_result(pg, filters, to_date=None):
	pg = jingrow.parse_json(pg)
	fields = []
	sql_function_map = {
		"Count": "count",
		"Sum": "sum",
		"Average": "avg",
		"Minimum": "min",
		"Maximum": "max",
	}

	function = sql_function_map[pg.function]

	if function == "count":
		fields = [f"{function}(*) as result"]
	else:
		fields = [f"{function}({pg.aggregate_function_based_on}) as result"]

	if not filters:
		filters = []
	elif isinstance(filters, str):
		filters = jingrow.parse_json(filters)

	if to_date:
		filters.append([pg.document_type, "creation", "<", to_date])

	res = jingrow.get_list(
		pg.document_type, fields=fields, filters=filters, parent_pagetype=pg.parent_document_type
	)
	number = res[0]["result"] if res else 0

	return flt(number)


@jingrow.whitelist()
def get_percentage_difference(pg, filters, result):
	pg = jingrow.parse_json(pg)
	result = jingrow.parse_json(result)

	pg = jingrow.get_pg("Number Card", pg.name)

	if not pg.get("show_percentage_stats"):
		return

	previous_result = calculate_previous_result(pg, filters)
	if previous_result == 0:
		return None
	else:
		if result == previous_result:
			return 0
		else:
			return ((result / previous_result) - 1) * 100.0


def calculate_previous_result(pg, filters):
	from jingrow.utils import add_to_date

	current_date = jingrow.utils.now()
	if pg.stats_time_interval == "Daily":
		previous_date = add_to_date(current_date, days=-1)
	elif pg.stats_time_interval == "Weekly":
		previous_date = add_to_date(current_date, weeks=-1)
	elif pg.stats_time_interval == "Monthly":
		previous_date = add_to_date(current_date, months=-1)
	else:
		previous_date = add_to_date(current_date, years=-1)

	return get_result(pg, filters, previous_date)


@jingrow.whitelist()
def create_number_card(args):
	args = jingrow.parse_json(args)
	pg = jingrow.new_pg("Number Card")

	pg.update(args)
	pg.insert(ignore_permissions=True)
	return pg


@jingrow.whitelist()
@jingrow.validate_and_sanitize_search_inputs
def get_cards_for_user(pagetype, txt, searchfield, start, page_len, filters):
	meta = jingrow.get_meta(pagetype)
	searchfields = meta.get_search_fields()
	search_conditions = []

	if not jingrow.db.exists("PageType", pagetype):
		return

	numberCard = PageType("Number Card")

	if txt:
		search_conditions = [numberCard[field].like(f"%{txt}%") for field in searchfields]

	condition_query = jingrow.qb.get_query(
		pagetype,
		filters=filters,
		validate_filters=True,
	)

	return (
		condition_query.select(numberCard.name, numberCard.label, numberCard.document_type)
		.where((numberCard.owner == jingrow.session.user) | (numberCard.is_public == 1))
		.where(Criterion.any(search_conditions))
	).run()


@jingrow.whitelist()
def create_report_number_card(args):
	card = create_number_card(args)
	args = jingrow.parse_json(args)
	args.name = card.name
	if args.dashboard:
		add_card_to_dashboard(jingrow.as_json(args))


@jingrow.whitelist()
def add_card_to_dashboard(args):
	args = jingrow.parse_json(args)

	dashboard = jingrow.get_pg("Dashboard", args.dashboard)
	dashboard_link = jingrow.new_pg("Number Card Link")
	dashboard_link.card = args.name

	if args.set_standard and dashboard.is_standard:
		card = jingrow.get_pg("Number Card", dashboard_link.card)
		card.is_standard = 1
		card.module = dashboard.module
		card.save()

	dashboard.append("cards", dashboard_link)
	dashboard.save()
