from datetime import datetime
from enum import Enum
from typing import Optional

from sqlalchemy import Enum as SQLEnum, ForeignKey, JSON
from sqlalchemy.orm import mapped_column, relationship, DeclarativeBase, Mapped

from ..sqlalchemy.mixins import ReprMixin

class SQLChatType(Enum):
    SENDER = "sender"
    PRIVATE = "private"
    GROUP = "group"
    SUPERGROUP = "supergroup"
    CHANNEL = "channel"

class BaseModel(ReprMixin, DeclarativeBase):
	pass

class ChatModel(BaseModel):
	__tablename__ = "chats"

	id: Mapped[int] = mapped_column(primary_key=True, autoincrement=False)
	type: Mapped[SQLChatType] = mapped_column(SQLEnum(SQLChatType))
	title: Mapped[Optional[str]]
	full_name: Mapped[str]
	username: Mapped[Optional[str]]
	bio: Mapped[Optional[str]]
	joined_at: Mapped[Optional[datetime]]

	messages: Mapped[list["MessageModel"]] = relationship(back_populates="chat")
	bot_messages: Mapped[list["BotMessageModel"]] = relationship(back_populates="chat")

class UserModel(BaseModel):
	__tablename__ = "users"
	
	id: Mapped[int] = mapped_column(primary_key=True, autoincrement=False)
	username: Mapped[Optional[str]]
	first_name: Mapped[str]
	last_name: Mapped[Optional[str]]
	full_name: Mapped[str]
	bio: Mapped[Optional[str]]
	language_code: Mapped[Optional[str]]
	is_premium: Mapped[bool] = mapped_column(default=False)
	joined_at: Mapped[Optional[datetime]]
	blocked: Mapped[bool] = mapped_column(default=False)

	messages: Mapped[list["MessageModel"]] = relationship(back_populates="user")
	callback_queries: Mapped[list["CallbackQueryModel"]] = relationship(back_populates="user")
	inline_queries: Mapped[list["InlineQueryModel"]] = relationship(back_populates="user")

class MessageModelMixin:
	id: Mapped[int] = mapped_column(primary_key=True, autoincrement=False)
	chat_id: Mapped[int] = mapped_column(ForeignKey("chats.id"))
	text: Mapped[Optional[str]]
	md_text: Mapped[Optional[str]]
	html_text: Mapped[Optional[str]]
	entities: Mapped[Optional[list[dict]]] = mapped_column(JSON)
	content_type: Mapped[str]
	file_id: Mapped[Optional[str]]
	media_group_id: Mapped[Optional[str]]
	reply_to_message_id: Mapped[Optional[int]]
	date: Mapped[datetime]

class MessageModel(MessageModelMixin, BaseModel):
	__tablename__ = "messages"

	chat: Mapped["ChatModel"] = relationship(back_populates="messages")
	user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
	user: Mapped["UserModel"] = relationship(back_populates="messages")

class BotMessageModel(MessageModelMixin, BaseModel):
	__tablename__ = "bot_messages"
	
	chat: Mapped["ChatModel"] = relationship(back_populates="bot_messages")
	inline_keyboard: Mapped[Optional[list[list[dict]]]] = mapped_column(JSON)

class CallbackQueryModel(BaseModel):
	__tablename__ = "callback_queries"
	
	id: Mapped[str] = mapped_column(primary_key=True)
	user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
	user: Mapped["UserModel"] = relationship(back_populates="callback_queries")
	message_id: Mapped[int] = mapped_column(ForeignKey("bot_messages.id"))
	message: Mapped["BotMessageModel"] = relationship()
	data: Mapped[str]
	date: Mapped[datetime]

class InlineQueryModel(BaseModel):
	__tablename__ = "inline_queries"
	
	id: Mapped[int] = mapped_column(primary_key=True, autoincrement=False)
	user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
	user: Mapped["UserModel"] = relationship(back_populates="inline_queries")
	query: Mapped[str]
	chat_type: Mapped[str]
	date: Mapped[datetime]

__all__ = ["BaseModel", "ChatModel","UserModel", "MessageModel", "BotMessageModel", "InlineQueryModel"]