import inspect
from typing import Protocol, runtime_checkable

import jingrow
from jingrow import _
from jingrow.model.base_page import get_controller


@runtime_checkable
class VirtualPagetype(Protocol):
	"""This class documents requirements that must be met by a pagetype controller to function as virtual pagetype


	Additional requirements:
	- PageType controller has to inherit from `jingrow.model.page.Page` class

	Note:
	- "Backend" here means any storage service, it can be a database, flat file or network call to API.
	"""

	# ============ class/static methods ============

	@staticmethod
	def get_list(args) -> list[jingrow._dict]:
		"""Similar to reportview.get_list"""
		...

	@staticmethod
	def get_count(args) -> int:
		"""Similar to reportview.get_count, return total count of documents on listview."""
		...

	@staticmethod
	def get_stats(args):
		"""Similar to reportview.get_stats, return sidebar stats."""
		...

	# ============ instance methods ============

	def db_insert(self, *args, **kwargs) -> None:
		"""Serialize the `Page` object and insert it in backend."""
		...

	def load_from_db(self) -> None:
		"""Using self.name initialize current document from backend data.

		This is responsible for updatinng __dict__ of class with all the fields on pagetype."""
		...

	def db_update(self, *args, **kwargs) -> None:
		"""Serialize the `Page` object and update existing document in backend."""
		...

	def delete(self, *args, **kwargs) -> None:
		"""Delete the current document from backend"""
		...


def validate_controller(pagetype: str) -> None:
	try:
		controller = get_controller(pagetype)
	except ImportError:
		jingrow.msgprint(_("Failed to import virtual pagetype {}, is controller file present?").format(pagetype))
		return

	def _as_str(method):
		if hasattr(method, "__module__"):
			return f"{method.__module__}.{method.__qualname__}"
		return "None"

	expected_static_method = ["get_list", "get_count", "get_stats"]
	for m in expected_static_method:
		method = inspect.getattr_static(controller, m, None)
		if not isinstance(method, staticmethod):
			jingrow.msgprint(
				_("Virtual PageType {} requires a static method called {} found {}").format(
					jingrow.bold(pagetype), jingrow.bold(m), jingrow.bold(_as_str(method))
				),
				title=_("Incomplete Virtual Pagetype Implementation"),
			)

	expected_instance_methods = ["db_insert", "db_update", "load_from_db", "delete"]
	parent_class = controller.mro()[1]
	for m in expected_instance_methods:
		method = getattr(controller, m, None)
		original_method = getattr(parent_class, m, None)
		if method == original_method:
			jingrow.msgprint(
				_("Virtual PageType {} requires overriding an instance method called {} found {}").format(
					jingrow.bold(pagetype), jingrow.bold(m), jingrow.bold(_as_str(method))
				),
				title=_("Incomplete Virtual Pagetype Implementation"),
			)
