import unicodedata
from typing import Any

from app.services.customer_state_service import CustomerStateService

SURVEY_TEXT = (
    "Como equipo de MacroBase, agradecemos sinceramente la oportunidad de apoyarte. "
    "Para nosotros es muy importante mejorar continuamente nuestro servicio. "
    "Podrias responder 3 preguntas breves acerca de tu experiencia en este chat?"
)

SURVEY_NO_TEXT = (
    "Gracias por comunicarte con MacroBase. Fue un gusto atenderte; quedamos a tus ordenes."
)

SURVEY_FINAL_TEXT = (
    "Como equipo de MacroBase, agradecemos sinceramente tu participacion en la encuesta. "
    "Valoramos mucho tus comentarios, ya que son de gran importancia para nuestro proceso "
    "de mejora continua. Fue un gusto atenderte."
)

SURVEY_QUESTIONS = {
    "rapidez": "La respuesta del agente en el chat fue rapida?",
    "amabilidad": "El agente fue amable y profesional durante la conversacion?",
    "resolucion": "Como calificarias la resolucion de tu conversacion con el agente?",
}

SURVEY_STEPS = ["rapidez", "amabilidad", "resolucion"]
STAR_RATINGS = ["⭐", "⭐⭐", "⭐⭐⭐", "⭐⭐⭐⭐", "⭐⭐⭐⭐⭐"]


def build_closure_survey_start_reply(
    store_path: str,
    conversation_id: str,
    backend: str = "sqlite",
    mysql_config: dict[str, Any] | None = None,
    customer_key: str | None = None,
) -> dict[str, Any] | None:
    if not conversation_id:
        return None

    service = CustomerStateService(backend=backend, sqlite_path=store_path, mysql_config=mysql_config)
    state = service.load(_survey_key(conversation_id))
    data = _ensure_data(state.get("data"))

    if data.get("closure_survey_sent"):
        return None
    if customer_key:
        customer_state = service.load(_survey_customer_key(customer_key))
        customer_data = _ensure_data(customer_state.get("data"))
        if customer_data.get("closure_survey_sent") and not customer_data.get("survey_complete"):
            return None

    return {
        "type": "quick_replies",
        "text": SURVEY_TEXT,
        "help_text": "Selecciona una opcion",
        "buttons": ["Si", "No"],
        "fallback_text": f"{SURVEY_TEXT}\n\nResponde Si o No.",
        "survey": True,
        "survey_action": "start",
    }


def mark_closure_survey_started(
    store_path: str,
    conversation_id: str,
    backend: str = "sqlite",
    mysql_config: dict[str, Any] | None = None,
    customer_key: str | None = None,
) -> None:
    if not conversation_id:
        return

    service = CustomerStateService(backend=backend, sqlite_path=store_path, mysql_config=mysql_config)
    state = service.load(_survey_key(conversation_id))
    data = _ensure_data(state.get("data"))
    data.update(
        {
            "closure_survey_sent": True,
            "closure_survey_answer": None,
            "survey_step": None,
            "ratings": {},
            "survey_conversation_id": conversation_id,
            "survey_customer_key": customer_key,
        }
    )
    _save_survey_data(service, data, conversation_id, customer_key)


def build_closure_survey_answer_reply(
    store_path: str,
    conversation_id: str,
    message_text: str,
    backend: str = "sqlite",
    mysql_config: dict[str, Any] | None = None,
    customer_key: str | None = None,
) -> dict[str, Any] | None:
    if not conversation_id:
        return None

    service = CustomerStateService(backend=backend, sqlite_path=store_path, mysql_config=mysql_config)
    data = _load_survey_data(service, conversation_id, customer_key)

    if not data.get("closure_survey_sent"):
        return None
    if data.get("survey_complete"):
        return None

    data["latest_conversation_id"] = conversation_id
    if customer_key:
        data["survey_customer_key"] = customer_key

    normalized = _normalize(message_text)
    if not data.get("closure_survey_answer"):
        if normalized in {"no", "n"}:
            data["closure_survey_answer"] = "no"
            data["survey_complete"] = True
            _save_survey_data(service, data, conversation_id, customer_key)
            return {
                "type": "text",
                "text": SURVEY_NO_TEXT,
                "survey": True,
                "survey_action": "declined",
            }

        if normalized in {"si", "s", "yes", "y"}:
            data["closure_survey_answer"] = "si"
            data["survey_step"] = SURVEY_STEPS[0]
            _save_survey_data(service, data, conversation_id, customer_key)
            return _rating_payload(SURVEY_STEPS[0])

        return {
            "type": "quick_replies",
            "text": "Para confirmar, deseas responder la encuesta breve de servicio?",
            "help_text": "Selecciona una opcion",
            "buttons": ["Si", "No"],
            "fallback_text": "Por favor responde Si o No.",
            "survey": True,
            "survey_action": "confirm",
        }

    current_step = data.get("survey_step")
    if current_step not in SURVEY_STEPS:
        return None

    rating = _parse_rating(message_text)
    if rating is None:
        return _rating_payload(
            current_step,
            intro="Selecciona una calificacion del 1 al 5 usando las estrellas.",
        )

    ratings = data.setdefault("ratings", {})
    if not isinstance(ratings, dict):
        ratings = {}
        data["ratings"] = ratings
    ratings[current_step] = rating

    next_step = _next_step(current_step)
    if next_step:
        data["survey_step"] = next_step
        _save_survey_data(service, data, conversation_id, customer_key)
        return _rating_payload(next_step)

    data["survey_step"] = None
    data["survey_complete"] = True
    data["promedio"] = round(sum(int(ratings[step]) for step in SURVEY_STEPS) / len(SURVEY_STEPS), 2)
    _save_survey_data(service, data, conversation_id, customer_key)

    return {
        "type": "text",
        "text": SURVEY_FINAL_TEXT,
        "survey": True,
        "survey_action": "completed",
        "promedio": data["promedio"],
    }


