import logging
from typing import Any

from app.core.config import Settings
from app.schemas.freshchat import WorkflowHandleOptionRequest, WorkflowStartInteractiveRequest
from app.services.conversation_builder import controlled_error
from app.services.event_store import (
    is_event_processed,
    mark_event_processed,
    mark_menu_sent,
    set_last_option,
    was_menu_sent,
)
from app.services.freshchat_client import (
    build_text_message_payload,
    send_conversation_message,
)
from app.services.workflow_service import handle_option, normalize_option, start_workflow_interactive

logger = logging.getLogger(__name__)


def handle_conversation_created_event(payload: dict[str, Any], settings: Settings) -> dict[str, Any]:
    context = extract_event_context(payload)
    if not context["conversation_id"]:
        return controlled_error("El evento no incluye conversation_id.", {"context": context})
    if not _is_user_event(context):
        return _ignored("Evento ignorado porque no fue originado por usuario.", context)

    event_key = _event_key(context, "conversation")
    if is_event_processed(settings, event_key):
        return _ignored("Evento duplicado ignorado.", context)

    mark_event_processed(settings, event_key)

    if was_menu_sent(settings, context["conversation_id"]):
        return _ignored("El menu ya fue enviado para esta conversacion.", context)

    response = start_workflow_interactive(
        WorkflowStartInteractiveRequest(
            cliente=context["user_id"] or context["actor_id"] or "",
            conversation_id=context["conversation_id"],
            user_id=context["user_id"] or context["actor_id"],
            canal="whatsapp",
            supports_interactive=True,
        ),
        settings,
    )
    if response.get("error") == "false":
        mark_menu_sent(settings, context["conversation_id"])
    return response


def handle_message_created_event(payload: dict[str, Any], settings: Settings) -> dict[str, Any]:
    context = extract_event_context(payload)
    if not context["conversation_id"]:
        return controlled_error("El evento no incluye conversation_id.", {"context": context})
    if not _is_user_event(context):
        return _ignored("Evento ignorado porque fue originado por bot/agente/sistema.", context)

    event_key = _event_key(context, "message")
    if is_event_processed(settings, event_key):
        return _ignored("Mensaje duplicado ignorado.", context)

    mark_event_processed(settings, event_key)

    selected_option = normalize_option(context["message_text"] or context["reply_payload"])
    if selected_option:
        option_response = handle_option(
            WorkflowHandleOptionRequest(
                cliente=context["user_id"] or context["actor_id"] or "",
                selected_option=selected_option,
                selected_option_id=selected_option,
                canal="whatsapp",
                supports_interactive=True,
            ),
            settings.default_response_mode,
        )
        if option_response.get("error") == "false" and option_response.get("response_type") == "text":
            text = option_response["mensaje"]
            payload_to_send = build_text_message_payload(
                text=text,
                actor_type=settings.freshworks_default_actor_type,
                actor_id=settings.freshworks_default_actor_id,
                user_id=context["user_id"] or context["actor_id"],
            )
            freshchat_response = send_conversation_message(
                settings,
                context["conversation_id"],
                payload_to_send,
            )
            set_last_option(settings, context["conversation_id"], selected_option)
            return {
                **option_response,
                "sent": True,
                "data": {
                    **option_response.get("data", {}),
                    "context": context,
                    "freshchat_message": freshchat_response,
                },
            }

    if not was_menu_sent(settings, context["conversation_id"]):
        response = start_workflow_interactive(
            WorkflowStartInteractiveRequest(
                cliente=context["user_id"] or context["actor_id"] or "",
                conversation_id=context["conversation_id"],
                user_id=context["user_id"] or context["actor_id"],
                canal="whatsapp",
                supports_interactive=True,
            ),
            settings,
        )
        if response.get("error") == "false":
            mark_menu_sent(settings, context["conversation_id"])
        return response

    return _ignored("Mensaje de usuario recibido sin opcion reconocida.", context)


def extract_event_context(payload: dict[str, Any]) -> dict[str, Any]:
    data = payload.get("data") or {}
    actor = data.get("actor") or payload.get("actor") or {}
    conversation = data.get("conversation") or payload.get("conversation") or {}
    message = data.get("message") or payload.get("message") or {}

    if not message and isinstance(conversation.get("messages"), list) and conversation["messages"]:
        message = conversation["messages"][-1]

    associations = data.get("associations") or {}
    associated_user = associations.get("user") or {}

    conversation_id = (
        conversation.get("conversation_id")
        or message.get("conversation_id")
        or payload.get("conversationAlias")
        or payload.get("conversation_id")
        or payload.get("conversationId")
    )
    user_id = conversation.get("user_id") or associated_user.get("id") or payload.get("user_id")
    actor_id = actor.get("id") or message.get("actor_id")
    actor_type = actor.get("type") or message.get("actor_type")
    message_id = (
        message.get("id")
        or payload.get("messageAlias")
        or payload.get("message_id")
        or payload.get("messageId")
    )

    return {
        "event": payload.get("event"),
        "conversation_id": conversation_id,
        "user_id": user_id,
        "actor_id": actor_id,
        "actor_type": actor_type,
        "message_id": message_id,
        "message_text": _extract_message_text(message),
        "reply_payload": _extract_reply_payload(message),
    }


def _extract_message_text(message: dict[str, Any]) -> str:
    parts = message.get("message_parts") or []
    for part in parts:
        text = part.get("text") or {}
        content = text.get("content")
        if content:
            return str(content).strip()
        quick_reply = part.get("quick_reply_button") or {}
        custom_reply_text = quick_reply.get("custom_reply_text") or quick_reply.get("label")
        if custom_reply_text:
            return str(custom_reply_text).strip()

    content = message.get("content") or message.get("text")
    return str(content).strip() if content else ""


def _extract_reply_payload(message: dict[str, Any]) -> str:
    parts = (message.get("reply_parts") or []) + (message.get("message_parts") or [])
    for part in parts:
        quick_reply = part.get("quick_reply_button") or {}
        payload = quick_reply.get("payload") or quick_reply.get("custom_reply_text")
        if payload:
            return str(payload).strip()
        callback = part.get("callback") or {}
        callback_payload = callback.get("payload") or callback.get("label")
        if callback_payload:
            return str(callback_payload).strip()
    return ""


def _event_key(context: dict[str, Any], fallback_prefix: str) -> str:
    if context.get("message_id"):
        return f"message:{context['message_id']}"
    if context.get("event") and context.get("conversation_id"):
        return f"{context['event']}:{context['conversation_id']}"
    return f"{fallback_prefix}:{context.get('conversation_id')}:{context.get('actor_id')}"


def _is_user_event(context: dict[str, Any]) -> bool:
    return (context.get("actor_type") or "").lower() == "user"


def _ignored(reason: str, context: dict[str, Any]) -> dict[str, Any]:
    logger.info("%s context=%s", reason, context)
    return {
        "error": "false",
        "mensaje": reason,
        "response_type": "text",
        "data": {"ignored": True, "context": context},
    }
