"""
End-to-End tests for NLP functionality.

Tests the complete flow: DSL parsing -> CLI generation -> Command execution.
"""

import pytest
import subprocess
import json
import time
from typing import Optional


class TestNLPCommandsE2E:
    """E2E tests for NLP command generation and execution."""

    @staticmethod
    def run_nlp_command(prompt: str, timeout: int = 30) -> tuple[bool, str, float]:
        """Run NLP command and return (success, output, duration_ms)."""
        start = time.time()
        try:
            result = subprocess.run(
                ["proxym", "chat", prompt, "--cli-mode"],
                capture_output=True,
                text=True,
                timeout=timeout
            )
            duration = (time.time() - start) * 1000
            success = result.returncode == 0 and "proxym" in result.stdout
            return success, result.stdout + result.stderr, duration
        except subprocess.TimeoutExpired:
            return False, "Timeout", (time.time() - start) * 1000
        except Exception as e:
            return False, str(e), (time.time() - start) * 1000

    def _assert_dsl_match(self, output: str, expected_command: str) -> None:
        """Assert that DSL matched and generated expected command."""
        assert "dsl_match" in output, f"Expected DSL match, got: {output}"
        assert expected_command in output, f"Expected '{expected_command}' in output"

    # ── Ticket Tests ────────────────────────────────────────────────────────────

    def test_create_ticket_simple(self):
        """E2E: Create simple ticket via NLP."""
        success, output, duration = self.run_nlp_command("create ticket for fix login bug")
        assert success, f"Command failed: {output}"
        self._assert_dsl_match(output, "proxym ticket add")
        assert duration < 2000, f"Too slow: {duration}ms"

    def test_create_ticket_typed(self):
        """E2E: Create typed ticket via NLP."""
        success, output, _ = self.run_nlp_command("create feature ticket for add search")
        assert success
        self._assert_dsl_match(output, "ticket add")
        assert "feature" in output.lower()

    def test_create_ticket_priority(self):
        """E2E: Create priority ticket via NLP."""
        success, output, _ = self.run_nlp_command("create high priority ticket for refactor")
        assert success
        self._assert_dsl_match(output, "ticket add")
        assert "high" in output.lower()

    def test_create_ticket_in_project(self):
        """E2E: Create ticket in specific project."""
        success, output, _ = self.run_nlp_command("create ticket in calculator for fix bug")
        assert success
        self._assert_dsl_match(output, "ticket add")
        assert "calculator" in output.lower()

    def test_dispatch_ticket(self):
        """E2E: Dispatch ticket via NLP."""
        success, output, _ = self.run_nlp_command("dispatch TKT-12345")
        assert success
        self._assert_dsl_match(output, "proxym dispatch")

    def test_assign_ticket_with_tool(self):
        """E2E: Assign ticket to specific tool."""
        success, output, _ = self.run_nlp_command("assign TKT-12345 to aider")
        assert success
        self._assert_dsl_match(output, "dispatch")
        assert "aider" in output.lower()

    def test_close_ticket(self):
        """E2E: Close ticket via NLP."""
        success, output, _ = self.run_nlp_command("close TKT-12345")
        assert success
        self._assert_dsl_match(output, "ticket close")

    def test_analyze_ticket(self):
        """E2E: Analyze ticket via NLP."""
        success, output, _ = self.run_nlp_command("analyze TKT-12345")
        assert success
        self._assert_dsl_match(output, "analyze")

    # ── Sprint Tests ────────────────────────────────────────────────────────────

    def test_create_sprint(self):
        """E2E: Create sprint via NLP."""
        success, output, _ = self.run_nlp_command("create sprint MVP")
        assert success
        self._assert_dsl_match(output, "sprint create")

    def test_create_sprint_with_goal(self):
        """E2E: Create sprint with goal via NLP."""
        success, output, _ = self.run_nlp_command("create sprint Release with goal to launch product")
        assert success
        self._assert_dsl_match(output, "sprint create")

    def test_start_sprint(self):
        """E2E: Start sprint via NLP."""
        success, output, _ = self.run_nlp_command("start sprint MVP")
        assert success
        self._assert_dsl_match(output, "sprint start")

    def test_close_sprint(self):
        """E2E: Close sprint via NLP."""
        success, output, _ = self.run_nlp_command("close sprint MVP")
        assert success
        self._assert_dsl_match(output, "sprint close")

    def test_add_ticket_to_sprint(self):
        """E2E: Add ticket to sprint via NLP."""
        success, output, _ = self.run_nlp_command("add TKT-12345 to sprint MVP")
        assert success
        self._assert_dsl_match(output, "sprint")

    # ── Project Tests ────────────────────────────────────────────────────────────

    def test_register_project(self):
        """E2E: Register project via NLP."""
        success, output, _ = self.run_nlp_command("register project test at /tmp/test")
        assert success
        self._assert_dsl_match(output, "project add")

    def test_register_project_with_tool(self):
        """E2E: Register project with specific tool via NLP."""
        success, output, _ = self.run_nlp_command("create project test using aider at /tmp/test")
        assert success
        self._assert_dsl_match(output, "project add")

    def test_remove_project(self):
        """E2E: Remove project via NLP."""
        success, output, _ = self.run_nlp_command("remove project oldproject")
        assert success
        self._assert_dsl_match(output, "project remove")

    # ── VM Tests ─────────────────────────────────────────────────────────────────

    def test_create_vm(self):
        """E2E: Create VM via NLP."""
        success, output, _ = self.run_nlp_command("create vm aider for myproject")
        assert success
        self._assert_dsl_match(output, "vm create")

    def test_start_vm(self):
        """E2E: Start VM via NLP."""
        success, output, _ = self.run_nlp_command("start vm-12345")
        assert success
        self._assert_dsl_match(output, "vm start")

    def test_stop_vm(self):
        """E2E: Stop VM via NLP."""
        success, output, _ = self.run_nlp_command("stop vm-12345")
        assert success
        self._assert_dsl_match(output, "vm stop")

    def test_restart_vm(self):
        """E2E: Restart VM via NLP."""
        success, output, _ = self.run_nlp_command("restart vm-12345")
        assert success
        self._assert_dsl_match(output, "vm restart")

    def test_delete_vm(self):
        """E2E: Delete VM via NLP."""
        success, output, _ = self.run_nlp_command("delete vm-12345")
        assert success
        self._assert_dsl_match(output, "vm delete")

    def test_snapshot_vm(self):
        """E2E: Snapshot VM via NLP."""
        success, output, _ = self.run_nlp_command("snapshot vm-12345 as backup")
        assert success
        self._assert_dsl_match(output, "vm snapshot")

    # ── Batch Tests ─────────────────────────────────────────────────────────────

    def test_dispatch_all_tickets(self):
        """E2E: Dispatch all tickets for project via NLP."""
        success, output, _ = self.run_nlp_command("dispatch all tickets for myproject")
        assert success
        self._assert_dsl_match(output, "dispatch --all")
        assert "myproject" in output

    def test_run_task_on_project(self):
        """E2E: Run task on project via NLP."""
        success, output, _ = self.run_nlp_command("run fix bug on myproject")
        assert success
        self._assert_dsl_match(output, "run")

    # ── Polish Language Tests ────────────────────────────────────────────────────

    def test_polish_create_ticket(self):
        """E2E: Create ticket in Polish via NLP."""
        success, output, _ = self.run_nlp_command("utwórz ticket dla napraw błąd")
        assert success
        self._assert_dsl_match(output, "ticket add")

    def test_polish_create_sprint(self):
        """E2E: Create sprint in Polish via NLP."""
        success, output, _ = self.run_nlp_command("utwórz sprint Sprint1")
        assert success
        self._assert_dsl_match(output, "sprint create")

    def test_polish_register_project(self):
        """E2E: Register project in Polish via NLP."""
        success, output, _ = self.run_nlp_command("zarejestruj projekt mojapp w /tmp/mojapp")
        assert success
        self._assert_dsl_match(output, "project add")

    # ── Performance Tests ────────────────────────────────────────────────────────

    def test_nlp_response_time(self):
        """E2E: All NLP commands should respond quickly."""
        commands = [
            "create ticket for test",
            "list tickets",
            "show status",
            "dispatch TKT-12345",
        ]
        for cmd in commands:
            success, output, duration = self.run_nlp_command(cmd)
            assert success, f"Command failed: {cmd}"
            assert duration < 1000, f"Too slow: {cmd} took {duration}ms"

    def test_dsl_vs_llm_performance(self):
        """E2E: DSL should be much faster than LLM fallback."""
        # DSL command
        _, _, dsl_time = self.run_nlp_command("create ticket for test")

        # Unknown command (will try LLM and fail quickly)
        _, output, llm_time = self.run_nlp_command("something completely unknown")

        # DSL should be significantly faster
        assert dsl_time < llm_time, f"DSL ({dsl_time}ms) should be faster than LLM ({llm_time}ms)"


