"""Interactive chat CLI — manage proxym through natural language.

Usage:
    proxym chat              # keyboard input
    proxym chat --voice      # microphone input (Whisper STT)
    proxym chat --tts        # + text-to-speech responses
    proxym chat --voice --tts  # full voice loop
"""

from __future__ import annotations

import json
import re
import sys
from typing import Any

import httpx
import structlog

from proxym.cli.dsl import DSLParser
from proxym.config import get_settings

_ANSI_RE = re.compile(r"\033\[[0-9;]*m")

logger = structlog.get_logger()


_FORMATTERS: dict[str, Any] = {}  # populated below


def _fmt_status(data: dict) -> str:
    parts = []
    if "vms" in data:
        parts.append(f"VMs: {data['vms'].get('count', '?')}")
    if "accounts" in data:
        parts.append(f"Accounts: {data['accounts'].get('count', '?')}")
    if "costs" in data and isinstance(data["costs"], dict):
        parts.append(f"Today: ${data['costs'].get('daily_total_usd', 0):.2f}")
    return ("✅ " + " | ".join(parts)) if parts else json.dumps(data, indent=2)


def _fmt_vms(data: dict) -> str:
    vms = data.get("vms", data.get("data", []))
    if not vms:
        return "No VMs found."
    lines = []
    for vm in vms:
        if isinstance(vm, dict):
            vid = vm.get("id", vm.get("vm_id", "?"))
            state = vm.get("state", "?")
            tool = vm.get("tool", "?")
            project = vm.get("project", vm.get("code_mount", "?"))
            lines.append(f"  {vid:<20} │ {state:<10} │ {tool:<10} │ {project}")
    return "\n".join(lines) if lines else json.dumps(data, indent=2)


def _fmt_costs(data: dict) -> str:
    daily = data.get("daily_total_usd", data.get("today_usd", 0))
    monthly = data.get("monthly_total_usd", data.get("month_usd", 0))
    return f"Today: ${daily:.2f} | This month: ${monthly:.2f}"


def _fmt_vm_action(data: dict) -> str:
    status = data.get("status", "done")
    vm_id = data.get("vm_id", "")
    return f"✅ {status}" + (f" ({vm_id})" if vm_id else "")


_FORMATTERS = {
    "status": _fmt_status,
    "vms": _fmt_vms,
    "costs": _fmt_costs,
    "vm_start": _fmt_vm_action,
    "vm_stop": _fmt_vm_action,
    "vm_create": _fmt_vm_action,
    "vm_snapshot": _fmt_vm_action,
}


def _format_result(data: dict[str, Any], pattern_name: str) -> str:
    """Format API response for human-readable chat output."""
    if "error" in data:
        return f"\033[31m✗ {data['error']}\033[0m"
    fmt = _FORMATTERS.get(pattern_name)
    if fmt:
        return fmt(data)
    return json.dumps(data, indent=2, ensure_ascii=False)


def _ask_proxym_llm(text: str, proxy_url: str, api_key: str) -> str:
    """Forward a question to the LLM via proxym with MCP tools."""
    from proxym.mcp.self_server import TOOL_SCHEMA

    try:
        r = httpx.post(
            f"{proxy_url}/v1/chat/completions",
            headers={"Authorization": f"Bearer {api_key}"},
            json={
                "model": "cheap",
                "messages": [
                    {
                        "role": "system",
                        "content": (
                            "Jesteś asystentem zarządzającym proxym — lokalnym proxy AI. "
                            "Używaj dostępnych narzędzi aby odpowiadać na pytania. "
                            "Odpowiadaj zwięźle po polsku."
                        ),
                    },
                    {"role": "user", "content": text},
                ],
                "tools": TOOL_SCHEMA,
                "tool_choice": "auto",
            },
            timeout=30.0,
        )
        data = r.json()
        choices = data.get("choices", [])
        if choices:
            return choices[0].get("message", {}).get("content", "(no response)")
        return json.dumps(data, indent=2, ensure_ascii=False)
    except httpx.ConnectError:
        return "\033[31m✗ Cannot connect to proxym server\033[0m"
    except Exception as exc:
        return f"\033[31m✗ LLM error: {exc}\033[0m"


def _get_input(voice) -> str | None:
    """Get user input from voice or keyboard. Returns None on empty."""
    if voice:
        text = voice.listen_once()
        if text:
            print(f"\033[36mYou:\033[0m {text}")
        return text or None
    text = input("\033[36mYou:\033[0m ").strip()
    return text or None


def _process_input(text: str, dsl: DSLParser, proxy_url: str, api_key: str) -> str:
    """Route text through DSL or LLM and return formatted response."""
    cmd = dsl.parse(text)
    if cmd:
        result = dsl.execute(cmd)
        return _format_result(result, cmd.raw_pattern)
    return _ask_proxym_llm(text, proxy_url, api_key)


def _init_voice(args):
    """Initialize voice listener if requested."""
    if not getattr(args, "voice", False):
        return None
    try:
        from proxym.cli.voice import VoiceListener
        return VoiceListener()
    except ImportError as exc:
        print(f"\033[31mVoice not available: {exc}\033[0m")
        sys.exit(1)


def _init_tts(args):
    """Initialize TTS engine if requested."""
    if not getattr(args, "tts", False):
        return None
    from proxym.cli.tts import TTSEngine
    return TTSEngine()


def cmd_chat(args) -> None:
    """Interactive chat with proxym — DSL first, LLM fallback."""
    settings = get_settings()
    proxy_url = getattr(args, "proxy", settings.default_proxy_url)
    api_key = getattr(args, "key", settings.default_api_key)

    dsl = DSLParser()
    voice = _init_voice(args)
    tts = _init_tts(args)

    mode = "voice" if voice else "text"
    print(f"\033[1mproxym chat\033[0m — {mode} mode (Ctrl+C to exit)")
    print("Type 'help' for available DSL commands.\n")

    while True:
        try:
            text = _get_input(voice)
            if not text:
                continue
            if text.lower() in ("exit", "quit", "bye"):
                print("Do widzenia!")
                break
            if text.lower() == "help":
                _print_help(dsl)
                continue

            response = _process_input(text, dsl, proxy_url, api_key)
            print(f"\033[32mproxym:\033[0m {response}")

            if tts:
                tts.speak(_ANSI_RE.sub("", response))

        except KeyboardInterrupt:
            print("\nDo widzenia!")
            break
        except EOFError:
            break


def _print_help(dsl: DSLParser) -> None:
    """Print available DSL patterns."""
    print("\n\033[1mAvailable commands (DSL — no LLM needed):\033[0m\n")
    for entry in dsl.list_patterns():
        ptype = "📖" if entry["type"] == "query" else "⚡"
        print(f"  {ptype} \033[1m{entry['name']}\033[0m")
        for p in entry["patterns"][:3]:
            print(f"     {p}")
        print()
    print("Anything else is forwarded to LLM with proxym tools.\n")
