"""공통 봇 유틸리티 함수 모음.

gemini_bot.py, codex_bot.py 양쪽에서 공유하는 함수들을 여기에 정의합니다.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    from telegram import Update
    from telegram.ext import ContextTypes


def should_respond(update: "Update", bot_username: str, owner_user_id: int) -> bool:
    """이 봇이 해당 메시지에 응답해야 하는지 판단합니다.

    응답 조건:
      - 발신자가 자기 자신 봇(같은 username)이면 False (루프 방지)
      - 다른 봇의 메시지에는 멘션/리플라이 조건에 따라 응답 가능 (봇 간 토론 지원)
      - DM(private chat)이고 발신자가 OWNER_USER_ID이면 True
      - 그룹/슈퍼그룹:
          - 메시지 entities 중 @멘션이 이 봇 username과 일치하면 True
          - 리플라이 대상이 이 봇이면 True
      - 그 외 False
    """
    message = update.message
    if message is None:
        return False

    sender = message.from_user
    if sender is None:
        return False

    # 자기 자신이 보낸 메시지는 무시 (루프 방지)
    # 다른 봇의 메시지에는 응답 가능 (봇 간 토론 지원)
    if sender.is_bot and sender.username and sender.username.lower() == bot_username.lower():
        return False

    chat_type = message.chat.type  # "private", "group", "supergroup", "channel"

    # DM: 오너만 허용
    if chat_type == "private":
        return sender.id == owner_user_id

    # 그룹 / 슈퍼그룹
    if chat_type in ("group", "supergroup"):
        # 0) 오너 메시지는 무조건 응답
        if sender.id == owner_user_id:
            return True

        # 1) @멘션 체크
        entities = message.entities or []
        text = message.text or ""
        for entity in entities:
            if entity.type == "mention":
                mentioned = text[entity.offset : entity.offset + entity.length]
                # @username 형태 → 앞의 @ 제거 후 비교 (대소문자 무시)
                if mentioned.lstrip("@").lower() == bot_username.lower():
                    return True

        # 2) 리플라이 대상이 이 봇인지 체크
        reply_to = message.reply_to_message
        if reply_to and reply_to.from_user:
            if reply_to.from_user.username and (reply_to.from_user.username.lower() == bot_username.lower()):
                return True

    return False


def split_message(text: str, max_len: int = 4096) -> list[str]:
    """텍스트를 max_len 이하의 청크로 분할합니다.

    가능하면 줄바꿈('\\n') 기준으로 분할합니다.
    단일 줄이 max_len을 초과하는 경우에는 강제로 자릅니다.
    """
    if len(text) <= max_len:
        return [text]

    chunks: list[str] = []
    current_chunk = ""

    for line in text.splitlines(keepends=True):
        # 단일 줄이 max_len을 초과하는 경우: 강제 분할
        if len(line) > max_len:
            # 현재 버퍼를 먼저 비움
            if current_chunk:
                chunks.append(current_chunk)
                current_chunk = ""
            # 긴 줄을 max_len 단위로 강제 분할
            for i in range(0, len(line), max_len):
                chunks.append(line[i : i + max_len])
            continue

        if len(current_chunk) + len(line) > max_len:
            if current_chunk:
                chunks.append(current_chunk)
            current_chunk = line
        else:
            current_chunk += line

    if current_chunk:
        chunks.append(current_chunk)

    return chunks


async def send_response(
    update: "Update",
    context: "ContextTypes.DEFAULT_TYPE",
    text: str,
    max_len: int = 4096,
) -> None:
    """응답 텍스트를 분할하여 텔레그램으로 전송합니다."""
    message = update.message
    if message is None:
        return
    chunks = split_message(text, max_len)
    for chunk in chunks:
        await message.reply_text(chunk)


async def send_thinking_message(bot: Any, chat_id: int) -> int:
    """'🤔 생각 중...' 메시지를 보내고 message_id를 반환한다."""
    msg = await bot.send_message(chat_id=chat_id, text="🤔 생각 중...")
    return msg.message_id


async def replace_thinking_message(bot: Any, chat_id: int, message_id: int, text: str, max_len: int = 4096) -> None:
    """'생각 중...' 메시지를 실제 응답으로 교체한다.

    텍스트가 max_len 이하면 edit_message_text로 교체.
    초과하면 첫 청크는 edit_message_text, 나머지는 send_message.
    """
    chunks = split_message(text, max_len)
    await bot.edit_message_text(chat_id=chat_id, message_id=message_id, text=chunks[0])
    for chunk in chunks[1:]:
        await bot.send_message(chat_id=chat_id, text=chunk)
