import logging
import datetime
from typing import Optional
from sqlalchemy import select
from app.database import async_session
from app.models import BotUser, BotConversation, BotMessage, BotKnowledgeBase, BotCategory
from app.max_api import max_api
from app.yandex_gpt import yandex_gpt
from app.config_reader import config_reader
from app.settings_cache import settings_cache
from app.keyboards import consent_keyboard, return_to_consent_keyboard

logger = logging.getLogger(__name__)


async def handle_greeting(
    user_id: int,
    text: Optional[str] = None,
    first_name: str = "",
    last_name: str = "",
    username: str = "",
) -> None:
    assistant_name = await settings_cache.get("assistant_name", "София")

    greeting_text = (
        f"Здравствуйте! Я {assistant_name}, помощник AegisOne Engineering. "
        f"Чем я могу быть вам полезна?"
    )

    await max_api.send_message(user_id, greeting_text)

    async with async_session() as db:
        existing = await db.execute(
            select(BotUser).where(BotUser.id == user_id)
        )
        user = existing.scalar_one_or_none()

        now = datetime.datetime.utcnow()
        if not user:
            user = BotUser(
                id=user_id,
                first_name=first_name,
                last_name=last_name,
                username=username,
                last_interaction=now,
                total_conversations=1,
                created_at=now,
            )
            db.add(user)
        else:
            if first_name:
                user.first_name = first_name
            if last_name:
                user.last_name = last_name
            if username:
                user.username = username
            user.last_interaction = now
            user.total_conversations = (user.total_conversations or 0) + 1

        await db.commit()
        await db.refresh(user)

        conv = BotConversation(
            user_id=user_id,
            state="analyzing",
            created_at=now,
        )
        db.add(conv)
        await db.commit()
        await db.refresh(conv)

    if text:
        await analyze_and_respond(user_id, conv.id, text)
    else:
        async with async_session() as db:
            conv.state = "awaiting_input"
            await db.commit()


async def handle_message(user_id: int, text: str) -> None:
    async with async_session() as db:
        result = await db.execute(
            select(BotConversation)
            .where(BotConversation.user_id == user_id)
            .order_by(BotConversation.id.desc())
            .limit(1)
        )
        conv = result.scalar_one_or_none()

        if not conv:
            await handle_greeting(user_id, text)
            return

        msg = BotMessage(
            conversation_id=conv.id,
            direction="incoming",
            text=text,
            created_at=datetime.datetime.utcnow(),
        )
        db.add(msg)
        await db.commit()

    state = conv.state if conv else "greeting"

    if state in ("greeting", "analyzing", "awaiting_input"):
        await analyze_and_respond(user_id, conv.id, text)
    elif state == "awaiting_consent":
        from app.handlers.consent import handle_consent_response
        await handle_consent_response(user_id, conv.id, text)
    elif state == "consent_refused":
        from app.handlers.consent import handle_refused_again
        await handle_refused_again(user_id, conv.id, text)
    elif state == "awaiting_contact":
        from app.handlers.contact import handle_manual_contact
        await handle_manual_contact(user_id, conv.id, text)
    elif state == "awaiting_inquiry":
        from app.handlers.inquiry import handle_inquiry
        await handle_inquiry(user_id, conv.id, text)
    elif state in ("completed", "escalated"):
        await max_api.send_message(
            user_id,
            "Ваше обращение уже передано специалисту. "
            "Если у вас новый вопрос, напишите его, и я помогу.",
        )


