from __future__ import annotations

import json
import re
from typing import Any

import httpx

from app.core.config import get_settings


SYSTEM_PROMPT = """Ты помощник инженера по редактированию ГОСТ-таблиц (перечень, спецификация, ведомость).
Пользователь даёт команды на русском. Ты отвечаешь ТОЛЬКО валидным JSON без markdown:
{
  "reply": "краткий ответ пользователю",
  "edits": [
    {"op": "update_row", "row_id": 123, "fields": {"note": "..."}},
    {"op": "update_row", "row_index": 5, "fields": {"designation": "..."}},
    {"op": "add_row", "row_index": 10, "fields": {...}},
    {"op": "delete_row", "row_id": 123}
  ]
}
Правила:
- Меняй только то, о чём просят.
- Используй row_id из снимка таблицы, если есть.
- Не выдумывай поля вне списка колонок.
- Если правок нет — edits: [].
"""


def _extract_json(text: str) -> dict[str, Any]:
    text = text.strip()
    if text.startswith("```"):
        text = re.sub(r"^```(?:json)?\s*", "", text)
        text = re.sub(r"\s*```$", "", text)
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        m = re.search(r"\{.*\}", text, re.S)
        if m:
            return json.loads(m.group(0))
        return {"reply": text, "edits": []}


def compress_rows(rows: list[dict[str, Any]], max_rows: int) -> list[dict[str, Any]]:
    slim = []
    for r in rows[:max_rows]:
        item = {"row_id": r.get("id"), "row_index": r.get("row_index")}
        for k, v in r.items():
            if k in ("id", "project_id", "is_auto_generated", "stretch"):
                continue
            if v not in ("", None, False, 0) or k in ("is_header", "is_empty"):
                item[k] = v
        slim.append(item)
    return slim


async def chat_edit_table(
    message: str,
    table_type: str,
    rows: list[dict[str, Any]],
) -> dict[str, Any]:
    settings = get_settings()
    if not settings.openrouter_api_key:
        return {
            "reply": "OpenRouter API key не настроен (OPENROUTER_API_KEY).",
            "edits": [],
        }

    snapshot = compress_rows(rows, settings.llm_max_context_rows)
    user_content = (
        f"Тип таблицы: {table_type}\n"
        f"Снимок строк (до {settings.llm_max_context_rows}):\n"
        f"{json.dumps(snapshot, ensure_ascii=False)}\n\n"
        f"Команда пользователя: {message}"
    )

    payload = {
        "model": settings.openrouter_model,
        "messages": [
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_content},
        ],
        "temperature": 0.2,
        "max_tokens": 2000,
    }
    headers = {
        "Authorization": f"Bearer {settings.openrouter_api_key}",
        "Content-Type": "application/json",
        "HTTP-Referer": "https://gostgenerator.local",
        "X-Title": "GostGenerator Web",
    }
    url = settings.openrouter_base_url.rstrip("/") + "/chat/completions"

    proxy = (settings.openrouter_proxy or "").strip() or None
    if proxy and "://" not in proxy:
        proxy = f"socks5://{proxy}"

    client_kwargs: dict[str, Any] = {"timeout": 90.0}
    if proxy:
        client_kwargs["proxy"] = proxy

    async with httpx.AsyncClient(**client_kwargs) as client:
        resp = await client.post(url, headers=headers, json=payload)
        resp.raise_for_status()
        data = resp.json()

    content = data["choices"][0]["message"]["content"]
    parsed = _extract_json(content)
    edits = parsed.get("edits") or []
    # normalize
    norm_edits = []
    for e in edits:
        if not isinstance(e, dict):
            continue
        norm_edits.append(
            {
                "op": e.get("op", "update_row"),
                "row_id": e.get("row_id"),
                "row_index": e.get("row_index"),
                "fields": e.get("fields") or {},
            }
        )
    return {"reply": parsed.get("reply") or "", "edits": norm_edits}
