import unicodedata

from fastapi import HTTPException

from app.core.config import Settings
from app.schemas.common import ResponseMode
from app.schemas.freshchat import (
    WorkflowHandleOptionRequest,
    WorkflowStartInteractiveRequest,
    WorkflowStartRequest,
)
from app.schemas.responses import ListRow, ListSection
from app.services.conversation_builder import (
    build_list_response,
    build_text_response,
    controlled_error,
    render_response,
)
from app.services.freshchat_client import (
    build_quick_reply_message_payload,
    build_text_message_payload,
    send_conversation_message,
)
from app.services.mbia_service import build_mbia_entry_response


MAIN_MENU_OPTIONS = [
    {"id": "emergencia_cobro", "title": "Emergencia de Cobro", "description": "Atencion urgente para cobros"},
    {"id": "soporte", "title": "Soporte", "description": "Ayuda con problemas del sistema"},
    {"id": "implementacion", "title": "Implementacion", "description": "Dudas sobre implementacion"},
    {"id": "ventas", "title": "Ventas", "description": "Informacion comercial"},
    {"id": "administracion", "title": "Administracion", "description": "Consultas administrativas"},
    {"id": "mbia", "title": "MBIA", "description": "Asistente conversacional MBIA"},
]

OPTION_RESPONSES = {
    "emergencia_cobro": (
        "Para poder apoyarte, necesitamos nos indiques:\n"
        "1. Tu nombre y empresa\n"
        "2. La tienda y caja en la que tienes el inconveniente\n"
        "3. Envianos foto, imagen o video del problema\n"
        "4. Descripcion del inconveniente\n"
        "5. Opcional: Numero de AnyDesk"
    ),
    "soporte": (
        "Para poder apoyarte, necesitamos nos indiques:\n"
        "1. Tu empresa\n"
        "2. Sistema que estas utilizando\n"
        "3. Opcion que estas utilizando\n"
        "4. Descripcion de lo que deseas podamos apoyarte\n"
        "5. Envianos foto o video\n"
        "6. Opcional: Numero de AnyDesk"
    ),
    "implementacion": (
        "Para poder apoyarte, necesitamos nos indiques:\n"
        "1. Tu nombre y empresa\n"
        "2. Descripcion de la duda que tienes"
    ),
    "ventas": (
        "Gracias por comunicarte a Ventas. Para atenderte de mejor manera, escribenos:\n"
        "1. Tu nombre\n"
        "2. Tu numero de telefono\n"
        "3. Tu correo electronico\n"
        "4. El nombre de tu empresa\n"
        "5. Tu tipo de industria"
    ),
    "administracion": (
        "Te has comunicado a Administracion. Por favor, envianos:\n"
        "1. Tu nombre y empresa\n"
        "2. NIT de tu empresa\n"
        "3. Descripcion de tu consulta"
    ),
}


def start_workflow(request: WorkflowStartRequest, mode: ResponseMode) -> dict:
    internal_response = build_main_menu_response()
    if not request.supports_interactive:
        return render_response(internal_response, "fallback")
    return render_response(internal_response, mode)


