"""Turns one Telegram Bot API update into either an account-linking action or
Document/IntakeEvent rows — the actual business logic, separate from the
webhook route so it can be unit tested with a plain dict, no real bot needed.

Reuses app.processing.intake_common for the actual filing/ambiguity rules,
same as the email channel.
"""
from datetime import datetime

from app.extensions import db
from app.models import IntakeEvent, User
from app.processing.intake_common import file_attachments_for_user

NOT_LINKED_REPLY = (
    "No encontramos tu cuenta vinculada. Entra a Memodoc > Mi cuenta > "
    "Telegram para vincularla primero."
)
HELP_REPLY = (
    "Envíame una foto o un PDF de tu documento médico y lo guardo en tu historia. "
    "Escribe 'resumen' para ver tu último resumen."
)


def process_telegram_update(update: dict, download_file=None) -> str | None:
    """Returns the text to reply with, or None if there's nothing to reply to."""
    if download_file is None:
        from app.telegram.telegram_client import download_file as default_download_file
        download_file = default_download_file

    message = update.get("message")
    if not message:
        return None

    chat_id = str(message.get("chat", {}).get("id") or "")
    if not chat_id:
        return None

    text = (message.get("text") or "").strip()

    if text.startswith("/start"):
        return _handle_start(chat_id, text)

    user = User.query.filter_by(telegram_chat_id=chat_id).first()
    if user is None:
        return NOT_LINKED_REPLY

    attachment = _extract_attachment(message)
    if attachment is None:
        if text.lower() in ("resumen", "/resumen"):
            return _handle_summary_request(user)
        return HELP_REPLY

    filename, file_id = attachment
    content = download_file(file_id)
    events = file_attachments_for_user(
        user, [(filename, content)], channel="telegram",
        sender_identifier=chat_id, subject=message.get("caption"),
    )
    db.session.commit()
    return _reply_for_events(events)


def _extract_attachment(message: dict):
    if "document" in message:
        doc = message["document"]
        filename = doc.get("file_name") or f"documento_{message.get('message_id', '')}.pdf"
        return filename, doc["file_id"]

    if "photo" in message:
        photos = message["photo"]
        if not photos:
            return None
        largest = photos[-1]  # Telegram lists photo sizes smallest to largest
        filename = f"foto_{message.get('message_id', '')}.jpg"
        return filename, largest["file_id"]

    return None


def _handle_start(chat_id: str, text: str) -> str:
    parts = text.split(maxsplit=1)
    if len(parts) < 2 or not parts[1].strip():
        return "Envía /start seguido del código que ves en la web (Mi cuenta > Telegram)."

    code = parts[1].strip()
    user = User.query.filter_by(telegram_link_code=code).first()
    if (
        user is None
        or not user.telegram_link_code_expires_at
        or user.telegram_link_code_expires_at < datetime.utcnow()
    ):
        return "Ese código no es válido o ya expiró. Genera uno nuevo desde la web."

    user.telegram_chat_id = chat_id
    user.telegram_link_code = None
    user.telegram_link_code_expires_at = None
    db.session.commit()
    return "¡Listo! Tu cuenta de Memodoc quedó vinculada. Envíame una foto o un PDF cuando quieras."


def _handle_summary_request(user: User) -> str:
    patients = user.patients
    if not patients:
        return "Todavía no tienes ningún perfil creado. Entra a la web para crear el primero."

    if len(patients) > 1:
        names = ", ".join(p.full_name for p in patients)
        return f"Administras varios perfiles ({names}). Por ahora, entra a la web para ver el resumen de cada uno."

    summary = patients[0].latest_summary()
    if summary is None:
        return "Todavía no hay un resumen generado. Sube algún documento primero."
    return summary.content


def _reply_for_events(events: list[IntakeEvent]) -> str:
    if not events:
        return "No pude procesar ese archivo."

    status = events[0].status
    if status == IntakeEvent.STATUS_MATCHED:
        return f"Recibido ({len(events)} archivo(s)). Se procesará en los próximos minutos."
    if status == IntakeEvent.STATUS_AMBIGUOUS_PATIENT:
        return (
            "Administras varios perfiles, así que no sé a cuál asignar esto. "
            "Entra a la web (Mis perfiles > Documentos pendientes) para indicarlo."
        )
    return events[0].notes or "No pude procesar ese archivo."
