from __future__ import annotations

import time

from asgiref.sync import sync_to_async

from core.clients import transport
from core.models import ChatSession, Message

STATUS_VISIBLE_SOURCE_SERVICES = {"web", "xmpp", "signal", "whatsapp"}


def chunk_for_transport(text: str, limit: int = 3000) -> list[str]:
    body = str(text or "").strip()
    if not body:
        return []
    if len(body) <= limit:
        return [body]
    parts = []
    remaining = body
    while len(remaining) > limit:
        cut = remaining.rfind("\n\n", 0, limit)
        if cut < int(limit * 0.45):
            cut = remaining.rfind("\n", 0, limit)
        if cut < int(limit * 0.35):
            cut = limit
        parts.append(remaining[:cut].rstrip())
        remaining = remaining[cut:].lstrip()
    if remaining:
        parts.append(remaining)
    return [part for part in parts if part]


async def post_status_in_source(
    trigger_message: Message, text: str, origin_tag: str
) -> bool:
    service = str(trigger_message.source_service or "").strip().lower()
    if service not in STATUS_VISIBLE_SOURCE_SERVICES:
        return False
    if service == "web":
        await sync_to_async(Message.objects.create)(
            user=trigger_message.user,
            session=trigger_message.session,
            sender_uuid="",
            text=text,
            ts=int(time.time() * 1000),
            custom_author="BOT",
            source_service="web",
            source_chat_id=trigger_message.source_chat_id or "",
            message_meta={"origin_tag": origin_tag},
        )
        return True
    # For non-web, route through transport raw API.
    if not str(trigger_message.source_chat_id or "").strip():
        return False
    try:
        await transport.send_message_raw(
            service,
            str(trigger_message.source_chat_id or "").strip(),
            text=text,
            attachments=[],
            metadata={"origin_tag": origin_tag},
        )
        return True
    except Exception:
        return False


async def post_to_channel_binding(
    trigger_message: Message,
    binding_service: str,
    binding_channel_identifier: str,
    text: str,
    origin_tag: str,
    command_slug: str,
) -> bool:
    service = str(binding_service or "").strip().lower()
    channel_identifier = str(binding_channel_identifier or "").strip()
    if service == "web":
        session = None
        if (
            channel_identifier
            and channel_identifier == str(trigger_message.source_chat_id or "").strip()
        ):
            session = trigger_message.session
        if session is None and channel_identifier:
            session = await sync_to_async(
                lambda: ChatSession.objects.filter(
                    user=trigger_message.user,
                    identifier__identifier=channel_identifier,
                )
                .order_by("-last_interaction")
                .first()
            )()
        if session is None:
            session = trigger_message.session
        await sync_to_async(Message.objects.create)(
            user=trigger_message.user,
            session=session,
            sender_uuid="",
            text=text,
            ts=int(time.time() * 1000),
            custom_author="BOT",
            source_service="web",
            source_chat_id=channel_identifier
            or str(trigger_message.source_chat_id or ""),
            message_meta={"origin_tag": origin_tag},
        )
        return True
    try:
        chunks = chunk_for_transport(text, limit=3000)
        if not chunks:
            return False
        for chunk in chunks:
            ts = await transport.send_message_raw(
                service,
                channel_identifier,
                text=chunk,
                attachments=[],
                metadata={
                    "origin_tag": origin_tag,
                    "command_slug": command_slug,
                },
            )
            if not ts:
                return False
        return True
    except Exception:
        return False