def start_workflow_interactive(
    request: WorkflowStartInteractiveRequest,
    settings: Settings,
) -> dict:
    conversation_id = _resolve_conversation_id(request)
    if not conversation_id:
        return controlled_error(
            "No se recibio conversation_id. Configura el body con el placeholder de conversacion correcto.",
            {
                "expected_fields": [
                    "conversation_id",
                    "conversationAlias",
                    "conversation_alias",
                    "conversationId",
                ],
                "hint": "En los logs de Freshworks normalmente aparece como conversationAlias.",
            },
        )

    internal_response = build_main_menu_response()
    rendered = render_response(internal_response, "freshchat_simple")
    message = internal_response["data"]["messages"][0]
    fallback_text = message.get("fallback_text") or rendered.get("send_message") or message["text"]
    options = [
        {
            "id": row["id"],
            "title": row["title"],
        }
        for section in message.get("sections", [])
        for row in section.get("rows", [])
    ]

    actor_type = request.actor_type or settings.freshworks_default_actor_type
    actor_id = request.actor_id or settings.freshworks_default_actor_id

    interactive_payload = build_quick_reply_message_payload(
        text=message["text"],
        options=options,
        actor_type=actor_type,
        actor_id=actor_id,
        user_id=request.user_id,
    )

    sent_payload = interactive_payload
    sent_as = "interactive"
    interactive_error = None

    try:
        freshchat_response = send_conversation_message(settings, conversation_id, interactive_payload)
    except HTTPException as exc:
        interactive_error = exc.detail
        fallback_payload = build_text_message_payload(
            text=fallback_text,
            actor_type=actor_type,
            actor_id=actor_id,
            user_id=request.user_id,
        )
        freshchat_response = send_conversation_message(settings, conversation_id, fallback_payload)
        sent_payload = fallback_payload
        sent_as = "fallback_text"

    return {
        **rendered,
        "mensaje": "Menu interactivo enviado." if sent_as == "interactive" else "Fallback de texto enviado.",
        "data": {
            **rendered.get("data", {}),
            "conversation_id": conversation_id,
            "freshchat_message": freshchat_response,
            "sent_payload": sent_payload,
            "sent_as": sent_as,
            "interactive_error": interactive_error,
        },
        "sent": True,
    }


def _resolve_conversation_id(request: WorkflowStartInteractiveRequest) -> str | None:
    candidates = [
        request.conversation_id,
        request.conversationAlias,
        request.conversation_alias,
        request.conversationId,
    ]
    for candidate in candidates:
        if candidate and "{{" not in candidate and "}}" not in candidate:
            return candidate.strip()
    return None


def handle_option(request: WorkflowHandleOptionRequest, mode: ResponseMode) -> dict:
    option_id = normalize_option(request.selected_option_id or request.selected_option)

    if option_id == "mbia":
        internal_response = build_mbia_entry_response()
        return render_response(internal_response, "fallback" if not request.supports_interactive else mode)

    message = OPTION_RESPONSES.get(option_id)
    if not message:
        return controlled_error("No fue posible identificar la opcion seleccionada. Por favor intenta nuevamente.")

    return build_text_response(message)


def build_main_menu_response() -> dict:
    menu_text = (
        "Hola, soy MBBot y estoy para servirte. Por favor escoge una de las siguientes "
        "opciones para poder comunicarte al area que necesitas."
    )
    fallback_text = (
        "Por favor responde con una de estas opciones:\n"
        "1. Emergencia de Cobro\n"
        "2. Soporte\n"
        "3. Implementacion\n"
        "4. Ventas\n"
        "5. Administracion\n"
        "6. MBIA"
    )
    rows = [
        ListRow(id=option["id"], title=option["title"], description=option["description"])
        for option in MAIN_MENU_OPTIONS
    ]
    return build_list_response(
        mensaje="Selecciona una opcion",
        text=menu_text,
        button_text="Ver opciones",
        sections=[ListSection(title="Areas disponibles", rows=rows)],
        fallback_text=fallback_text,
    )


def normalize_option(value: str | None) -> str:
    if not value:
        return ""
    normalized = unicodedata.normalize("NFKD", value)
    normalized = "".join(char for char in normalized if not unicodedata.combining(char))
    normalized = normalized.lower().strip()
    normalized = normalized.replace("-", " ").replace("_", " ")
    normalized = normalized.replace(".", " ")
    normalized = " ".join(normalized.split())

    aliases = {
        "1": "emergencia_cobro",
        "opcion 1": "emergencia_cobro",
        "emergencia cobro": "emergencia_cobro",
        "emergencia de cobro": "emergencia_cobro",
        "cobro": "emergencia_cobro",
        "2": "soporte",
        "opcion 2": "soporte",
        "soporte": "soporte",
        "3": "implementacion",
        "opcion 3": "implementacion",
        "implementacion": "implementacion",
        "4": "ventas",
        "opcion 4": "ventas",
        "ventas": "ventas",
        "5": "administracion",
        "opcion 5": "administracion",
        "administracion": "administracion",
        "6": "mbia",
        "opcion 6": "mbia",
        "mbia": "mbia",
    }
    return aliases.get(normalized, normalized.replace(" ", "_"))
