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


import jingrow
import jingrow.defaults
from jingrow import _
from jingrow.core.pagetype.pagetype.pagetype import (
	clear_permissions_cache,
	validate_permissions_for_pagetype,
)
from jingrow.exceptions import DoesNotExistError
from jingrow.modules.import_file import get_file_path, read_pg_from_file
from jingrow.permissions import (
	AUTOMATIC_ROLES,
	add_permission,
	get_all_perms,
	get_linked_pagetypes,
	reset_perms,
	setup_custom_perms,
	update_permission_property,
)
from jingrow.utils.user import get_users_with_role as _get_user_with_role

not_allowed_in_permission_manager = ["PageType", "Patch Log", "Module Def", "Transaction Log"]


@jingrow.whitelist()
def get_roles_and_pagetypes():
	jingrow.only_for("System Manager")

	active_domains = jingrow.get_active_domains()

	pagetypes = jingrow.get_all(
		"PageType",
		filters={
			"istable": 0,
			"name": ("not in", ",".join(not_allowed_in_permission_manager)),
		},
		or_filters={"ifnull(restrict_to_domain, '')": "", "restrict_to_domain": ("in", active_domains)},
		fields=["name"],
	)

	restricted_roles = ["Administrator"]
	if jingrow.session.user != "Administrator":
		custom_user_type_roles = jingrow.get_all("User Type", filters={"is_standard": 0}, fields=["role"])
		restricted_roles.extend(row.role for row in custom_user_type_roles)
		restricted_roles.extend(AUTOMATIC_ROLES)

	roles = jingrow.get_all(
		"Role",
		filters={
			"name": ("not in", restricted_roles),
			"disabled": 0,
		},
		or_filters={"ifnull(restrict_to_domain, '')": "", "restrict_to_domain": ("in", active_domains)},
		fields=["name"],
	)

	pagetypes_list = [{"label": _(d.get("name")), "value": d.get("name")} for d in pagetypes]
	roles_list = [{"label": _(d.get("name")), "value": d.get("name")} for d in roles]

	return {
		"pagetypes": sorted(pagetypes_list, key=lambda d: d["label"].casefold()),
		"roles": sorted(roles_list, key=lambda d: d["label"].casefold()),
	}


@jingrow.whitelist()
def get_permissions(pagetype: str | None = None, role: str | None = None):
	jingrow.only_for("System Manager")

	if role:
		out = get_all_perms(role)
		if pagetype:
			out = [p for p in out if p.parent == pagetype]

	else:
		filters = {"parent": pagetype}
		if jingrow.session.user != "Administrator":
			custom_roles = jingrow.get_all("Role", filters={"is_custom": 1}, pluck="name")
			filters["role"] = ["not in", custom_roles]

		out = jingrow.get_all("Custom PagePerm", fields="*", filters=filters, order_by="permlevel")
		if not out:
			out = jingrow.get_all("PagePerm", fields="*", filters=filters, order_by="permlevel")

	linked_pagetypes = {}
	for d in out:
		if d.parent not in linked_pagetypes:
			try:
				linked_pagetypes[d.parent] = get_linked_pagetypes(d.parent)
			except DoesNotExistError:
				# exclude & continue if linked pagetype is not found
				jingrow.clear_last_message()
				continue
		d.linked_pagetypes = linked_pagetypes[d.parent]
		if meta := jingrow.get_meta(d.parent):
			d.is_submittable = meta.is_submittable
			d.in_create = meta.in_create

	return out


@jingrow.whitelist()
def add(parent, role, permlevel):
	jingrow.only_for("System Manager")
	add_permission(parent, role, permlevel)


@jingrow.whitelist()
def update(pagetype, role, permlevel, ptype, value=None, if_owner=0):
	"""Update role permission params

	Args:
	        pagetype (str): Name of the PageType to update params for
	        role (str): Role to be updated for, eg "Website Manager".
	        permlevel (int): perm level the provided rule applies to
	        ptype (str): permission type, example "read", "delete", etc.
	        value (None, optional): value for ptype, None indicates False

	Returns:
	        str: Refresh flag is permission is updated successfully
	"""

	def clear_cache():
		jingrow.clear_cache(pagetype=pagetype)

	jingrow.only_for("System Manager")

	if ptype == "report" and value == "1" and if_owner == "1":
		jingrow.throw(_("Cannot set 'Report' permission if 'Only If Creator' permission is set"))

	out = update_permission_property(pagetype, role, permlevel, ptype, value, if_owner=if_owner)

	if ptype == "if_owner" and value == "1":
		update_permission_property(pagetype, role, permlevel, "report", "0", if_owner=value)

	jingrow.db.after_commit.add(clear_cache)

	return "refresh" if out else None


@jingrow.whitelist()
def remove(pagetype, role, permlevel, if_owner=0):
	jingrow.only_for("System Manager")
	setup_custom_perms(pagetype)

	jingrow.db.delete(
		"Custom PagePerm",
		{"parent": pagetype, "role": role, "permlevel": permlevel, "if_owner": if_owner},
	)

	if not jingrow.get_all("Custom PagePerm", {"parent": pagetype}):
		jingrow.throw(_("There must be atleast one permission rule."), title=_("Cannot Remove"))

	validate_permissions_for_pagetype(pagetype, for_remove=True, alert=True)


@jingrow.whitelist()
def reset(pagetype):
	jingrow.only_for("System Manager")
	reset_perms(pagetype)
	clear_permissions_cache(pagetype)


@jingrow.whitelist()
def get_users_with_role(role):
	jingrow.only_for("System Manager")
	return _get_user_with_role(role)


@jingrow.whitelist()
def get_standard_permissions(pagetype):
	jingrow.only_for("System Manager")
	meta = jingrow.get_meta(pagetype)
	if meta.custom:
		pg = jingrow.get_pg("PageType", pagetype)
		return [p.as_dict() for p in pg.permissions]
	else:
		# also used to setup permissions via patch
		path = get_file_path(meta.module, "PageType", pagetype)
		return read_pg_from_file(path).get("permissions")