async def _get_user_history_context(user_id: int) -> str:
    from app.models import BotTicket
    async with async_session() as db:
        recent_msgs = await db.execute(
            select(BotMessage)
            .join(BotConversation)
            .where(BotConversation.user_id == user_id)
            .order_by(BotMessage.id.desc())
            .limit(10)
        )
        messages = list(reversed(recent_msgs.scalars().all()))

        open_tickets = await db.execute(
            select(BotTicket)
            .where(BotTicket.user_id == user_id)
            .where(BotTicket.status != "Закрыта")
            .order_by(BotTicket.id.desc())
        )
        tickets = open_tickets.scalars().all()

    parts = []
    if messages:
        msg_lines = []
        for m in messages:
            who = "Клиент" if m.direction == "incoming" else "Бот"
            msg_lines.append(f"{who}: {m.text or ''}")
        parts.append("Последние сообщения из прошлых диалогов:\n" + "\n".join(msg_lines))

    if tickets:
        ticket_lines = []
        for t in tickets:
            ticket_lines.append(f"  - Заявка #{t.id}: {t.title} (статус: {t.status})")
        parts.append("Открытые заявки пользователя:\n" + "\n".join(ticket_lines))

    return "\n\n".join(parts)


async def analyze_and_respond(user_id: int, conv_id: int, text: str) -> None:
    gpt_available = await yandex_gpt.is_available()

    if not gpt_available:
        await _limited_mode(user_id, conv_id)
        return

    history_context = await _get_user_history_context(user_id)
    intent = await yandex_gpt.analyze_intent(text, history_context)

    async with async_session() as db:
        result = await db.execute(
            select(BotConversation).where(BotConversation.id == conv_id)
        )
        conv = result.scalar_one_or_none()
        if not conv:
            return
        conv.intent = intent

        if intent == "question":
            kb_context = await _get_knowledge_base_context(text)
            answer = await yandex_gpt.generate_answer(text, kb_context, history_context)
            if answer:
                await max_api.send_message(user_id, answer)
            else:
                await _send_contacts(user_id)
            conv.state = "completed"

        elif intent == "ticket":
            conv.state = "awaiting_consent"
            consent_text = (
                "Для обработки Вашего запроса нам нужны ваши контактные данные "
                "для обратной связи. Даёте согласие на обработку "
                "персональных данных?"
            )
            await max_api.send_message(
                user_id, consent_text, attachments=consent_keyboard()
            )

        else:
            clarification = await yandex_gpt.clarify_intent(text, history_context)
            await max_api.send_message(user_id, clarification)
            conv.state = "awaiting_consent"
            after_text = (
                "\n\nДля обработки Вашего запроса нам нужны ваши контактные данные "
                "для обратной связи. Даёте согласие на обработку "
                "персональных данных?"
            )
            await max_api.send_message(
                user_id, after_text, attachments=consent_keyboard()
            )

        await db.commit()


async def _limited_mode(user_id: int, conv_id: int) -> None:
    async with async_session() as db:
        result = await db.execute(
            select(BotConversation).where(BotConversation.id == conv_id)
        )
        conv = result.scalar_one_or_none()
        if conv:
            conv.state = "completed"
            await db.commit()

    await _send_contacts(user_id)


async def _send_contacts(user_id: int) -> None:
    phones = config_reader.get_phones()
    email = config_reader.get_site_mail()

    phone_text = "\n".join(
        f"📞 {phone} — [позвонить](tel:{link})"
        for phone, link in phones
    )

    message = (
        "Вы можете связаться с нами:\n\n"
        f"{phone_text}\n"
        f"📧 [Написать на почту](mailto:{email})\n\n"
        f"Или написать на почту: {email}"
    )

    await max_api.send_message(user_id, message, format="markdown")


async def _get_knowledge_base_context(query: str) -> str:
    async with async_session() as db:
        result = await db.execute(
            select(BotKnowledgeBase)
            .where(BotKnowledgeBase.is_active == True)
            .order_by(BotKnowledgeBase.sort_order)
        )
        cards = result.scalars().all()

    if not cards:
        return ""

    parts = []
    for card in cards:
        keywords = " ".join(card.keywords) if card.keywords else ""
        answer = card.answer or "Нет ответа"
        cat_name = card.category.name if card.category else "Общее"
        parts.append(f"[{cat_name}] {card.question}: {answer} (ключевые слова: {keywords})")

    return "\n\n".join(parts[:20])