def is_resolution_event(event_type: str | None, payload: dict[str, Any]) -> bool:
    normalized_event = _normalize(event_type or "")
    if normalized_event in {
        "conversation_resolution",
        "conversation_resolved",
        "conversation_update",
        "onconversationupdate",
    }:
        if _payload_has_resolved_status(payload) or "resolution" in normalized_event:
            return True
    return _payload_has_resolved_status(payload)


def _rating_payload(step: str, intro: str | None = None) -> dict[str, Any]:
    question = SURVEY_QUESTIONS[step]
    text = f"{intro}\n\n{question}" if intro else question
    return {
        "type": "dropdown",
        "text": text,
        "help_text": "Califica de 1 a 5",
        "buttons": STAR_RATINGS,
        "fallback_text": (
            f"{question}\n\n"
            "Responde con un numero del 1 al 5 o envia estrellas, por ejemplo: ⭐⭐⭐⭐⭐."
        ),
        "survey": True,
        "survey_action": "rating",
        "survey_step": step,
    }


def _payload_has_resolved_status(payload: dict[str, Any]) -> bool:
    candidates = [
        payload.get("status"),
        _get_path(payload, "data.status"),
        _get_path(payload, "conversation.status"),
        _get_path(payload, "data.conversation.status"),
        _get_path(payload, "data.resolve.conversation.status"),
    ]
    for value in candidates:
        if _normalize(str(value or "")) == "resolved":
            return True

    status_change = _get_path(payload, "changes.model_changes.status")
    if isinstance(status_change, list):
        return any(_normalize(str(value)) == "resolved" for value in status_change)
    if isinstance(status_change, dict):
        return any(_normalize(str(value)) == "resolved" for value in status_change.values())

    return False


def _parse_rating(value: str) -> int | None:
    normalized = _normalize(value)
    if normalized in {"1", "2", "3", "4", "5"}:
        return int(normalized)

    compact = (value or "").replace(" ", "").replace("\ufe0f", "")
    if compact and set(compact).issubset({"⭐", "★"}) and 1 <= len(compact) <= 5:
        return len(compact)

    return None


def _next_step(current_step: str) -> str | None:
    index = SURVEY_STEPS.index(current_step)
    next_index = index + 1
    if next_index >= len(SURVEY_STEPS):
        return None
    return SURVEY_STEPS[next_index]


def _survey_key(conversation_id: str) -> str:
    return f"closure_survey:{conversation_id}"


def _survey_customer_key(customer_key: str) -> str:
    return f"closure_survey_customer:{customer_key}"


def _load_survey_data(
    service: CustomerStateService,
    conversation_id: str,
    customer_key: str | None,
) -> dict[str, Any]:
    data = _ensure_data(service.load(_survey_key(conversation_id)).get("data"))
    if data.get("closure_survey_sent"):
        return data
    if customer_key:
        data = _ensure_data(service.load(_survey_customer_key(customer_key)).get("data"))
        if data.get("closure_survey_sent"):
            return data
    return {}


def _save_survey_data(
    service: CustomerStateService,
    data: dict[str, Any],
    conversation_id: str,
    customer_key: str | None,
) -> None:
    service.save(_survey_key(conversation_id), None, None, data)
    original_conversation_id = str(data.get("survey_conversation_id") or "").strip()
    if original_conversation_id and original_conversation_id != conversation_id:
        service.save(_survey_key(original_conversation_id), None, None, data)
    if customer_key:
        service.save(_survey_customer_key(customer_key), None, None, data)


def _ensure_data(value: Any) -> dict[str, Any]:
    return value if isinstance(value, dict) else {}


def _normalize(value: str) -> str:
    normalized = unicodedata.normalize("NFKD", value or "")
    normalized = "".join(char for char in normalized if not unicodedata.combining(char))
    return " ".join(normalized.lower().strip().split())


def _get_path(payload: dict[str, Any], path: str) -> Any:
    current: Any = payload
    for key in path.split("."):
        if not isinstance(current, dict):
            return None
        current = current.get(key)
    return current

