from __future__ import annotations

from datetime import UTC, datetime

from sqlalchemy import extract, func, select
from sqlalchemy.orm import Session

from app.models.chat import ChatMessage, ChatSession, TopicSession
from app.models.user import User


class TopicSessionService:
    @staticmethod
    def active_for_session(db: Session, *, user: User, session: ChatSession) -> TopicSession | None:
        return db.scalar(
            select(TopicSession)
            .where(
                TopicSession.user_id == user.id,
                TopicSession.chat_session_id == session.id,
                TopicSession.status == "active",
            )
            .order_by(TopicSession.created_at.desc(), TopicSession.id.desc())
            .limit(1)
        )

    @staticmethod
    def monthly_used_count(db: Session, user_id: int, *, at: datetime | None = None) -> int:
        current = at or _now()
        return int(
            db.scalar(
                select(func.count(TopicSession.id)).where(
                    TopicSession.user_id == user_id,
                    extract("year", TopicSession.started_at) == current.year,
                    extract("month", TopicSession.started_at) == current.month,
                    TopicSession.quota_deducted == 1,
                )
            )
            or 0
        )

    @staticmethod
    def get_or_create_active(
        db: Session,
        *,
        user: User,
        session: ChatSession,
        question: str,
        deduct_quota: bool,
    ) -> TopicSession:
        topic = TopicSessionService.active_for_session(db, user=user, session=session)
        if topic is not None:
            return topic
        topic = TopicSession(
            user_id=user.id,
            chat_session_id=session.id,
            title=_title_from_question(question),
            core_question=question.strip(),
            status="active",
            message_count=0,
            token_input=0,
            token_output=0,
            quota_deducted=1 if deduct_quota else 0,
            started_at=_now(),
        )
        db.add(topic)
        db.flush()
        return topic

    @staticmethod
    def attach_user_message(message: ChatMessage, topic: TopicSession) -> None:
        message.topic_session_id = topic.id
        topic.message_count += 1

    @staticmethod
    def attach_assistant_message(
        message: ChatMessage,
        topic: TopicSession,
        *,
        token_input: int | None,
        token_output: int | None,
    ) -> None:
        message.topic_session_id = topic.id
        topic.message_count += 1
        topic.token_input += int(token_input or 0)
        topic.token_output += int(token_output or 0)

    @staticmethod
    def topic_dict(topic: TopicSession) -> dict:
        return {
            "id": topic.id,
            "userId": topic.user_id,
            "chatSessionId": topic.chat_session_id,
            "title": topic.title,
            "coreQuestion": topic.core_question,
            "status": topic.status,
            "messageCount": topic.message_count,
            "tokenInput": topic.token_input,
            "tokenOutput": topic.token_output,
            "quotaDeducted": bool(topic.quota_deducted),
            "helpCardGenerated": bool(topic.help_card_generated),
            "shareDraftGenerated": bool(topic.share_draft_generated),
            "startedAt": topic.started_at,
            "endedAt": topic.ended_at,
            "updatedAt": topic.updated_at,
        }


def _now() -> datetime:
    return datetime.now(UTC).replace(tzinfo=None)


def _title_from_question(question: str) -> str:
    title = question.strip().replace("\n", " ")
    return title[:40] if title else "新主题"