class TestDSLSchemaCoverage:
    """Tests for DSL schema completeness and coverage."""

    def test_dsl_has_all_command_types(self):
        """Verify DSL has patterns for all major command types."""
        from proxym.cli.dsl import DSLParser

        dsl = DSLParser()
        patterns = dsl.list_patterns()

        required_types = [
            "ticket_create", "ticket_assign", "ticket_close",
            "sprint_create", "sprint_start", "sprint_close",
            "project_register", "project_remove",
            "vm_create", "vm_start", "vm_stop",
            "batch_tickets", "run_workflow"
        ]

        pattern_names = [p["name"] for p in patterns]

        for required in required_types:
            assert required in pattern_names, f"Missing pattern: {required}"

    def test_dsl_has_query_patterns(self):
        """Verify DSL has query patterns."""
        from proxym.cli.dsl import DSLParser

        dsl = DSLParser()
        patterns = dsl.list_patterns()

        query_patterns = [p for p in patterns if p["type"] == "query"]
        assert len(query_patterns) > 0, "Should have query patterns"

        required_queries = ["status", "tickets", "projects", "vms"]
        query_names = [p["name"] for p in query_patterns]

        for required in required_queries:
            assert required in query_names, f"Missing query: {required}"

    def test_dsl_multilingual_support(self):
        """Verify DSL supports multiple languages."""
        from proxym.cli.dsl import DSLParser

        dsl = DSLParser()

        # English
        assert dsl.parse("create ticket for test") is not None
        assert dsl.parse("list tickets") is not None

        # Polish
        assert dsl.parse("utwórz ticket dla test") is not None
        assert dsl.parse("pokaż tickety") is not None


