import logging
from typing import Any

import httpx
from fastapi import HTTPException, status

from app.core.config import Settings
from app.services.exceptions import FreshchatAPIError

logger = logging.getLogger(__name__)


class FreshchatClient:
    def __init__(self, base_url: str, token: str, actor_type: str = "bot") -> None:
        self.base_url = base_url.rstrip("/")
        self.token = token
        self.actor_type = actor_type

    async def send_text_message(self, conversation_id: str, text: str) -> dict[str, Any]:
        url = f"{self.base_url}/conversations/{conversation_id}/messages"
        payload = {
            "message_parts": [
                {
                    "text": {
                        "content": text,
                    }
                }
            ],
            "message_type": "normal",
            "actor_type": self.actor_type,
        }
        headers = {
            "Authorization": f"Bearer {self.token}",
            "Content-Type": "application/json",
        }

        logger.info("Sending Freshchat text message conversation_id=%s actor_type=%s", conversation_id, self.actor_type)

        try:
            async with httpx.AsyncClient(timeout=10) as client:
                response = await client.post(url, headers=headers, json=payload)
        except httpx.HTTPError as exc:
            logger.exception("Freshchat API connection error while sending text message")
            raise FreshchatAPIError("No fue posible conectar con Freshchat Conversations API.") from exc

        if response.status_code < 200 or response.status_code >= 300:
            logger.error(
                "Freshchat API send message error status_code=%s response_body=%s",
                response.status_code,
                response.text[:1000],
            )
            raise FreshchatAPIError(
                "Freshchat Conversations API respondio con error.",
                status_code=response.status_code,
                response_body=response.text[:2000],
            )

        if not response.content:
            return {"status": "sent"}

        try:
            return response.json()
        except ValueError:
            return {"status": "sent", "raw_response": response.text}

    async def send_quick_reply_message(
        self,
        conversation_id: str,
        text: str,
        buttons: list[str],
        help_text: str = "Selecciona una opción",
        display_order_style: str = "snake",
    ) -> dict[str, Any]:
        clean_buttons = [button.strip() for button in buttons if button and button.strip()][:3]
        if not clean_buttons:
            raise FreshchatAPIError("Debe enviar al menos un boton para quick replies.")
        clean_help_text = help_text.strip() if help_text else "Selecciona una opción"
        if not clean_help_text:
            clean_help_text = "Selecciona una opción"
        order_key = "displayOrder" if display_order_style == "camel" else "display_order"

        url = f"{self.base_url}/conversations/{conversation_id}/messages"
        sub_parts = [
            {
                "help_text": {
                    "content": clean_help_text,
                }
            }
        ]
        sub_parts.extend(
            {
                "quick_reply_button": {
                    "label": button,
                    order_key: index,
                }
            }
            for index, button in enumerate(clean_buttons, start=1)
        )

        payload = {
            "message_parts": [
                {
                    "text": {
                        "content": text,
                    }
                }
            ],
            "reply_parts": [
                {
                    "collection": {
                        "sub_parts": sub_parts,
                    }
                }
            ],
            "message_type": "normal",
            "actor_type": self.actor_type,
        }
        headers = {
            "Authorization": f"Bearer {self.token}",
            "Content-Type": "application/json",
        }

        logger.info(
            "Sending Freshchat quick reply message conversation_id=%s actor_type=%s payload=%s",
            conversation_id,
            self.actor_type,
            payload,
        )

        try:
            async with httpx.AsyncClient(timeout=10) as client:
                response = await client.post(url, headers=headers, json=payload)
        except httpx.HTTPError as exc:
            logger.exception("Freshchat API connection error while sending quick replies")
            raise FreshchatAPIError("No fue posible conectar con Freshchat Conversations API.") from exc

        if response.status_code < 200 or response.status_code >= 300:
            logger.error(
                "Freshchat API quick replies error status_code=%s response_body=%s",
                response.status_code,
                response.text,
            )
            raise FreshchatAPIError(
                "Freshchat Conversations API respondio con error al enviar quick replies.",
                status_code=response.status_code,
                response_body=response.text,
            )

        if not response.content:
            return {"status": "sent"}

        try:
            return response.json()
        except ValueError:
            return {"status": "sent", "raw_response": response.text}

    async def send_dropdown_message(
        self,
        conversation_id: str,
        text: str,
        options: list[str],
        help_text: str = "Selecciona una opcion",
    ) -> dict[str, Any]:
        clean_options = [option.strip() for option in options if option and option.strip()]
        if not clean_options:
            raise FreshchatAPIError("Debe enviar al menos una opcion para el selector.")
        clean_help_text = help_text.strip() if help_text else "Selecciona una opcion"
        if not clean_help_text:
            clean_help_text = "Selecciona una opcion"

        url = f"{self.base_url}/conversations/{conversation_id}/messages"
        payload = {
            "message_parts": [
                {
                    "text": {
                        "content": text,
                    }
                }
            ],
            "reply_parts": [
                {
                    "template_content": {
                        "type": "quick_reply_dropdown",
                        "sections": [
                            {
                                "name": clean_help_text,
                                "parts": [
                                    {
                                        "quick_reply_button": {
                                            "label": option,
                                            "payload": option,
                                            "custom_reply_text": option,
                                            "display_order": index,
                                        }
                                    }
                                    for index, option in enumerate(clean_options, start=1)
                                ],
                            }
                        ],
                    }
                }
            ],
            "message_type": "normal",
            "actor_type": self.actor_type,
        }
        headers = {
            "Authorization": f"Bearer {self.token}",
            "Content-Type": "application/json",
        }

        logger.info(
            "Sending Freshchat dropdown message conversation_id=%s actor_type=%s payload=%s",
            conversation_id,
            self.actor_type,
            payload,
        )

        try:
            async with httpx.AsyncClient(timeout=10) as client:
                response = await client.post(url, headers=headers, json=payload)
        except httpx.HTTPError as exc:
            logger.exception("Freshchat API connection error while sending dropdown")
            raise FreshchatAPIError("No fue posible conectar con Freshchat Conversations API.") from exc

        if response.status_code < 200 or response.status_code >= 300:
            logger.error(
                "Freshchat API dropdown error status_code=%s response_body=%s",
                response.status_code,
                response.text,
            )
            raise FreshchatAPIError(
                "Freshchat Conversations API respondio con error al enviar selector.",
                status_code=response.status_code,
                response_body=response.text,
            )

        if not response.content:
            return {"status": "sent"}

        try:
            return response.json()
        except ValueError:
            return {"status": "sent", "raw_response": response.text}

    async def resolve_conversation(self, conversation_id: str) -> dict[str, Any]:
        url = f"{self.base_url}/conversations/{conversation_id}"
        payload = {"status": "resolved"}
        headers = {
            "Authorization": f"Bearer {self.token}",
            "Content-Type": "application/json",
        }

        logger.info("Resolving Freshchat conversation conversation_id=%s", conversation_id)

        try:
            async with httpx.AsyncClient(timeout=10) as client:
                response = await client.put(url, headers=headers, json=payload)
        except httpx.HTTPError as exc:
            logger.exception("Freshchat API connection error while resolving conversation")
            raise FreshchatAPIError("No fue posible conectar con Freshchat Conversations API.") from exc

        if response.status_code < 200 or response.status_code >= 300:
            logger.error(
                "Freshchat API resolve conversation error status_code=%s response_body=%s",
                response.status_code,
                response.text,
            )
            raise FreshchatAPIError(
                "Freshchat Conversations API respondio con error al cerrar la conversacion.",
                status_code=response.status_code,
                response_body=response.text,
            )

        if not response.content:
            return {"status": "resolved"}

        try:
            return response.json()
        except ValueError:
            return {"status": "resolved", "raw_response": response.text}


