"""
Обработчики создания заявки.

Поток:
1. Нажатие "Создать заявку" → переход в waiting_description
2. Первое сообщение с текстом → сохранение описания, переход в collecting_attachments
3. Дополнительные сообщения → накопление вложений
4. Нажатие "Готово" → сохранение заявки в БД, подтверждение
"""
import asyncio

from maxapi.context import BaseContext
from maxapi.dispatcher import Router
from maxapi.enums.attachment import AttachmentType
from maxapi.filters import F
from maxapi.types.attachments.attachment import (
    OtherAttachmentPayload,
    PhotoAttachmentPayload,
)
from maxapi.types.updates.message_callback import MessageCallback
from maxapi.types.updates.message_created import MessageCreated

from bot.keyboards import done_ticket_kb, main_menu_kb
from bot.logging_setup import get_logger
from bot.send_helper import bot_send
from bot.states import TicketStates

logger = get_logger("bot.handlers.create_ticket")
from database.queries.ticket_attachments import add_attachment
from database.queries.tickets import create_ticket
import external.client as ext

router = Router(router_id="create_ticket")

_MEDIA_TYPES = {
    AttachmentType.IMAGE,
    AttachmentType.VIDEO,
    AttachmentType.AUDIO,
    AttachmentType.FILE,
}


def _extract_attachments(event: MessageCreated) -> list[dict]:
    """Извлекает метаданные вложений из сообщения."""
    result = []
    body = event.message.body
    if not body or not body.attachments:
        return result
    for att in body.attachments:
        att_type = getattr(att, "type", None)
        if att_type not in _MEDIA_TYPES:
            continue
        url = None
        payload = getattr(att, "payload", None)
        if isinstance(payload, (PhotoAttachmentPayload, OtherAttachmentPayload)):
            url = payload.url
        result.append({"type": str(att_type), "url": url})
    return result


@router.message_callback(F.callback.payload == "create_ticket")
async def cb_create_ticket(
    event: MessageCallback, context: BaseContext, bot_user: dict
) -> None:
    await context.set_state(TicketStates.waiting_description)
    await context.set_data({"pending_attachments": []})
    logger.info("📝 create_ticket started | user_id=%s", bot_user["max_user_id"])
    await event.answer(notification="")

    chat_id = event.message.recipient.chat_id if event.message else None
    if chat_id is None:
        return

    await bot_send(
        event.bot,
        chat_id=chat_id,
        user_id=bot_user["max_user_id"],
        text=(
            "📝 Опишите вашу проблему.\n\n"
            "Вы также можете прикрепить файлы, фото или голосовые сообщения.\n"
            "Когда закончите — нажмите кнопку «Готово»."
        ),
        attachments=[done_ticket_kb()],
    )


@router.message_created(states=TicketStates.waiting_description)
async def on_ticket_description(
    event: MessageCreated, context: BaseContext
) -> None:
    chat_id, user_id = event.get_ids()
    if chat_id is None:
        return

    body = event.message.body
    text = (body.text or "").strip() if body else ""
    attachments = _extract_attachments(event)

    await context.update_data(
        description=text,
        pending_attachments=attachments,
    )
    await context.set_state(TicketStates.collecting_attachments)

    await bot_send(
        event.bot,
        chat_id=chat_id,
        user_id=user_id,
        text=(
            "✏️ Описание принято. Вы можете добавить ещё файлы "
            "или нажмите «Готово» для отправки заявки."
        ),
        attachments=[done_ticket_kb()],
    )


@router.message_created(states=TicketStates.collecting_attachments)
async def on_ticket_attachment(
    event: MessageCreated, context: BaseContext
) -> None:
    data = await context.get_data()
    body = event.message.body
    extra_text = (body.text or "").strip() if body else ""
    new_atts = _extract_attachments(event)

    if extra_text:
        current = data.get("description", "")
        data["description"] = (current + "\n" + extra_text).strip()

    pending = data.get("pending_attachments", [])
    pending.extend(new_atts)
    data["pending_attachments"] = pending

    await context.set_data(data)


@router.message_callback(
    F.callback.payload == "done_ticket",
    states=[TicketStates.waiting_description, TicketStates.collecting_attachments],
)
async def cb_done_ticket(
    event: MessageCallback, context: BaseContext, bot_user: dict
) -> None:
    data = await context.get_data()
    description = (data.get("description") or "").strip()

    chat_id = event.message.recipient.chat_id if event.message else None
    if chat_id is None:
        return

    if not description:
        await event.answer(notification="Сначала опишите проблему!")
        await bot_send(
            event.bot,
            chat_id=chat_id,
            user_id=bot_user["max_user_id"],
            text="❗ Пожалуйста, сначала напишите описание проблемы.",
            attachments=[done_ticket_kb()],
        )
        return

    ticket_id = await create_ticket(
        org_id=bot_user["org_id"],
        created_by=bot_user["id"],
        description=description,
    )
    logger.info(
        "✅ ticket created | ticket_id=%s user_id=%s org_id=%s attachments=%s",
        ticket_id, bot_user["max_user_id"], bot_user["org_id"],
        len(data.get("pending_attachments", [])),
    )

    for att in data.get("pending_attachments", []):
        await add_attachment(
            ticket_id=ticket_id,
            attachment_type=att["type"],
            attachment_url=att.get("url"),
        )

    await context.clear()

    await event.answer(notification="Заявка создана!")
    await bot_send(
        event.bot,
        chat_id=chat_id,
        user_id=bot_user["max_user_id"],
        text=(
            f"✅ Заявка №{ticket_id} успешно создана!\n"
            "Наши специалисты свяжутся с вами в ближайшее время."
        ),
        attachments=[main_menu_kb()],
    )

    # Fire-and-forget: отправка во внешнюю систему
    async def _sync_external():
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(None, ext.sync_ticket, ticket_id)

    asyncio.create_task(_sync_external())