class TestNLPErrorHandling:
    """Tests for NLP error handling and edge cases."""

    def test_empty_prompt(self):
        """Handle empty prompt gracefully."""
        success, output, _ = TestNLPCommandsE2E.run_nlp_command("")
        assert not success or "No command" in output or "empty" in output.lower()

    def test_whitespace_only(self):
        """Handle whitespace-only prompt."""
        success, output, _ = TestNLPCommandsE2E.run_nlp_command("   ")
        # Should not crash
        assert "error" in output.lower() or "No command" in output or not success

    def test_special_characters(self):
        """Handle special characters in task description."""
        success, output, _ = TestNLPCommandsE2E.run_nlp_command("create ticket for fix bug @#$%")
        assert success
        assert "ticket add" in output

    def test_unicode_text(self):
        """Handle unicode text in task description."""
        success, output, _ = TestNLPCommandsE2E.run_nlp_command("create ticket for 修复登录错误")
        assert success
        assert "ticket add" in output

    def test_very_long_task(self):
        """Handle very long task descriptions."""
        long_task = "create ticket for " + "a" * 500
        success, output, _ = TestNLPCommandsE2E.run_nlp_command(long_task)
        # Should not crash, might truncate or handle gracefully
        assert "error" not in output.lower() or "ticket" in output.lower()


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