def build_quick_reply_message_payload(
    text: str,
    options: list[dict[str, Any]],
    actor_type: str,
    actor_id: str | None = None,
    user_id: str | None = None,
) -> dict[str, Any]:
    reply_parts = [_build_dropdown_reply_part(options)] if len(options) > 3 else [_build_buttons_reply_part(options)]
    payload: dict[str, Any] = {
        "message_type": "normal",
        "actor_type": actor_type,
        "message_parts": [{"text": {"content": text}}],
        "reply_parts": reply_parts,
    }

    if actor_id:
        payload["actor_id"] = actor_id
    if user_id:
        payload["user_id"] = user_id

    return payload


def _build_buttons_reply_part(options: list[dict[str, Any]]) -> dict[str, Any]:
    return {
        "collection": {
            "sub_parts": [
                {
                    "quick_reply_button": {
                        "label": option["title"],
                        "payload": option["id"],
                        "custom_reply_text": option["title"],
                        "display_order": str(index),
                    }
                }
                for index, option in enumerate(options, start=1)
            ]
        }
    }


def _build_dropdown_reply_part(options: list[dict[str, Any]]) -> dict[str, Any]:
    return {
        "template_content": {
            "type": "quick_reply_dropdown",
            "sections": [
                {
                    "name": "Opciones",
                    "parts": [
                        {
                            "quick_reply_button": {
                                "label": option["title"],
                                "payload": option["id"],
                                "custom_reply_text": option["title"],
                                "display_order": str(index),
                            }
                        }
                        for index, option in enumerate(options, start=1)
                    ],
                }
            ],
        }
    }


def build_text_message_payload(
    text: str,
    actor_type: str,
    actor_id: str | None = None,
    user_id: str | None = None,
) -> dict[str, Any]:
    payload: dict[str, Any] = {
        "message_type": "normal",
        "actor_type": actor_type,
        "message_parts": [{"text": {"content": text}}],
    }

    if actor_id:
        payload["actor_id"] = actor_id
    if user_id:
        payload["user_id"] = user_id

    return payload


def send_conversation_message(
    settings: Settings,
    conversation_id: str,
    payload: dict[str, Any],
) -> dict[str, Any]:
    if not settings.freshworks_api_base_url or not settings.freshworks_api_token:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=(
                "Faltan FRESHWORKS_API_BASE_URL o FRESHWORKS_API_TOKEN para enviar "
                "mensajes interactivos desde Freshchat API."
            ),
        )

    base_url = settings.freshworks_api_base_url.rstrip("/")
    url = f"{base_url}/v2/conversations/{conversation_id}/messages"

    headers = {
        "Authorization": f"Bearer {settings.freshworks_api_token}",
        "Content-Type": "application/json",
    }
    if settings.freshworks_assume_identity:
        headers["ASSUME-IDENTITY"] = "true"
    else:
        headers["ASSUME-IDENTITY"] = "false"

    logger.info("Sending Freshchat interactive message conversation_id=%s", conversation_id)

    try:
        with httpx.Client(timeout=20) as client:
            response = client.post(url, headers=headers, json=payload)
    except httpx.HTTPError as exc:
        logger.exception("Freshchat API connection error")
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail="No fue posible conectar con Freshchat Conversation API.",
        ) from exc

    if response.status_code >= 400:
        logger.error(
            "Freshchat API error status=%s body=%s",
            response.status_code,
            response.text[:500],
        )
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail=f"Freshchat Conversation API respondió con HTTP {response.status_code}.",
        )

    if not response.content:
        return {"status": "sent"}
    return response.json()
