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

import jingrow


def get_all_webhooks():
	# query webhooks
	webhooks_list = jingrow.get_all(
		"Webhook",
		fields=["name", "condition", "webhook_docevent", "webhook_pagetype", "background_jobs_queue"],
		filters={"enabled": True},
	)

	# make webhooks map
	webhooks = {}
	for w in webhooks_list:
		webhooks.setdefault(w.webhook_pagetype, []).append(w)

	return webhooks


def run_webhooks(pg, method):
	"""Run webhooks for this method"""

	jingrow_flags = jingrow.local.flags

	if jingrow_flags.in_import or jingrow_flags.in_patch or jingrow_flags.in_install or jingrow_flags.in_migrate:
		return

	# load all webhooks from cache / DB
	webhooks = jingrow.cache.get_value("webhooks", get_all_webhooks)

	# get webhooks for this pagetype
	webhooks_for_pg = webhooks.get(pg.pagetype, None)

	if not webhooks_for_pg:
		# no webhooks, quit
		return

	event_list = ["on_update", "after_insert", "on_submit", "on_cancel", "on_trash"]

	if not pg.flags.in_insert:
		# value change is not applicable in insert
		event_list.append("on_change")
		event_list.append("before_update_after_submit")

	from jingrow.integrations.pagetype.webhook.webhook import get_context

	for webhook in webhooks_for_pg:
		trigger_webhook = False
		event = method if method in event_list else None
		if not webhook.condition:
			trigger_webhook = True
		elif jingrow.safe_eval(webhook.condition, eval_locals=get_context(pg)):
			trigger_webhook = True

		if trigger_webhook and event and webhook.webhook_docevent == event:
			_add_webhook_to_queue(webhook, pg)


def _add_webhook_to_queue(webhook, pg):
	# Maintain a queue and flush on commit
	if not getattr(jingrow.local, "_webhook_queue", None):
		jingrow.local._webhook_queue = []
		jingrow.db.after_commit.add(flush_webhook_execution_queue)

	jingrow.local._webhook_queue.append(jingrow._dict(pg=pg, webhook=webhook))


def flush_webhook_execution_queue():
	"""Enqueue all pending webhook executions.

	Each webhook can trigger multiple times on same document or even different instance of same
	document. We assume that last enqueued version of document is the final document for this DB
	transaction.
	"""
	if not getattr(jingrow.local, "_webhook_queue", None):
		return

	uniq_hooks = set()
	unique_last_instances = []

	# reverse
	jingrow.local._webhook_queue.reverse()

	# deduplicate on (pg.name, webhook.name)
	# 'pg' holds the last instance values
	for execution in jingrow.local._webhook_queue:
		key = (execution.webhook.get("name"), execution.pg.get("name"))
		if key not in uniq_hooks:
			uniq_hooks.add(key)
			unique_last_instances.append(execution)

	# Clear original queue so next enqueue computation happens correctly.
	del jingrow.local._webhook_queue

	# reverse again, to get back the original order on which to execute webhooks
	unique_last_instances.reverse()

	for instance in unique_last_instances:
		jingrow.enqueue(
			"jingrow.integrations.pagetype.webhook.webhook.enqueue_webhook",
			pg=instance.pg,
			webhook=instance.webhook,
			now=jingrow.flags.in_test,
			queue=instance.webhook.background_jobs_queue or "default",
		)
