"""DSL parser — maps natural language phrases to proxym API calls.

Simple pattern matching that works without LLM. Handles both Polish and English
phrases. Falls back to None when no pattern matches (caller should route to LLM).

Usage:
    parser = DSLParser()
    cmd = parser.parse("pokaż VM-y")
    if cmd:
        result = parser.execute(cmd)
"""

from __future__ import annotations

import re
import time
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any

import yaml

import structlog

logger = structlog.get_logger()

_DEFAULT_DSL_PATH = Path.home() / ".config" / "proxym" / "dsl.yaml"

# Bundled DSL used when no user config exists
_BUNDLED_DSL: dict[str, Any] = {
    "version": "2.0",
    "queries": {
        # ── Status & System ─────────────────────────────────────────────────────
        "status": {
            "patterns": [
                "status", "jak idzie", "co działa", "pokaż stan", "show status",
                "system status", "health", "health check", "sprawdź status"
            ],
            "action": "GET /dashboard/system",
            "format": "table",
        },
        "diagnose": {
            "patterns": [
                "diagnose", "diagnostics", "run tests", "sprawdź", "testy",
                "verify system", "check health", "health check"
            ],
            "action": "GET /tests/status",
            "format": "text",
        },
        # ── VMs ───────────────────────────────────────────────────────────────────
        "vms": {
            "patterns": [
                "pokaż VM-y", "lista maszyn", "które VM-y działają",
                "vm list", "list vms", "show vms", "vms", "maszyny"
            ],
            "action": "GET /dashboard/vms",
            "format": "table",
        },
        # ── Tickets ─────────────────────────────────────────────────────────────
        "tickets": {
            "patterns": [
                "list tickets", "show tickets", "pokaż tickety", "zadania",
                "tickets", "tickety", "wszystkie tickety", "all tickets",
                "show all tickets", "pokaż wszystkie tickety"
            ],
            "action": "GET /dashboard/tickets",
            "format": "table",
        },
        "ticket_board": {
            "patterns": [
                "board", "kanban", "tablica", "show board", "pokaż tablicę",
                "ticket board", "task board"
            ],
            "action": "GET /dashboard/tickets/board/view",
            "format": "table",
        },
        "ticket_detail": {
            "patterns": [
                "show ticket {ticket_id}", "ticket {ticket_id}", "pokaż ticket {ticket_id}",
                "details for {ticket_id}", "info about {ticket_id}"
            ],
            "action": "GET /dashboard/tickets/{ticket_id}",
            "format": "table",
        },
        # ── Sprints ─────────────────────────────────────────────────────────────
        "sprints": {
            "patterns": [
                "list sprints", "sprinty", "show sprints", "sprints",
                "wszystkie sprinty", "all sprints", "pokaż sprinty"
            ],
            "action": "GET /dashboard/sprints",
            "format": "table",
        },
        "sprint_detail": {
            "patterns": [
                "show sprint {sprint_name}", "sprint {sprint_name}", "pokaż sprint {sprint_name}",
                "details for sprint {sprint_name}"
            ],
            "action": "GET /dashboard/sprints/{sprint_name}",
            "format": "table",
        },
        # ── Projects ─────────────────────────────────────────────────────────────
        "projects": {
            "patterns": [
                "list projects", "projekty", "show projects", "projects",
                "wszystkie projekty", "all projects", "pokaż projekty"
            ],
            "action": "GET /dashboard/projects",
            "format": "table",
        },
        "project_detail": {
            "patterns": [
                "show project {project_name}", "project {project_name}", "pokaż projekt {project_name}",
                "details for project {project_name}"
            ],
            "action": "GET /dashboard/projects/{project_name}",
            "format": "table",
        },
        # ── Tools & Jobs ──────────────────────────────────────────────────────────
        "tools": {
            "patterns": [
                "list tools", "tools", "narzędzia", "show tools", "pokaż narzędzia",
                "available tools", "dostępne narzędzia"
            ],
            "action": "GET /dashboard/tools",
            "format": "table",
        },
        "jobs": {
            "patterns": [
                "list jobs", "jobs", "zadania", "show jobs", "pokaż zadania",
                "job queue", "kolejka zadań", "running jobs"
            ],
            "action": "GET /dashboard/tools/jobs",
            "format": "table",
        },
        "queue": {
            "patterns": [
                "queue", "show queue", "pokaż kolejkę", "task queue"
            ],
            "action": "GET /dashboard/tools/queue",
            "format": "table",
        },
        # ── Models & Providers ────────────────────────────────────────────────────
        "models": {
            "patterns": [
                "jakie modele", "dostępne modele", "models", "list models",
                "show models", "pokaż modele", "available models"
            ],
            "action": "GET /v1/models",
            "format": "table",
        },
        "providers": {
            "patterns": [
                "providers", "list providers", "providery", "dostawcy",
                "show providers", "pokaż dostawców"
            ],
            "action": "GET /dashboard/providers",
            "format": "table",
        },
        # ── Logs & Costs ──────────────────────────────────────────────────────────
        "logs": {
            "patterns": [
                "logi", "błędy", "ostatnie zdarzenia", "co się stało",
                "logs", "show logs", "errors", "recent logs", "system logs"
            ],
            "action": "GET /dashboard/logs?lines=50",
            "format": "text",
        },
        "costs": {
            "patterns": [
                "ile wydałem", "koszty", "podsumowanie budżetu",
                "costs", "show costs", "budget", "spending", "expenses"
            ],
            "action": "GET /dashboard/costs",
            "format": "chart",
        },
        # ── Analysis ───────────────────────────────────────────────────────────────
        "analyze": {
            "patterns": [
                "analyze {ticket_id}", "analyze ticket {ticket_id}", "analysis for {ticket_id}",
                "check {ticket_id}", "review {ticket_id}", "sprawdź {ticket_id}",
                "analiza {ticket_id}", "analizuj {ticket_id}"
            ],
            "action": "GET /dashboard/tickets/{ticket_id}/analyze",
            "format": "text",
        },
    },
    "commands": {
        # ── Ticket Management ──────────────────────────────────────────────────────
        "ticket_create": {
            "patterns": [
                "create ticket for {task}", "add ticket for {task}", "new ticket for {task}",
                "utwórz ticket dla {task}", "dodaj ticket dla {task}", "nowy ticket dla {task}",
                "create ticket to {task}", "add ticket to {task}",
                "create {type} ticket for {task}", "create {priority} priority ticket for {task}",
                "create {priority} priority {type} ticket for {task}",
                "utwórz ticket {type} dla {task}", "dodaj {type} ticket dla {task}",
                "utwórz {priority} priorytet ticket dla {task}"
            ],
            "action": "POST /dashboard/tickets",
            "params_from_pattern": ["task", "type", "priority"],
            "defaults": {"type": "task", "priority": "medium"},
        },
        "ticket_create_in_project": {
            "patterns": [
                "create ticket in {project} for {task}", "add ticket in {project} for {task}",
                "create ticket for {task} in {project}", "add ticket for {task} in {project}",
                "utwórz ticket w {project} dla {task}", "dodaj ticket w {project} dla {task}",
                "create {type} ticket in {project} for {task}",
                "create {priority} priority ticket in {project} for {task}",
                "utwórz {type} ticket w {project} dla {task}"
            ],
            "action": "POST /dashboard/tickets",
            "params_from_pattern": ["project", "task", "type", "priority"],
            "defaults": {"type": "task", "priority": "medium"},
        },
        "ticket_assign": {
            "patterns": [
                "assign {ticket_id} to {tool}", "assign ticket {ticket_id} to {tool}",
                "przypisz {ticket_id} do {tool}", "przypisz ticket {ticket_id} do {tool}",
                "dispatch {ticket_id}", "dispatch ticket {ticket_id}",
                "wyślij {ticket_id}", "wyślij ticket {ticket_id}",
                "assign {ticket_id} to {tool} with {model}",
                "dispatch {ticket_id} using {tool}", "dispatch {ticket_id} with {tool}"
            ],
            "action": "POST /dashboard/tools/dispatch",
            "params_from_pattern": ["ticket_id", "tool", "model"],
            "defaults": {"model": "smart"},
            "exclude": ["all", "all tickets"],  # These should match batch_tickets instead
        },
        "ticket_close": {
            "patterns": [
                "close {ticket_id}", "close ticket {ticket_id}", "zamknij {ticket_id}",
                "zamknij ticket {ticket_id}", "mark {ticket_id} as done",
                "finish {ticket_id}", "complete {ticket_id}"
            ],
            "action": "POST /dashboard/tickets/{ticket_id}/close",
            "params_from_pattern": ["ticket_id"],
        },
        "ticket_update": {
            "patterns": [
                "update {ticket_id} priority to {priority}", "change {ticket_id} priority to {priority}",
                "set {ticket_id} priority {priority}", "zmień priorytet {ticket_id} na {priority}"
            ],
            "action": "POST /dashboard/tickets/{ticket_id}/update",
            "params_from_pattern": ["ticket_id", "priority"],
        },
        # ── Sprint Management ──────────────────────────────────────────────────────
        "sprint_create": {
            "patterns": [
                "create sprint {name}", "new sprint {name}", "add sprint {name}",
                "utwórz sprint {name}", "nowy sprint {name}", "dodaj sprint {name}",
                "create sprint {name} with goal {goal}", "create sprint {name} for {goal}",
                "utwórz sprint {name} z celem {goal}", "utwórz sprint {name} dla {goal}"
            ],
            "action": "POST /dashboard/sprints",
            "params_from_pattern": ["name", "goal"],
            "defaults": {},
        },
        "sprint_start": {
            "patterns": [
                "start sprint {sprint_name}", "activate sprint {sprint_name}",
                "rozpocznij sprint {sprint_name}", "włącz sprint {sprint_name}"
            ],
            "action": "POST /dashboard/sprints/{sprint_name}/start",
            "params_from_pattern": ["sprint_name"],
        },
        "sprint_close": {
            "patterns": [
                "close sprint {sprint_name}", "end sprint {sprint_name}",
                "complete sprint {sprint_name}", "zamknij sprint {sprint_name}",
                "zakończ sprint {sprint_name}"
            ],
            "action": "POST /dashboard/sprints/{sprint_name}/close",
            "params_from_pattern": ["sprint_name"],
        },
        "sprint_add_ticket": {
            "patterns": [
                "add {ticket_id} to sprint {sprint_name}",
                "move {ticket_id} to sprint {sprint_name}",
                "dodaj {ticket_id} do sprintu {sprint_name}",
                "przenieś {ticket_id} do sprintu {sprint_name}"
            ],
            "action": "POST /dashboard/sprints/{sprint_name}/tickets",
            "params_from_pattern": ["ticket_id", "sprint_name"],
        },
        # ── Project Management ─────────────────────────────────────────────────────
        "project_register": {
            "patterns": [
                "register project {name} at {path}", "add project {name} at {path}",
                "create project {name} at {path}", "new project {name} at {path}",
                "zarejestruj projekt {name} w {path}", "dodaj projekt {name} w {path}",
                "utwórz projekt {name} w {path}", "nowy projekt {name} w {path}",
                "register project {name} using {tool} at {path}",
                "create project {name} using {tool} at {path}",
                "create project {name} with tool {tool} at {path}"
            ],
            "action": "POST /dashboard/projects",
            "params_from_pattern": ["name", "path", "tool"],
            "defaults": {"tool": "aider"},
        },
        "project_remove": {
            "patterns": [
                "remove project {project_name}", "delete project {project_name}",
                "usun projekt {project_name}", "usuń projekt {project_name}"
            ],
            "action": "DELETE /dashboard/projects/{project_name}",
            "params_from_pattern": ["project_name"],
        },
        # ── VM Management ─────────────────────────────────────────────────────────
        "vm_create": {
            "patterns": [
                "stwórz VM {tool} dla {project}", "nowa maszyna {tool} projekt {project}",
                "utwórz {tool} dla {project}", "create vm {tool} for {project}",
                "create {tool} for {project}", "new vm {tool} for {project}"
            ],
            "action": "POST /dashboard/vms",
            "params_from_pattern": ["tool", "project"],
            "defaults": {"account": "cheapest_active"},
        },
        "vm_start": {
            "patterns": [
                "uruchom {vm_id}", "start {vm_id}", "włącz {vm_id}",
                "start vm {vm_id}", "power on {vm_id}"
            ],
            "action": "POST /dashboard/vms/{vm_id}/start",
            "params_from_pattern": ["vm_id"],
        },
        "vm_stop": {
            "patterns": [
                "zatrzymaj {vm_id}", "stop {vm_id}", "wyłącz {vm_id}",
                "stop vm {vm_id}", "power off {vm_id}", "shutdown {vm_id}"
            ],
            "action": "POST /dashboard/vms/{vm_id}/stop",
            "params_from_pattern": ["vm_id"],
        },
        "vm_restart": {
            "patterns": [
                "restart {vm_id}", "reboot {vm_id}", "zrestartuj {vm_id}",
                "restart vm {vm_id}", "reboot vm {vm_id}"
            ],
            "action": "POST /dashboard/vms/{vm_id}/restart",
            "params_from_pattern": ["vm_id"],
        },
        "vm_delete": {
            "patterns": [
                "delete {vm_id}", "remove {vm_id}", "destroy {vm_id}",
                "usuń {vm_id}", "skasuj {vm_id}", "delete vm {vm_id}"
            ],
            "action": "DELETE /dashboard/vms/{vm_id}",
            "params_from_pattern": ["vm_id"],
        },
        "vm_snapshot": {
            "patterns": [
                "snapshot {vm_id} jako {name}", "snapshot {vm_id} as {name}",
                "snapshot {vm_id}", "zapisz stan {vm_id}",
                "create snapshot {vm_id}", "save snapshot {vm_id}"
            ],
            "action": "POST /dashboard/vms/{vm_id}/snapshot",
            "params_from_pattern": ["vm_id", "name"],
            "defaults": {"name": "auto-{timestamp}"},
        },
        "vm_restore": {
            "patterns": [
                "restore {vm_id} from {name}", "restore snapshot {name} on {vm_id}",
                "przywróć {vm_id} z {name}", "przywróć snapshot {name} na {vm_id}"
            ],
            "action": "POST /dashboard/vms/{vm_id}/restore",
            "params_from_pattern": ["vm_id", "name"],
        },
        "switch_project": {
            "patterns": [
                "przełącz {vm_id} na {project}", "zmień projekt {vm_id} na {project}",
                "switch {vm_id} to {project}", "move {vm_id} to {project}",
                "change project for {vm_id} to {project}"
            ],
            "action": "POST /dashboard/vms/{vm_id}/switch-project",
            "params_from_pattern": ["vm_id", "project"],
        },
        # ── Account Management ────────────────────────────────────────────────────
        "add_account": {
            "patterns": [
                "dodaj konto {provider} klucz {key}", "nowe konto {provider}",
                "add account {provider} key {key}", "add {provider} account",
                "register account {provider}"
            ],
            "action": "POST /dashboard/accounts",
            "params_from_pattern": ["provider", "key"],
        },
        # ── Batch Operations ──────────────────────────────────────────────────────
        "batch_tickets": {
            "patterns": [
                "dispatch all tickets for {project}", "run all tickets for {project}",
                "wyślij wszystkie tickety dla {project}", "uruchom wszystkie dla {project}",
                "process all tickets in {project}", "execute all for {project}"
            ],
            "action": "POST /dashboard/tools/batch",
            "params_from_pattern": ["project"],
        },
        "run_workflow": {
            "patterns": [
                "run {task} on {project}", "execute {task} on {project}",
                "run {task} in {project}", "wykonaj {task} na {project}",
                "uruchom {task} w {project}", "do {task} on {project}"
            ],
            "action": "POST /dashboard/tools/run",
            "params_from_pattern": ["task", "project"],
        },
    },
}


