from typing import Any

from app.schemas.common import ResponseMode
from app.schemas.responses import (
    ButtonOption,
    ConversationResponse,
    ListRow,
    ListSection,
)


def success_response(mensaje: str, response_type: str, data: dict[str, Any]) -> dict[str, Any]:
    return ConversationResponse(
        error="false",
        mensaje=mensaje,
        response_type=response_type,  # type: ignore[arg-type]
        data=data,
    ).model_dump(exclude_none=True)


def controlled_error(mensaje: str, data: dict[str, Any] | None = None) -> dict[str, Any]:
    return {
        "error": "true",
        "mensaje": mensaje,
        "response_type": "text",
        "data": data or {},
    }


def build_text_response(text: str, extra_data: dict[str, Any] | None = None) -> dict[str, Any]:
    data: dict[str, Any] = {"messages": [{"type": "text", "text": text}]}
    if extra_data:
        data.update(extra_data)
    return success_response(text, "text", data)


def build_buttons_response(
    mensaje: str,
    text: str,
    buttons: list[ButtonOption],
    fallback_text: str,
) -> dict[str, Any]:
    return success_response(
        mensaje=mensaje,
        response_type="buttons",
        data={
            "messages": [
                {
                    "type": "buttons",
                    "text": text,
                    "buttons": [button.model_dump() for button in buttons],
                    "fallback_text": fallback_text,
                }
            ]
        },
    )


def build_quick_replies_response(
    mensaje: str,
    text: str,
    replies: list[ButtonOption],
    fallback_text: str,
) -> dict[str, Any]:
    return success_response(
        mensaje=mensaje,
        response_type="quick_replies",
        data={
            "messages": [
                {
                    "type": "quick_replies",
                    "text": text,
                    "quick_replies": [reply.model_dump() for reply in replies],
                    "fallback_text": fallback_text,
                }
            ]
        },
    )


def build_list_response(
    mensaje: str,
    text: str,
    button_text: str,
    sections: list[ListSection],
    fallback_text: str,
) -> dict[str, Any]:
    return success_response(
        mensaje=mensaje,
        response_type="list",
        data={
            "messages": [
                {
                    "type": "list",
                    "text": text,
                    "button_text": button_text,
                    "sections": [section.model_dump(exclude_none=True) for section in sections],
                    "fallback_text": fallback_text,
                }
            ]
        },
    )


def build_rating_response(
    mensaje: str,
    text: str,
    fallback_text: str,
    scale_min: int = 1,
    scale_max: int = 5,
    labels: dict[str, str] | None = None,
) -> dict[str, Any]:
    return success_response(
        mensaje=mensaje,
        response_type="rating",
        data={
            "messages": [
                {
                    "type": "rating",
                    "text": text,
                    "scale_min": scale_min,
                    "scale_max": scale_max,
                    "labels": labels or {},
                    "fallback_text": fallback_text,
                }
            ]
        },
    )


def render_response(payload: dict[str, Any], mode: ResponseMode) -> dict[str, Any]:
    if mode == "internal":
        return ensure_base_shape(payload)
    if mode == "freshchat_simple":
        return to_freshchat_simple(payload)
    if mode == "fallback":
        return to_fallback(payload)
    return controlled_error("Modo de renderizado no soportado.")


def ensure_base_shape(payload: dict[str, Any]) -> dict[str, Any]:
    return {
        "error": str(payload.get("error", "false")).lower(),
        "mensaje": payload.get("mensaje") or _extract_primary_text(payload),
        "response_type": payload.get("response_type") or "text",
        "data": payload.get("data") or {},
    }


def to_freshchat_simple(payload: dict[str, Any]) -> dict[str, Any]:
    response = ensure_base_shape(payload)
    messages = response.get("data", {}).get("messages", [])
    first_message = messages[0] if messages else {}
    options = _extract_options(first_message)
    fallback_text = first_message.get("fallback_text")
    question_text = first_message.get("text") or response["mensaje"]

    simple: dict[str, Any] = {
        "error": response["error"],
        "mensaje": response["mensaje"],
        "response_type": response["response_type"],
        "data": response["data"],
        "send_message": _build_send_message(question_text, options, fallback_text),
        "question_text": question_text,
        "options_text": _build_options_text(options),
        "options_csv": ", ".join(option.get("title", "") for option in options if option.get("title")),
        "option_ids_csv": ", ".join(option.get("id", "") for option in options if option.get("id")),
        "option_count": len(options),
        "supports_native_interactive": bool(options),
        "freshchat_api_library_renders_interactive": False,
        "integration_note": (
            "API Library guarda variables; para botones nativos usa acciones nativas de Freshchat "
            "o envia el payload whatsapp_interactive desde una integracion directa."
        ),
    }

    message_type = first_message.get("type")
    if message_type:
        simple["message_type"] = message_type
        simple["native_component_type"] = message_type

    if fallback_text:
        simple["fallback_text"] = fallback_text

    whatsapp_interactive = _build_whatsapp_interactive(first_message, options)
    if whatsapp_interactive:
        simple["whatsapp_interactive"] = whatsapp_interactive

    for index, option in enumerate(options, start=1):
        simple[f"option_{index}"] = option.get("title")
        simple[f"option_{index}_id"] = option.get("id")
        if option.get("description"):
            simple[f"option_{index}_description"] = option.get("description")

    return simple


