from __future__ import annotations

import json
from typing import Any

from sqlalchemy import select

from services.shared.core import utc_now_iso
from services.shared.models import AIOperatorConfig, AIOperatorConfigOut
from services.shared.sql_models import AIOperatorSettingsRow


AI_OPERATOR_SETTINGS_KEY = "global"


def ai_operator_default_config() -> AIOperatorConfig:
    return AIOperatorConfig(
        agent_name="Айнур",
        company_name="DigiOps",
        base_system_prompt=(
            "Ты Айнур, единый ИИ-оператор контакт-центра DigiOps для звонков, Telegram и других каналов. "
            "Всегда сохраняй одну и ту же личность: тебя зовут Айнур. Если клиент спрашивает, кто ты или как "
            "тебя зовут, отвечай, что ты Айнур. Отвечай естественно, кратко и по делу. Когда говоришь о себе, "
            "используй женский род: могла, смогла, сделала, готова, проверила, нашла. Не завершай диалог "
            "самостоятельно и говори «до свидания» только если клиент явно попрощался или попросил завершить "
            "разговор. Телефонные номера читай по цифрам. Не используй Markdown, URL или таблицы."
        ),
        identity_reply_ru="Я Айнур, оператор контакт-центра DigiOps. Чем могу помочь?",
        identity_reply_kz="Мен Айнурмын, DigiOps байланыс орталығының операторымын. Қалай көмектесе аламын?",
        voice_greeting_ru="Здравствуйте. Я Айнур. Подскажите, пожалуйста, чем помочь. (тест деплоя)",
        voice_greeting_kz="Сәлеметсіз бе. Мен Айнурмын. Қалай көмектесе аламын?",
    )


def _settings_row(session) -> AIOperatorSettingsRow | None:
    return session.execute(
        select(AIOperatorSettingsRow).where(AIOperatorSettingsRow.settings_key == AI_OPERATOR_SETTINGS_KEY)
    ).scalar_one_or_none()


def _normalize_config_payload(raw: Any) -> AIOperatorConfig:
    if isinstance(raw, AIOperatorConfig):
        return raw
    if not isinstance(raw, dict):
        raise ValueError("AI operator config payload must be an object")
    return AIOperatorConfig.model_validate(raw)


def load_ai_operator_config(session) -> AIOperatorConfigOut:
    default_config = ai_operator_default_config()
    row = _settings_row(session)
    if row is None:
        return AIOperatorConfigOut(config=default_config, updated_at=None, source="defaults")
    try:
        parsed = json.loads(row.config_json or "{}")
        config = _normalize_config_payload(parsed)
        return AIOperatorConfigOut(config=config, updated_at=row.updated_at, source="database")
    except Exception:
        return AIOperatorConfigOut(config=default_config, updated_at=row.updated_at, source="defaults")


def load_effective_ai_operator_config(session) -> AIOperatorConfig:
    return load_ai_operator_config(session).config


def save_ai_operator_config(
    session,
    config_payload: AIOperatorConfig | dict[str, Any],
) -> AIOperatorConfigOut:
    config = _normalize_config_payload(config_payload)
    row = _settings_row(session)
    now = utc_now_iso()
    if row is None:
        row = AIOperatorSettingsRow(
            settings_key=AI_OPERATOR_SETTINGS_KEY,
            config_json="{}",
            updated_at=now,
        )
        session.add(row)
    row.config_json = json.dumps(config.model_dump(), ensure_ascii=False)
    row.updated_at = now
    session.commit()
    session.refresh(row)
    return AIOperatorConfigOut(config=config, updated_at=row.updated_at, source="database")


def sync_ai_operator_config_from_code(session) -> AIOperatorConfigOut:
    """Overwrite the DB-stored config with the code defaults.

    Called on service startup so `ai_operator_default_config()` is the
    source of truth: edit it, deploy, and the DB row is overwritten to match.
    Any manual edits made via the API/psql since the last deploy are lost.
    """
    return save_ai_operator_config(session, ai_operator_default_config())
