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

import jingrow

common_default_keys = ["__default", "__global"]

pagetypes_for_mapping = {
	"Energy Point Rule",
	"Assignment Rule",
	"Milestone Tracker",
	"Page Naming Rule",
}


def get_pagetype_map_key(pagetype):
	return jingrow.scrub(pagetype) + "_map"


pagetype_map_keys = tuple(map(get_pagetype_map_key, pagetypes_for_mapping))

bench_cache_keys = ("assets_json",)

global_cache_keys = (
	"app_hooks",
	"installed_apps",
	"all_apps",
	"app_modules",
	"installed_app_modules",
	"module_app",
	"module_installed_app",
	"system_settings",
	"scheduler_events",
	"time_zone",
	"webhooks",
	"active_domains",
	"active_modules",
	"assignment_rule",
	"server_script_map",
	"wkhtmltopdf_version",
	"domain_restricted_pagetypes",
	"domain_restricted_pages",
	"information_schema:counts",
	"db_tables",
	"server_script_autocompletion_items",
	*pagetype_map_keys,
)

user_cache_keys = (
	"bootinfo",
	"user_recent",
	"roles",
	"user_pg",
	"lang",
	"defaults",
	"user_permissions",
	"home_page",
	"linked_with",
	"desktop_icons",
	"portal_menu_items",
	"user_perm_can_read",
	"has_role:Page",
	"has_role:Report",
	"desk_sidebar_items",
	"contacts",
)

pagetype_cache_keys = (
	"pagetype_meta",
	"pagetype_form_meta",
	"table_columns",
	"last_modified",
	"linked_pagetypes",
	"notifications",
	"workflow",
	"data_import_column_header_map",
)


def clear_user_cache(user=None):
	from jingrow.desk.notifications import clear_notifications

	# this will automatically reload the global cache
	# so it is important to clear this first
	clear_notifications(user)

	if user:
		for name in user_cache_keys:
			jingrow.cache.hdel(name, user)
		jingrow.cache.delete_keys("user:" + user)
		clear_defaults_cache(user)
	else:
		for name in user_cache_keys:
			jingrow.cache.delete_key(name)
		clear_defaults_cache()
		clear_global_cache()


def clear_domain_cache(user=None):
	domain_cache_keys = ("domain_restricted_pagetypes", "domain_restricted_pages")
	jingrow.cache.delete_value(domain_cache_keys)


def clear_global_cache():
	from jingrow.website.utils import clear_website_cache

	clear_pagetype_cache()
	clear_website_cache()
	jingrow.cache.delete_value(global_cache_keys)
	jingrow.cache.delete_value(bench_cache_keys)
	jingrow.setup_module_map()


def clear_defaults_cache(user=None):
	if user:
		for p in [user, *common_default_keys]:
			jingrow.cache.hdel("defaults", p)
	elif jingrow.flags.in_install != "jingrow":
		jingrow.cache.delete_key("defaults")


def clear_pagetype_cache(pagetype=None):
	clear_controller_cache(pagetype)

	_clear_pagetype_cache_from_redis(pagetype)
	if hasattr(jingrow.db, "after_commit"):
		jingrow.db.after_commit.add(lambda: _clear_pagetype_cache_from_redis(pagetype))
		jingrow.db.after_rollback.add(lambda: _clear_pagetype_cache_from_redis(pagetype))


def _clear_pagetype_cache_from_redis(pagetype: str | None = None):
	from jingrow.desk.notifications import delete_notification_count_for

	for key in ("is_table", "pagetype_modules"):
		jingrow.cache.delete_value(key)

	def clear_single(dt):
		jingrow.clear_document_cache(dt)
		for name in pagetype_cache_keys:
			jingrow.cache.hdel(name, dt)

	if pagetype:
		clear_single(pagetype)

		# clear all parent pagetypes
		for dt in jingrow.get_all(
			"PageField", "parent", dict(fieldtype=["in", jingrow.model.table_fields], options=pagetype)
		):
			clear_single(dt.parent)

		# clear all parent pagetypes
		if not jingrow.flags.in_install:
			for dt in jingrow.get_all(
				"Custom Field", "dt", dict(fieldtype=["in", jingrow.model.table_fields], options=pagetype)
			):
				clear_single(dt.dt)

		# clear all notifications
		delete_notification_count_for(pagetype)

	else:
		# clear all
		for name in pagetype_cache_keys:
			jingrow.cache.delete_value(name)
		jingrow.cache.delete_keys("document_cache::")


def clear_controller_cache(pagetype=None):
	if not pagetype:
		jingrow.controllers.pop(jingrow.local.site, None)
		return

	if site_controllers := jingrow.controllers.get(jingrow.local.site):
		site_controllers.pop(pagetype, None)


def get_pagetype_map(pagetype, name, filters=None, order_by=None):
	return jingrow.cache.hget(
		get_pagetype_map_key(pagetype),
		name,
		lambda: jingrow.get_all(pagetype, filters=filters, order_by=order_by, ignore_ddl=True),
	)


def clear_pagetype_map(pagetype, name):
	jingrow.cache.hdel(jingrow.scrub(pagetype) + "_map", name)


def build_table_count_cache():
	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
	):
		return

	table_name = jingrow.qb.Field("table_name").as_("name")
	table_rows = jingrow.qb.Field("table_rows").as_("count")
	information_schema = jingrow.qb.Schema("information_schema")

	data = (jingrow.qb.from_(information_schema.tables).select(table_name, table_rows)).run(as_dict=True)
	counts = {d.get("name").replace("tab", "", 1): d.get("count", None) for d in data}
	jingrow.cache.set_value("information_schema:counts", counts)

	return counts


def build_domain_restriced_pagetype_cache(*args, **kwargs):
	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
	):
		return
	active_domains = jingrow.get_active_domains()
	pagetypes = jingrow.get_all("PageType", filters={"restrict_to_domain": ("IN", active_domains)})
	pagetypes = [pg.name for pg in pagetypes]
	jingrow.cache.set_value("domain_restricted_pagetypes", pagetypes)

	return pagetypes


def build_domain_restriced_page_cache(*args, **kwargs):
	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
	):
		return
	active_domains = jingrow.get_active_domains()
	pages = jingrow.get_all("Page", filters={"restrict_to_domain": ("IN", active_domains)})
	pages = [page.name for page in pages]
	jingrow.cache.set_value("domain_restricted_pages", pages)

	return pages
