from __future__ import annotations

import contextvars
import json
from pathlib import Path


ACTION_CONTEXT = contextvars.ContextVar("levbot_action_context", default="")
CHANNELS = ("site", "telegram", "max", "bitrix", "avito")

TASK_LABELS = {
    "sales": "продажа",
    "consultation": "консультация",
    "sales_consultation": "продажа с консультацией",
    "support": "поддержка",
}
GOAL_LABELS = {
    "collect_phone": "получить номер телефона",
    "collect_request": "собрать заявку",
    "send_to_site": "отправить клиента на сайт",
    "handoff_manager": "передать менеджеру",
    "direct_sale": "прямая продажа",
    "booking": "запись или бронирование",
    "help_only": "просто помочь клиенту",
}
FALLBACK_LABELS = {
    "continue_consultation": "продолжить консультацию",
    "fallback_collect_phone": "предложить оставить телефон",
    "fallback_send_to_site": "предложить перейти на сайт",
    "fallback_handoff": "передать менеджеру",
    "finish_without_pressure": "завершить без давления",
}


def _default_actions() -> dict:
    return {
        "schema": "levbot-actions/1",
        "use_same_for_all_channels": True,
        "default": {
            "task": "sales_consultation",
            "goal": "collect_phone",
            "goal_config": {},
            "fallback": "continue_consultation",
        },
        "channels": {channel: {"inherit": True} for channel in CHANNELS},
    }


def _load_actions() -> dict:
    path = Path(__file__).with_name("actions.json")
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        return _default_actions()
    return data if isinstance(data, dict) else _default_actions()


def _active_rule(actions: dict, channel: str) -> dict:
    default = actions.get("default") if isinstance(actions.get("default"), dict) else _default_actions()["default"]
    if actions.get("use_same_for_all_channels", True):
        return dict(default)
    item = actions.get("channels", {}).get(channel, {})
    if not isinstance(item, dict) or item.get("inherit", True):
        return dict(default)
    rule = dict(default)
    rule.update(item)
    if not isinstance(rule.get("goal_config"), dict):
        rule["goal_config"] = {}
    return rule


def resolve_channel(chat_id: str = "", client_id: str = "") -> str:
    raw = f"{chat_id or ''} {client_id or ''}".lower()
    if raw.startswith("telegram:") or "telegram:" in raw:
        return "telegram"
    if raw.startswith("max:") or "max:" in raw:
        return "max"
    if "avito" in raw:
        return "avito"
    if client_id:
        return "bitrix"
    return "site"


def _cfg_line(label: str, value: object) -> str:
    text = str(value or "").strip()
    return f"{label}: {text}" if text else ""


def build_action_context(channel: str) -> str:
    actions = _load_actions()
    rule = _active_rule(actions, channel)
    goal = str(rule.get("goal") or "collect_phone")
    task = str(rule.get("task") or "sales_consultation")
    fallback = str(rule.get("fallback") or "continue_consultation")
    cfg = rule.get("goal_config") if isinstance(rule.get("goal_config"), dict) else {}
    lines = [
        "Настройка действия владельца LEVBOT.",
        f"Текущий канал: {channel}.",
        f"Основная задача: {TASK_LABELS.get(task, task)}.",
        f"Главная цель разговора: {GOAL_LABELS.get(goal, goal)}.",
        f"Если клиент пока не готов: {FALLBACK_LABELS.get(fallback, fallback)}.",
        "Сначала ответь по существу. Предлагай следующий шаг только когда это уместно.",
        "Не придумывай ссылки, реквизиты, стоимость, контакты и способы записи.",
    ]
    if goal == "collect_phone":
        lines.append("Если после консультации нужен следующий шаг, естественно предложи оставить номер телефона.")
    elif goal == "collect_request":
        lines.append(_cfg_line("Данные для заявки", "; ".join(str(cfg.get("fields", "")).splitlines())))
        lines.append(_cfg_line("Текст после заявки", cfg.get("after_text")))
    elif goal == "send_to_site":
        lines.append(_cfg_line("Разрешённая ссылка", cfg.get("url")))
        lines.append(_cfg_line("Текст перед ссылкой", cfg.get("message_before")))
        lines.append(_cfg_line("Название ссылки", cfg.get("link_label")))
    elif goal == "handoff_manager":
        lines.append(_cfg_line("Текст перед передачей", cfg.get("handoff_before")))
        lines.append(_cfg_line("Если менеджер недоступен", cfg.get("handoff_unavailable")))
        lines.append("Используй существующий механизм передачи менеджеру, если он настроен.")
    elif goal == "direct_sale":
        method = str(cfg.get("method") or "payment_instructions")
        lines.append(f"Способ прямой продажи: {method}.")
        lines.append(_cfg_line("Стоимость или пояснение", cfg.get("price_text")))
        if method == "payment_link":
            lines.append(_cfg_line("Разрешённая платёжная ссылка", cfg.get("payment_url")))
            lines.append(_cfg_line("Текст перед ссылкой", cfg.get("message_before")))
        else:
            lines.append(_cfg_line("Инструкция по оплате", cfg.get("payment_instructions")))
        lines.append(_cfg_line("Что делать после оплаты", cfg.get("after_payment")))
        lines.append("Не утверждай, что платёж получен, и не проверяй оплату.")
        lines.append("Не отправляй оплату без явной готовности клиента купить или оплатить.")
    elif goal == "booking":
        method = str(cfg.get("method") or "booking_link")
        lines.append(f"Способ записи: {method}.")
        lines.append(_cfg_line("Ссылка на запись", cfg.get("booking_url")))
        lines.append(_cfg_line("Текст приглашения", cfg.get("invite_text")))
        lines.append(_cfg_line("Текст после перехода", cfg.get("after_booking")))
    elif goal == "help_only":
        lines.append("Отвечай по существу и не обязан переводить клиента к продаже, контакту или менеджеру.")
    return "\n".join(line for line in lines if line)


def install(server_module):
    original_ask_lev = server_module.ask_lev
    original_turn = server_module.turn

    async def ask_lev_with_actions(history, extra_system=""):
        action_context = ACTION_CONTEXT.get()
        combined = "\n\n".join(part for part in (action_context, extra_system) if str(part or "").strip())
        return await original_ask_lev(history, combined)

    async def turn_with_actions(chat_id, user_text, image_data_uri="", client_id=""):
        channel = resolve_channel(str(chat_id or ""), str(client_id or ""))
        token = ACTION_CONTEXT.set(build_action_context(channel))
        try:
            return await original_turn(chat_id, user_text, image_data_uri, client_id)
        finally:
            ACTION_CONTEXT.reset(token)

    server_module.ask_lev = ask_lev_with_actions
    server_module.turn = turn_with_actions
    return server_module.app
