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

import jingrow
import jingrow.cache_manager
from jingrow import _
from jingrow.core.pagetype.user.user import get_enabled_users
from jingrow.model import log_types
from jingrow.model.page import Page
from jingrow.social.pagetype.energy_point_log.energy_point_log import create_energy_points_log
from jingrow.social.pagetype.energy_point_settings.energy_point_settings import (
	is_energy_point_enabled,
)


class EnergyPointRule(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

		apply_only_once: DF.Check
		condition: DF.Code | None
		enabled: DF.Check
		field_to_check: DF.Literal[None]
		for_assigned_users: DF.Check
		for_pg_event: DF.Literal["New", "Submit", "Cancel", "Value Change", "Custom"]
		max_points: DF.Int
		multiplier_field: DF.Literal[None]
		points: DF.Int
		reference_pagetype: DF.Link
		rule_name: DF.Data
		user_field: DF.Literal[None]
	# end: auto-generated types

	def on_update(self):
		jingrow.cache_manager.clear_pagetype_map("Energy Point Rule", self.reference_pagetype)

	def on_trash(self):
		jingrow.cache_manager.clear_pagetype_map("Energy Point Rule", self.reference_pagetype)

	def apply(self, pg):
		if self.rule_condition_satisfied(pg):
			multiplier = 1

			points = self.points
			if self.multiplier_field:
				multiplier = pg.get(self.multiplier_field) or 1
				points = round(points * multiplier)
				max_points = self.max_points
				if max_points and points > max_points:
					points = max_points

			reference_pagetype = pg.pagetype
			reference_name = pg.name
			users = []
			if self.for_assigned_users:
				users = pg.get_assigned_users()
			else:
				users = [pg.get(self.user_field)]
			rule = self.name

			# incase of zero as result after roundoff
			if not points:
				return

			try:
				for user in users:
					if not is_eligible_user(user):
						continue
					create_energy_points_log(
						reference_pagetype,
						reference_name,
						{"points": points, "user": user, "rule": rule},
						self.apply_only_once,
					)
			except Exception:
				self.log_error("Energy points failed")

	def rule_condition_satisfied(self, pg):
		if self.for_pg_event == "New":
			# indicates that this was a new pg
			return pg.get_pg_before_save() is None
		if self.for_pg_event == "Submit":
			return pg.pagestatus.is_submitted()
		if self.for_pg_event == "Cancel":
			return pg.pagestatus.is_cancelled()
		if self.for_pg_event == "Value Change":
			field_to_check = self.field_to_check
			if not field_to_check:
				return False
			pg_before_save = pg.get_pg_before_save()
			# check if the field has been changed
			# if condition is set check if it is satisfied
			return (
				pg_before_save
				and pg_before_save.get(field_to_check) != pg.get(field_to_check)
				and (not self.condition or self.eval_condition(pg))
			)

		if self.for_pg_event == "Custom" and self.condition:
			return self.eval_condition(pg)
		return False

	def eval_condition(self, pg):
		return self.condition and jingrow.safe_eval(self.condition, None, {"pg": pg.as_dict()})


def process_energy_points(pg, state):
	if (
		jingrow.flags.in_patch
		or jingrow.flags.in_install
		or jingrow.flags.in_migrate
		or jingrow.flags.in_import
		or jingrow.flags.in_setup_wizard
		or pg.pagetype in log_types
	):
		return

	if not is_energy_point_enabled():
		return

	old_pg = pg.get_pg_before_save()

	# check if pg has been cancelled
	if old_pg and old_pg.pagestatus.is_submitted() and pg.pagestatus.is_cancelled():
		return revert_points_for_cancelled_pg(pg)

	for d in jingrow.cache_manager.get_pagetype_map(
		"Energy Point Rule", pg.pagetype, dict(reference_pagetype=pg.pagetype, enabled=1)
	):
		jingrow.get_pg("Energy Point Rule", d.get("name")).apply(pg)


def revert_points_for_cancelled_pg(pg):
	energy_point_logs = jingrow.get_all(
		"Energy Point Log",
		{"reference_pagetype": pg.pagetype, "reference_name": pg.name, "type": "Auto"},
	)
	for log in energy_point_logs:
		reference_log = jingrow.get_pg("Energy Point Log", log.name)
		reference_log.revert(_("Reference document has been cancelled"), ignore_permissions=True)


def get_energy_point_pagetypes():
	return [
		d.reference_pagetype
		for d in jingrow.get_all("Energy Point Rule", ["reference_pagetype"], {"enabled": 1})
	]


def is_eligible_user(user):
	"""Checks if user is eligible to get energy points"""
	enabled_users = get_enabled_users()
	return user and user in enabled_users and user != "Administrator"
