"""Integration tests for Navari CLI commands against a running server.

Requires:
1. A running Navari server
2. Valid credentials (run `navari login <url>` first)

Run with: uv run pytest cli/tests/integration/test_cli_commands.py -v
"""

import json

import pytest
from navari_cli.cli import app
from typer.testing import CliRunner

runner = CliRunner()


@pytest.fixture
def _require_server(server_url):
    """Skip if no server configured."""


@pytest.mark.usefixtures("_require_server")
class TestVersion:
    """Verify `navari version` outputs version string."""

    def test_version(self):
        result = runner.invoke(app, ["version"])
        assert result.exit_code == 0
        assert "Navari CLI v" in result.output


@pytest.mark.usefixtures("_require_server")
class TestWhoami:
    """Verify `navari whoami` shows server and user."""

    def test_whoami(self):
        result = runner.invoke(app, ["whoami"])
        assert result.exit_code == 0
        assert "Server:" in result.output
        assert "User:" in result.output


@pytest.mark.usefixtures("_require_server")
class TestConversationCommands:
    """Conversation CRUD lifecycle."""

    def test_create_list_get_messages_delete(self):
        """Verifies:
        - whoami user matches conversation user_id
        - create with explicit title, list (JSON), get, messages, delete
        - deleted conversation returns "not found"
        """
        # Whoami — get current user for assertions
        result = runner.invoke(app, ["whoami"])
        assert result.exit_code == 0
        whoami_user = result.output.split("User:")[1].strip().split("\n")[0].strip()
        assert whoami_user, "Could not parse user from whoami output"

        # Create
        result = runner.invoke(app, ["conversations", "create", "--title", "CLI System Test", "--format", "json"])
        assert result.exit_code == 0
        conv = json.loads(result.output)
        conv_id = conv["id"]
        assert conv.get("user_id") == whoami_user, (
            f"Created conversation user mismatch: {conv.get('user_id')} != {whoami_user}"
        )

        # List (JSON, limit=5) — all returned conversations belong to current user
        result = runner.invoke(app, ["conversations", "list", "--limit", "5", "--format", "json"])
        assert result.exit_code == 0
        conversations = json.loads(result.output)
        assert any(c["id"] == conv_id for c in conversations), "Newly created conversation not in list"
        for c in conversations:
            assert c.get("user_id") == whoami_user, (
                f"Conversation {c['id']} belongs to {c.get('user_id')}, expected {whoami_user}"
            )

        # Get
        result = runner.invoke(app, ["conversations", "get", conv_id])
        assert result.exit_code == 0
        assert conv_id in result.output

        # Messages
        result = runner.invoke(app, ["conversations", "messages", conv_id])
        assert result.exit_code == 0

        # Delete
        result = runner.invoke(app, ["conversations", "delete", conv_id, "--yes"])
        assert result.exit_code == 0
        assert "Deleted" in result.output

        # Get deleted conversation should exit 1 with a clean "not found" message
        result = runner.invoke(app, ["conversations", "get", conv_id])
        assert result.exit_code == 1
        assert "not found" in result.output.lower()


@pytest.mark.usefixtures("_require_server")
class TestChatNewMessage:
    """Verify `navari chat --new -m` creates conversation with title derived from the message."""

    def test_chat_new_with_message_titles_from_message(self):
        """navari chat --new -m creates a conversation titled from the message."""
        result = runner.invoke(app, ["chat", "--new", "-m", ":test_10th_prime"])
        assert result.exit_code == 0
        assert "Created conversation: :test_10th_prime" in result.output


@pytest.mark.usefixtures("_require_server")
class TestFileCommands:
    """File operations and workspace download."""

    def test_upload_list_download_delete(self, tmp_path):
        """Verifies upload, list, download (content match), delete."""
        # Create conversation for file
        result = runner.invoke(app, ["conversations", "create", "--title", "CLI File Test", "--format", "json"])
        assert result.exit_code == 0
        conv = json.loads(result.output)
        conv_id = conv["id"]

        # Create test file
        test_content = "hello from CLI system test"
        test_file = tmp_path / "test.txt"
        test_file.write_text(test_content)

        # Upload
        result = runner.invoke(app, ["files", "upload", str(test_file), "--conversation", conv_id, "--format", "json"])
        assert result.exit_code == 0
        upload_result = json.loads(result.output)
        file_id = upload_result.get("id", upload_result.get("file_id"))

        # List files for conversation
        result = runner.invoke(app, ["files", "list", "--conversation", conv_id])
        assert result.exit_code == 0

        # Download
        download_path = tmp_path / "downloaded.txt"
        result = runner.invoke(app, ["files", "download", file_id, "--output", str(download_path)])
        assert result.exit_code == 0
        assert download_path.exists()
        assert download_path.read_text() == test_content

        # Delete file
        result = runner.invoke(app, ["files", "delete", file_id, "--yes"])
        assert result.exit_code == 0
        assert "Deleted" in result.output

    def test_workspace_download(self, tmp_path):
        """Verifies:
        - Auto-rename on `chat <id> -m` for untitled conversations
        - Workspace zip download after agent run
        """
        # Create conversation with default title (no --title → "New Conversation")
        result = runner.invoke(app, ["conversations", "create", "--format", "json"])
        assert result.exit_code == 0
        conv = json.loads(result.output)
        conv_id = conv["id"]
        assert conv["title"] == "New Conversation"

        # Run the fake model which creates workspace files; auto-renames conversation
        result = runner.invoke(app, ["chat", conv_id, "-m", ":test_10th_prime"])
        assert result.exit_code == 0

        # Verify auto-rename happened
        result = runner.invoke(app, ["conversations", "get", conv_id, "--format", "json"])
        assert result.exit_code == 0
        assert json.loads(result.output)["title"] == ":test_10th_prime"

        # Download workspace
        output_path = tmp_path / "workspace.zip"
        result = runner.invoke(app, ["files", "workspace", conv_id, "--output", str(output_path)])
        assert result.exit_code == 0
        assert output_path.exists()
        assert output_path.stat().st_size > 0


@pytest.mark.usefixtures("_require_server")
class TestRunCommands:
    """Run management commands."""

    def test_list_runs(self):
        result = runner.invoke(app, ["runs", "list"])
        assert result.exit_code == 0

    def test_run_status_no_active_run(self):
        """Test that runs status gives a clean error when no run is active."""
        result = runner.invoke(app, ["conversations", "create", "--title", "CLI Run Status Test", "--format", "json"])
        assert result.exit_code == 0
        conv = json.loads(result.output)
        conv_id = conv["id"]

        result = runner.invoke(app, ["runs", "status", conv_id])
        # No active run, so should exit 1 with a clean message
        assert result.exit_code == 1
        assert "no run" in result.output.lower() or "not found" in result.output.lower()
