import functools
import inspect
from collections import OrderedDict
from collections.abc import Callable

import jingrow
from jingrow import TYPE_CHECKING, _
from jingrow.model.page import Page

from jcloude.utils import user as utils_user

if TYPE_CHECKING:
	from jcloude.jcloude.pagetype.team.team import Team


def only_owner(team: Callable[[Page, OrderedDict], str] = lambda document, _: str(document.team)):
	"""
	This guard can only be used for a class method. No other options are
	supported.
	"""

	def wrapper(fn):
		@functools.wraps(fn)
		def inner(self, *args, **kwargs):
			if utils_user.is_system_manager():
				return fn(self, *args, **kwargs)
			bound_args = inspect.signature(fn).bind(self, *args, **kwargs)
			bound_args.apply_defaults()
			t = team(self, bound_args.arguments)
			d: Team = jingrow.get_cached_pg("Team", t)
			if not d.is_team_owner():
				message = _("Only team owner can perform this action.")
				jingrow.throw(message, jingrow.PermissionError)
			return fn(self, *args, **kwargs)

		return inner

	return wrapper


def only_admin(
	team: Callable[[Page, OrderedDict], str] = lambda document, _: str(document.team),
	skip: Callable[[Page, OrderedDict], bool] = lambda _, __: False,
):
	"""
	This guard can only be used for a class method. No other options are
	supported. Team owner is considered as admin.
	"""

	def wrapper(fn):
		@functools.wraps(fn)
		def inner(self, *args, **kwargs):
			if utils_user.is_system_manager():
				return fn(self, *args, **kwargs)
			bound_args = inspect.signature(fn).bind(self, *args, **kwargs)
			bound_args.apply_defaults()
			if skip(self, bound_args.arguments):
				return fn(self, *args, **kwargs)
			t = team(self, bound_args.arguments)
			d: Team = jingrow.get_cached_pg("Team", t)
			if not (d.is_team_owner() or d.is_admin_user()):
				message = _("Only team admin can perform this action.")
				jingrow.throw(message, jingrow.PermissionError)
			return fn(self, *args, **kwargs)

		return inner

	return wrapper


def only_member(
	team: Callable[[Page, OrderedDict], str] = lambda document, _: str(document.team),
	user: Callable[[Page, OrderedDict], str] = lambda _, __: str(jingrow.session.user),
	error_message: str | None = None,
):
	"""
	This guard can only be used for a class method. No other options are
	supported.
	"""

	def wrapper(fn):
		@functools.wraps(fn)
		def inner(self, *args, **kwargs):
			if utils_user.is_system_manager():
				return fn(self, *args, **kwargs)
			bound_args = inspect.signature(fn).bind(self, *args, **kwargs)
			bound_args.apply_defaults()
			t = team(self, bound_args.arguments)
			u = user(self, bound_args.arguments)
			if not bool(jingrow.db.exists({"pagetype": "Team Member", "parent": t, "user": u})):
				message = error_message or _("Only team member can perform this action.")
				jingrow.throw(message, jingrow.PermissionError)
			return fn(self, *args, **kwargs)

		return inner

	return wrapper
