from __future__ import annotations

import enum
from dataclasses import dataclass
from typing import TYPE_CHECKING

from files.helpers.config.const import PERMS

if TYPE_CHECKING:
	from files.classes.user import User
	from files.helpers.content import Submittable


class StateMod(enum.Enum):
    VISIBLE = 0
    FILTERED = 1
    REMOVED = 2

class StateReport(enum.Enum):
    UNREPORTED = 0
    RESOLVED = 1
    REPORTED = 2
    IGNORED = 3


@dataclass(frozen=True, kw_only=True, slots=True)
class VisibilityState:
	'''
	The full moderation state machine. It holds the moderation state, report
	state, deleted information, and shadowban information. A decision to show
	or hide a post or comment should be able to be done with information from
	this alone.
	'''
	state_mod: StateMod
	state_mod_set_by: str | None
	state_report: StateReport
	state_mod_set_by: str | None
	deleted: bool
	op_shadowbanned: bool
	op_id: int
	op_name_safe: str
	distinguished: bool
	is_blocking: bool

	@property
	def removed(self) -> bool:
		return self.state_mod == StateMod.REMOVED
	
	@property
	def filtered(self) -> bool:
		return self.state_mod == StateMod.FILTERED
	
	@property
	def reports_ignored(self) -> bool:
		return self.state_report == StateReport.IGNORED

	@classmethod
	def from_submittable(cls, target: Submittable) -> "VisibilityState":
		return cls(
			state_mod=target.state_mod,
			state_mod_set_by=target.state_mod_set_by, # type: ignore
			state_report=target.state_report,
			deleted=bool(target.state_user_deleted_utc != None),
			op_shadowbanned=bool(target.author.shadowbanned),
			op_id=target.author_id,  # type: ignore
			op_name_safe=target.author_name,
			distinguished=bool(getattr(target, 'distinguish_level', 0)),
			is_blocking=bool(getattr(target, 'is_blocking', False)),
		)
	
	def visibility_and_message(self, v: User | None) -> tuple[bool, str | None]:
		'''
		Returns a tuple of whether this content is visible and a publicly 
		visible message to accompany it. The visibility state machine is
		a slight mess but... this should at least unify the state checks.
		'''
		def can(v: User | None, perm_level: int) -> bool:
			return v and v.admin_level >= perm_level

		can_moderate: bool = can(v, PERMS['POST_COMMENT_MODERATION'])
		can_shadowban: bool = can(v, PERMS['USER_SHADOWBAN'])

		is_blocking = self.is_blocking
		
		if v and v.id == self.op_id:
			return True, None
		if (self.removed and not can_moderate) or \
				(self.op_shadowbanned and not can_shadowban):
			msg: str = 'Removed'
			if self.state_mod_set_by:
				msg = f'Removed by @{self.state_mod_set_by}'
			return False, msg
		if self.filtered and not can_moderate:
			return False, 'Filtered'
		if self.deleted and not can_moderate:
			return False, 'Deleted by author'
		if is_blocking:
			if self.distinguished:
				return True, f'(You are blocking @{self.op_name_safe}, but this is an official post and cannot be blocked)'
			return False, f'You are blocking @{self.op_name_safe}'
		return True, None
	
	def is_visible_to(self, v: User | None) -> bool:
		return self.visibility_and_message(v)[0]
	
	def added_message(self, v: User | None) -> str | None:
		return self.visibility_and_message(v)[1]
	
	@property
	def publicly_visible(self) -> bool:
		return all(
			not state for state in 
			[self.deleted, self.removed, self.filtered, self.op_shadowbanned]
		)
	
	@property
	def explicitly_moderated(self) -> bool:
		'''
		Whether this was removed or filtered and not as the result of a shadowban
		'''
		return self.removed or self.filtered
