from datetime import datetime

from sqlalchemy.ext.asyncio import AsyncEngine

from aiogram import BaseMiddleware
from aiogram.enums import ChatType, ContentType, ChatMemberStatus
from aiogram.types import TelegramObject, User, Message, CallbackQuery, InlineQuery, ChatMemberUpdated

from .models import BaseModel, ChatModel, UserModel, MessageModel, CallbackQueryModel, InlineQueryModel
from ..sqlalchemy.session import AsyncSessionManagerFactory
from ..utils.logging import loggers

class AnalyticsMiddleware(BaseMiddleware):
	"""
	Middleware to collect analytics from user interactions.

	:param path: Path to SQL database file
	:param chats: Whether to track chats
	:param messages: Whether to track messages
	:param callback_queries: Whether to track callback queries
	:param inline_queries: Whether to track inline queries
	"""

	def __init__(self, engine: str | AsyncEngine, chats: bool, messages: bool, callback_queries: bool, inline_queries: bool):
		self.tables_created = False

		self.engine = engine
		self.session_manager_factory = AsyncSessionManagerFactory(self.engine)

		self.chats = chats
		self.messages = messages
		self.inline_queries = inline_queries
		self.callback_queries = callback_queries

	async def create_all(self):
		if self.tables_created:
			loggers.analytics.error("Tables are already created")

			return False
		
		async with self.engine.begin() as connection:
			await connection.run_sync(BaseModel.metadata.create_all)

		self.tables_created = True

		return True

	async def __call__(self, handler, event: TelegramObject, data: dict):
		user: User = data.get("event_from_user")
		
		if user:
			async with self.session_manager_factory() as session:
				is_new = await session.get(UserModel, user.id) is None

				if is_new:
					loggers.analytics.info(f"New user id={user.id}")

				model = UserModel(
					id=user.id,
					username=user.username,
					first_name=user.first_name,
					last_name=user.last_name,
					full_name=user.full_name,
					is_premium=bool(user.is_premium)
				)

				if is_new:
					model.joined_at = datetime.now()

				await session.merge(model)

			if isinstance(event, ChatMemberUpdated):
				if event.chat.type == ChatType.PRIVATE and event.bot.id in (event.old_chat_member.user.id, event.new_chat_member.user.id):
					if event.new_chat_member.status == ChatMemberStatus.MEMBER:
						blocked = False
					elif event.new_chat_member.status == ChatMemberStatus.KICKED:
						blocked = True
					else:
						blocked = None

					if blocked is not None:
						if blocked:
							loggers.analytics.info(f"Blocked by user id={user.id}")
						else:
							loggers.analytics.info(f"Unblocked by user id={user.id}")

						async with self.session_manager_factory() as session:
							(await session.get(UserModel, user.id)).blocked = blocked
				
				if self.chats:
					loggers.analytics.info("chats")
					async with self.session_manager_factory() as session:
						is_new = await session.get(ChatModel, event.chat.id) is None

						model = ChatModel(
							id=event.chat.id,
							type=event.chat.type,
							title=event.chat.title,
							full_name=event.chat.full_name,
							username=event.chat.username,
							bio=event.chat.bio
						)

						if is_new:
							model.joined_at = event.date

						await session.merge(model)
		
			if isinstance(event, Message) and self.messages:
				loggers.analytics.info(f"New message from user id={user.id}")

				async with self.session_manager_factory() as session:
					if event.content_type == ContentType.PHOTO:
						file_id = event.photo[-1].file_id
					elif event.content_type in [
						ContentType.DOCUMENT,
						ContentType.VIDEO,
						ContentType.AUDIO,
						ContentType.VOICE,
						ContentType.VIDEO_NOTE,
						ContentType.ANIMATION,
						ContentType.STICKER
					]:
						file_id = getattr(event, event.content_type).file_id
					else:
						file_id = None

					model = MessageModel(
						id=event.message_id,
						chat_id=event.chat.id,
						user_id=user.id,
						text=event.text or event.caption,
						md_text=event.md_text,
						html_text=event.html_text,
						entities=event.model_dump()["entities"],
						content_type=event.content_type,
						file_id=file_id,
						media_group_id=event.media_group_id,
						reply_to_message_id=event.reply_to_message.message_id if event.reply_to_message else None,
						date=event.date
					)

					session.add(model)

			if isinstance(event, CallbackQuery) and self.callback_queries:
				loggers.analytics.info(f"New callback query from user id={user.id}")

				async with self.session_manager_factory() as session:
					model = CallbackQueryModel(
						id=event.id,
						user_id=user.id,
						message_id=event.message.message_id,
						data=event.data,
						date=datetime.now()
					)

					session.add(model)

			if isinstance(event, InlineQuery) and self.inline_queries:
				loggers.analytics.info(f"New inline query from user id={user.id}")

				async with self.session_manager_factory() as session:
					model = InlineQueryModel(
						id=event.id,
						user=await session.get(UserModel, user.id),
						query=event.query,
						chat_type=event.chat_type,
						date=datetime.now()
					)

					session.add(model)

		return await handler(event, data)
	
__all__ = ["AnalyticsMiddleware"]