@dataclass
class ParsedCommand:
    """Result of successfully parsing a user phrase against the DSL."""

    action_type: str        # "query" or "command"
    endpoint: str           # e.g. "GET /api/v1/vms"
    params: dict[str, Any] = field(default_factory=dict)
    raw_pattern: str = ""
    confidence: float = 1.0
    format: str = "text"


class DSLParser:
    """Parse natural language phrases into proxym API calls.

    Works without LLM — pure pattern matching against a YAML DSL definition.
    """

    def __init__(self, dsl_path: Path | None = None) -> None:
        self._dsl = self._load_dsl(dsl_path)
        self._patterns = self._compile_patterns()

    @staticmethod
    def _load_dsl(dsl_path: Path | None) -> dict:
        """Load DSL from file or use bundled defaults."""
        path = dsl_path or _DEFAULT_DSL_PATH
        if path.exists():
            with open(path) as f:
                return yaml.safe_load(f)
        return _BUNDLED_DSL

    def _compile_patterns(self) -> list[tuple]:
        """Compile all DSL patterns into (regex, action_type, name, spec) tuples."""
        section_type = {"queries": "query", "commands": "command"}
        compiled: list[tuple] = []
        for section in ("queries", "commands"):
            for name, spec in self._dsl.get(section, {}).items():
                for pattern in spec.get("patterns", []):
                    # Convert {placeholder} to named capture groups
                    # Use different patterns based on parameter name
                    def replace_placeholder(match: re.Match) -> str:
                        param_name = match.group(1)
                        if param_name == "path":
                            # Path can contain any characters except whitespace
                            return rf"(?P<{param_name}>\S+)"
                        elif param_name == "task" or param_name == "goal":
                            # Task/goal can contain spaces and other characters
                            return rf"(?P<{param_name}>.+?)(?:\s+(?:in|w|with|z|using|using tool)\s+|$)"
                        else:
                            # Standard word characters
                            return rf"(?P<{param_name}>[\w._-]+)"

                    regex_str = re.sub(r"\{(\w+)\}", replace_placeholder, pattern)
                    compiled.append((
                        re.compile(regex_str, re.IGNORECASE),
                        section_type[section],
                        name,
                        spec,
                    ))
        return compiled

    def parse(self, text: str) -> ParsedCommand | None:
        """Try to match *text* against DSL patterns.

        Returns ``None`` if no pattern matches — caller should forward to LLM.
        """
        text = text.strip()

        for regex, action_type, name, spec in self._patterns:
            m = regex.fullmatch(text) or regex.match(text)
            if m:
                # Check excluded values
                exclude_list = spec.get("exclude", [])
                if exclude_list:
                    # Check if any captured group matches excluded values
                    for key, value in m.groupdict().items():
                        if value and value.lower() in [ex.lower() for ex in exclude_list]:
                            # Skip this pattern, try next
                            break
                    else:
                        # No excluded values found, proceed
                        return self._build_command(m.groupdict(), action_type, name, spec)
                else:
                    return self._build_command(m.groupdict(), action_type, name, spec)

        return None

    @staticmethod
    def _resolve_default(value: Any) -> Any:
        """Resolve dynamic default values like ``auto-{timestamp}``."""
        if isinstance(value, str) and value == "auto-{timestamp}":
            return f"auto-{int(time.time())}"
        return value

    def _build_command(
        self, params: dict, action_type: str, name: str, spec: dict,
    ) -> ParsedCommand:
        """Build a ParsedCommand from matched groups and spec."""
        for k, v in spec.get("defaults", {}).items():
            if k not in params:
                params[k] = self._resolve_default(v)

        endpoint = spec["action"]
        for k, v in params.items():
            endpoint = endpoint.replace(f"{{{k}}}", str(v))

        logger.debug("dsl_match", pattern=name, params=params, endpoint=endpoint)
        return ParsedCommand(
            action_type=action_type,
            endpoint=endpoint,
            params=params,
            raw_pattern=name,
            confidence=1.0,
            format=spec.get("format", "text"),
        )

    def execute(self, cmd: ParsedCommand) -> dict:
        """Execute a parsed command against the proxym API."""
        import httpx

        from proxym.config import get_settings

        settings = get_settings()

        parts = cmd.endpoint.split(" ", 1)
        if len(parts) != 2:
            return {"error": f"Invalid endpoint format: {cmd.endpoint}"}
        method, path = parts
        url = f"http://localhost:{settings.port}{path}"
        headers = {"Authorization": f"Bearer {settings.master_key}"}

        try:
            with httpx.Client(timeout=10, headers=headers) as client:
                if method.upper() == "GET":
                    r = client.get(url)
                else:
                    r = client.post(url, json=cmd.params)
                return r.json()
        except httpx.ConnectError:
            return {"error": "Cannot connect to proxym server"}
        except Exception as exc:
            return {"error": str(exc)}

    def list_patterns(self) -> list[dict[str, Any]]:
        """Return all registered patterns for help / autocomplete."""
        section_type = {"queries": "query", "commands": "command"}
        results = []
        for section in ("queries", "commands"):
            for name, spec in self._dsl.get(section, {}).items():
                results.append({
                    "name": name,
                    "type": section_type[section],
                    "patterns": spec.get("patterns", []),
                    "action": spec.get("action", ""),
                })
        return results
