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

import xhiveframework
from xhiveframework import _
from xhiveframework.model import no_value_fields
from xhiveframework.model.document import Document


class Workflow(Document):
	def validate(self):
		self.set_active()
		self.create_custom_field_for_workflow_state()
		self.update_default_workflow_status()
		self.validate_docstatus()

	def on_update(self):
		self.update_doc_status()
		xhiveframework.clear_cache(doctype=self.document_type)
		xhiveframework.cache().delete_key("workflow_" + self.name)  # clear cache created in model/workflow.py

	def create_custom_field_for_workflow_state(self):
		xhiveframework.clear_cache(doctype=self.document_type)
		meta = xhiveframework.get_meta(self.document_type)
		if not meta.get_field(self.workflow_state_field):
			# create custom field
			xhiveframework.get_doc(
				{
					"doctype": "Custom Field",
					"dt": self.document_type,
					"__islocal": 1,
					"fieldname": self.workflow_state_field,
					"label": self.workflow_state_field.replace("_", " ").title(),
					"hidden": 1,
					"allow_on_submit": 1,
					"no_copy": 1,
					"fieldtype": "Link",
					"options": "Workflow State",
					"owner": "Administrator",
				}
			).save()

			xhiveframework.msgprint(
				_("Created Custom Field {0} in {1}").format(self.workflow_state_field, self.document_type)
			)

	def update_default_workflow_status(self):
		docstatus_map = {}
		states = self.get("states")
		for d in states:
			if not d.doc_status in docstatus_map:
				xhiveframework.db.sql(
					"""
					UPDATE `tab{doctype}`
					SET `{field}` = %s
					WHERE ifnull(`{field}`, '') = ''
					AND `docstatus` = %s
				""".format(
						doctype=self.document_type, field=self.workflow_state_field
					),
					(d.state, d.doc_status),
				)

				docstatus_map[d.doc_status] = d.state

	def update_doc_status(self):
		"""
		Checks if the docstatus of a state was updated.
		If yes then the docstatus of the document with same state will be updated
		"""
		doc_before_save = self.get_doc_before_save()
		before_save_states, new_states = {}, {}
		if doc_before_save:
			for d in doc_before_save.states:
				before_save_states[d.state] = d
			for d in self.states:
				new_states[d.state] = d

			for key in new_states:
				if key in before_save_states:
					if not new_states[key].doc_status == before_save_states[key].doc_status:
						xhiveframework.db.set_value(
							self.document_type,
							{self.workflow_state_field: before_save_states[key].state},
							"docstatus",
							new_states[key].doc_status,
							update_modified=False,
						)

	def validate_docstatus(self):
		def get_state(state):
			for s in self.states:
				if s.state == state:
					return s

			xhiveframework.throw(xhiveframework._("{0} not a valid State").format(state))

		for t in self.transitions:
			state = get_state(t.state)
			next_state = get_state(t.next_state)

			if state.doc_status == "2":
				xhiveframework.throw(
					xhiveframework._("Cannot change state of Cancelled Document. Transition row {0}").format(t.idx)
				)

			if state.doc_status == "1" and next_state.doc_status == "0":
				xhiveframework.throw(
					xhiveframework._("Submitted Document cannot be converted back to draft. Transition row {0}").format(
						t.idx
					)
				)

			if state.doc_status == "0" and next_state.doc_status == "2":
				xhiveframework.throw(xhiveframework._("Cannot cancel before submitting. See Transition {0}").format(t.idx))

	def set_active(self):
		if int(self.is_active or 0):
			# clear all other
			xhiveframework.db.sql(
				"""UPDATE `tabWorkflow` SET `is_active`=0
				WHERE `document_type`=%s""",
				self.document_type,
			)


@xhiveframework.whitelist()
def get_fieldnames_for(doctype):
	return [
		f.fieldname for f in xhiveframework.get_meta(doctype).fields if f.fieldname not in no_value_fields
	]


@xhiveframework.whitelist()
def get_workflow_state_count(doctype, workflow_state_field, states):
	states = xhiveframework.parse_json(states)
	result = xhiveframework.get_all(
		doctype,
		fields=[workflow_state_field, "count(*) as count"],
		filters={workflow_state_field: ["not in", states]},
		group_by=workflow_state_field,
	)
	return [r for r in result if r[workflow_state_field]]