def to_fallback(payload: dict[str, Any]) -> dict[str, Any]:
    response = ensure_base_shape(payload)
    fallback_text = _extract_fallback_text(response) or response["mensaje"]
    return build_text_response(fallback_text)


def _extract_primary_text(payload: dict[str, Any]) -> str:
    messages = payload.get("data", {}).get("messages", [])
    if messages:
        return messages[0].get("text") or "Respuesta generada."
    return "Respuesta generada."


def _extract_fallback_text(payload: dict[str, Any]) -> str | None:
    messages = payload.get("data", {}).get("messages", [])
    if not messages:
        return None
    return messages[0].get("fallback_text") or messages[0].get("text")


def _extract_options(message: dict[str, Any]) -> list[dict[str, Any]]:
    if message.get("type") == "buttons":
        return message.get("buttons", [])
    if message.get("type") == "quick_replies":
        return message.get("quick_replies", [])
    if message.get("type") == "list":
        options: list[dict[str, Any]] = []
        for section in message.get("sections", []):
            options.extend(section.get("rows", []))
        return options
    if message.get("type") == "rating":
        scale_min = int(message.get("scale_min", 1))
        scale_max = int(message.get("scale_max", 5))
        return [{"id": str(value), "title": str(value)} for value in range(scale_min, scale_max + 1)]
    return []


def _build_send_message(
    question_text: str,
    options: list[dict[str, Any]],
    fallback_text: str | None,
) -> str:
    if not options:
        return question_text
    if fallback_text:
        return f"{question_text}\n\n{fallback_text}"
    return f"{question_text}\n\n{_build_options_text(options)}"


def _build_options_text(options: list[dict[str, Any]]) -> str:
    if not options:
        return ""
    lines = []
    for index, option in enumerate(options, start=1):
        title = option.get("title") or option.get("id") or f"Opcion {index}"
        lines.append(f"{index}. {title}")
    return "\n".join(lines)


def _build_whatsapp_interactive(
    message: dict[str, Any],
    options: list[dict[str, Any]],
) -> dict[str, Any] | None:
    message_type = message.get("type")
    text = message.get("text") or "Selecciona una opcion"

    if message_type == "list":
        sections = []
        for section in message.get("sections", []):
            rows = [
                {
                    "id": row.get("id"),
                    "title": row.get("title"),
                    **({"description": row.get("description")} if row.get("description") else {}),
                }
                for row in section.get("rows", [])
            ]
            sections.append({"title": section.get("title", "Opciones"), "rows": rows})

        return {
            "type": "interactive",
            "interactive": {
                "type": "list",
                "body": {"text": text},
                "action": {
                    "button": message.get("button_text", "Ver opciones"),
                    "sections": sections,
                },
            },
        }

    if message_type in {"buttons", "quick_replies"} and options:
        if len(options) > 3:
            return {
                "type": "interactive",
                "interactive": {
                    "type": "list",
                    "body": {"text": text},
                    "action": {
                        "button": "Ver opciones",
                        "sections": [
                            {
                                "title": "Opciones",
                                "rows": [
                                    {
                                        "id": option.get("id"),
                                        "title": option.get("title"),
                                        **(
                                            {"description": option.get("description")}
                                            if option.get("description")
                                            else {}
                                        ),
                                    }
                                    for option in options
                                ],
                            }
                        ],
                    },
                },
            }

        return {
            "type": "interactive",
            "interactive": {
                "type": "button",
                "body": {"text": text},
                "action": {
                    "buttons": [
                        {
                            "type": "reply",
                            "reply": {
                                "id": option.get("id"),
                                "title": option.get("title"),
                            },
                        }
                        for option in options
                    ]
                },
            },
        }

    if message_type == "rating" and options:
        return {
            "type": "interactive",
            "interactive": {
                "type": "list",
                "body": {"text": text},
                "action": {
                    "button": "Calificar",
                    "sections": [
                        {
                            "title": "Calificacion",
                            "rows": [
                                {"id": option.get("id"), "title": option.get("title")}
                                for option in options
                            ],
                        }
                    ],
                },
            },
        }

    return None
