"""System-level integration tests for Navari CLI commands.

These tests invoke the CLI via typer's CliRunner, exercising cli.py
end-to-end 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/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:
    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:
    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:
    def test_create_list_get_messages_delete(self):
        # Create
        result = runner.invoke(app, ["--format", "json", "conversations", "create", "--title", "CLI System Test"])
        assert result.exit_code == 0
        conv = json.loads(result.output)
        conv_id = conv["id"]

        # List
        result = runner.invoke(app, ["conversations", "list", "--limit", "3"])
        assert result.exit_code == 0
        assert conv_id in result.output

        # 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 TestFileCommands:
    def test_upload_list_download_delete(self, tmp_path):
        # Create conversation for file
        result = runner.invoke(app, ["--format", "json", "conversations", "create", "--title", "CLI File Test"])
        assert result.exit_code == 0
        conv = json.loads(result.output)
        conv_id = conv["id"]

        try:
            # 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, ["--format", "json", "files", "upload", str(test_file), "--conversation", conv_id]
            )
            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
        finally:
            runner.invoke(app, ["conversations", "delete", conv_id, "--yes"])

    def test_workspace_download(self, tmp_path):
        """Test downloading workspace files as zip after an agent run creates files."""
        # Create conversation and run the fake model (it creates workspace files)
        result = runner.invoke(app, ["--format", "json", "conversations", "create", "--title", "CLI Workspace Test"])
        assert result.exit_code == 0
        conv = json.loads(result.output)
        conv_id = conv["id"]

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

            # 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
        finally:
            runner.invoke(app, ["conversations", "delete", conv_id, "--yes"])


@pytest.mark.usefixtures("_require_server")
class TestRunCommands:
    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, ["--format", "json", "conversations", "create", "--title", "CLI Run Status Test"])
        assert result.exit_code == 0
        conv = json.loads(result.output)
        conv_id = conv["id"]

        try:
            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()
        finally:
            runner.invoke(app, ["conversations", "delete", conv_id, "--yes"])
