from __future__ import annotations
import time

from typing import List, Optional
import sqlalchemy
from sqlalchemy import update
from sqlalchemy.orm import mapped_column, relationship, Mapped

from api.model.base import BaseHelper, BaseModel
from api.model.toolkit_ui.page_title import PageTitleModel
from service.database import DatabaseService


class ConversationModel(BaseModel):
    __tablename__ = "toolkit_ui_conversation"

    id: Mapped[int] = mapped_column(sqlalchemy.Integer, primary_key=True, autoincrement=True)
    user_id: Mapped[int] = mapped_column(sqlalchemy.Integer, index=True)
    module: Mapped[str] = mapped_column(sqlalchemy.String(60), index=True)
    title: Mapped[str] = mapped_column(sqlalchemy.String(255), nullable=True)
    thumbnail: Mapped[str] = mapped_column(sqlalchemy.Text(), nullable=True)
    description: Mapped[str] = mapped_column(sqlalchemy.Text(), nullable=True)
    page_id: Mapped[int] = mapped_column(sqlalchemy.ForeignKey("toolkit_ui_page_title.page_id"), index=True, nullable=True)
    rev_id: Mapped[int] = mapped_column(sqlalchemy.Integer, nullable=True)
    updated_at: Mapped[int] = mapped_column(sqlalchemy.BigInteger, index=True)
    pinned: Mapped[bool] = mapped_column(
        sqlalchemy.Boolean, default=False, index=True)
    extra: Mapped[dict] = mapped_column(sqlalchemy.JSON, default={})

    page_info: Mapped[PageTitleModel] = relationship("PageTitleModel", lazy="joined")


class ConversationHelper(BaseHelper):
    async def add(self, obj: ConversationModel):
        obj.updated_at = int(time.time())
        self.session.add(obj)
        await self.session.commit()
        await self.session.refresh(obj)
        return obj

    async def refresh_updated_at(self, conversation_id: int):
        stmt = update(ConversationModel).where(ConversationModel.id ==
                                               conversation_id).values(updated_at=int(time.time()))
        await self.session.execute(stmt)
        await self.session.commit()

    async def update(self, obj: ConversationModel):
        obj.updated_at = int(time.time())
        await self.session.merge(obj)
        await self.session.commit()
        await self.session.refresh(obj)
        return obj

    async def get_conversation_list(self, user_id: int, module: Optional[str] = None, page_id: Optional[int] = None) -> List[ConversationModel]:
        stmt = sqlalchemy.select(ConversationModel) \
            .where(ConversationModel.user_id == user_id)

        if module is not None:
            stmt = stmt.where(ConversationModel.module == module)

        if page_id is not None:
            stmt = stmt.where(ConversationModel.page_id == page_id)

        stmt = stmt.order_by(ConversationModel.pinned.desc(),
                             ConversationModel.updated_at.desc())

        return await self.session.scalars(stmt)

    async def find_by_id(self, id: int):
        stmt = sqlalchemy.select(ConversationModel).where(
            ConversationModel.id == id)
        return await self.session.scalar(stmt)
    
    async def filter_user_owned_ids(self, ids: list[int], user_id: int) -> list[int]:
        stmt = sqlalchemy.select(ConversationModel.id) \
            .where(ConversationModel.id.in_(ids)).where(ConversationModel.user_id == user_id)
        return list(await self.session.scalars(stmt))

    async def remove(self, conversation_id: int):
        stmt = sqlalchemy.delete(ConversationModel).where(
            ConversationModel.id == conversation_id)
        await self.session.execute(stmt)
        await self.session.commit()

    async def remove_multiple(self, ids: list[int]):
        stmt = sqlalchemy.delete(ConversationModel) \
            .where(ConversationModel.id.in_(ids))

        await self.session.execute(stmt)
        await self.session.commit()