from typing import Any, Optional, Union

from aiogram import Dispatcher, Router
from aiogram.client.default import Default
from aiogram.enums import ChatType, ContentType
from aiogram.types import Message, MessageEntity, LinkPreviewOptions, ReplyParameters, ReplyMarkupUnion

from .middleware import AnalyticsMiddleware
from .models import BotMessageModel
from ..sqlalchemy.session import AsyncSessionManagerFactory
from ..utils.logging import loggers

async def _empty_callback(event):
	pass

async def _false_filter(event):
	return False

async def setup_analytics(
	router: Router,
	path="analytics.db",
	chats: bool=True,
	messages: bool=True,
	bot_messages: bool=True,
	callback_queries: bool=True,
	inline_queries: bool=False
):
	"""
	Setup analytics for `router`.

	:param router: Router to setup analytics for
	:param chats: Whether to track chats
	:param messages: Whether to track messages
	:param bot_messages: Whether to track bot (outgoing) messages
	:param callback_queries: Whether to track callback queries
	:param inline_queries: Whether to track inline queries
	"""

	session_manager_factory = AsyncSessionManagerFactory(path)

	middleware = AnalyticsMiddleware(
		engine=session_manager_factory.engine,
		chats=chats,
		messages=messages,
		callback_queries=callback_queries,
		inline_queries=inline_queries
	)

	await middleware.create_all()

	router.my_chat_member.register(_empty_callback, _false_filter)
	router.my_chat_member.outer_middleware(middleware)

	if messages:
		router.message.register(_empty_callback, _false_filter)
		router.message.outer_middleware(middleware)

	if bot_messages:
		super_answer = Message.answer

		async def answer(
			self,
			text: str,
			parse_mode: Optional[Union[str, Default]] = Default("parse_mode"),
			entities: Optional[list[MessageEntity]] = None,
			link_preview_options: Optional[Union[LinkPreviewOptions, Default]] = Default(
				"link_preview"
			),
			disable_notification: Optional[bool] = None,
			protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
			allow_paid_broadcast: Optional[bool] = None,
			message_effect_id: Optional[str] = None,
			reply_parameters: Optional[ReplyParameters] = None,
			reply_markup: Optional[ReplyMarkupUnion] = None,
			allow_sending_without_reply: Optional[bool] = None,
			disable_web_page_preview: Optional[Union[bool, Default]] = Default(
				"link_preview_is_disabled"
			),
			reply_to_message_id: Optional[int] = None,
			**kwargs: Any,
		):
			message = await super_answer(self, text, parse_mode, entities, link_preview_options, disable_notification, protect_content, allow_paid_broadcast, message_effect_id, reply_parameters, reply_markup, allow_sending_without_reply, disable_web_page_preview, reply_to_message_id, **kwargs)

			if message.content_type == ContentType.PHOTO:
				file_id = message.photo[-1].file_id
			elif message.content_type in [
				ContentType.DOCUMENT,
				ContentType.VIDEO,
				ContentType.AUDIO,
				ContentType.VOICE,
				ContentType.VIDEO_NOTE,
				ContentType.ANIMATION,
				ContentType.STICKER
			]:
				file_id = getattr(message, message.content_type).file_id
			else:
				file_id = None

			if message.reply_markup and message.reply_markup.inline_keyboard:
				inline_keyboard = message.model_dump()["reply_markup"]["inline_keyboard"]
			else:
				inline_keyboard = None

			async with session_manager_factory() as session:
				model = BotMessageModel(
					id=message.message_id,
					chat_id=message.chat.id,
					text=message.text or message.caption,
					md_text=message.md_text,
					html_text=message.html_text,
					entities=message.model_dump()["entities"],
					content_type=message.content_type,
					file_id=file_id,
					media_group_id=message.media_group_id,
					reply_to_message_id=message.reply_to_message.message_id if message.reply_to_message else None,
					inline_keyboard=inline_keyboard,
					date=message.date
				)

				session.add(model)

			if message.chat.type == ChatType.PRIVATE:
				chat_type = "user"
			else:
				chat_type = message.chat.type

			loggers.analytics.info(f"New outgoing message to {chat_type} id={message.chat.id}")

			return message
		
		Message.answer = answer

	if callback_queries:
		router.callback_query.register(_empty_callback, _false_filter)
		router.callback_query.outer_middleware(middleware)

	if inline_queries:
		router.inline_query.register(_empty_callback, _false_filter)
		router.inline_query.outer_middleware(middleware)

	if isinstance(router, Dispatcher):
		loggers.analytics.info("Setup analytics for dispatcher")
	else:
		loggers.analytics.info(f"Setup analytics for router name={router.name!r}")

__all__ = ["setup_analytics"]