"""Tests for vr open command."""

import json
import pytest
from pathlib import Path
from unittest.mock import patch, Mock

from typer.testing import CliRunner

from vr_cli.cli import app
from vr_cli.commands.open import open_cmd
from vr_cli.utils.agent_lock import load_agent_lock, AGENT_LOCK_FILE


runner = CliRunner()


class TestLoadAgentLock:
    """Tests for load_agent_lock function."""

    def test_load_existing_lock(self, temp_dir):
        """Should load existing agent.lock file."""
        voicerun_dir = temp_dir / ".voicerun"
        voicerun_dir.mkdir()
        lock_data = {"id": "agent-123", "functionId": "func-456"}
        (voicerun_dir / AGENT_LOCK_FILE).write_text(json.dumps(lock_data))

        result = load_agent_lock(voicerun_dir)
        assert result == lock_data

    def test_load_nonexistent_lock(self, temp_dir):
        """Should return None when lock file doesn't exist."""
        voicerun_dir = temp_dir / ".voicerun"
        voicerun_dir.mkdir()

        result = load_agent_lock(voicerun_dir)
        assert result is None

    def test_load_invalid_json(self, temp_dir):
        """Should return None for invalid JSON."""
        voicerun_dir = temp_dir / ".voicerun"
        voicerun_dir.mkdir()
        (voicerun_dir / AGENT_LOCK_FILE).write_text("not valid json {")

        with patch("vr_cli.commands.open.print_error"):
            result = load_agent_lock(voicerun_dir)
        assert result is None


class TestOpenCommand:
    """Tests for the open command."""

    def test_open_not_voicerun_project(self, temp_dir, monkeypatch):
        """Should fail when not in a voicerun project."""
        monkeypatch.chdir(temp_dir)

        with patch("vr_cli.commands.open.print_error"), \
             patch("vr_cli.commands.open.print_info"):
            result = runner.invoke(app, ["open"])

        assert result.exit_code != 0

    def test_open_no_lock_file(self, voicerun_project, monkeypatch):
        """Should fail when agent.lock doesn't exist."""
        monkeypatch.chdir(voicerun_project)

        with patch("vr_cli.commands.open.print_error"):
            result = runner.invoke(app, ["open"])

        assert result.exit_code != 0

    def test_open_with_lock_file(self, voicerun_project_with_lock, monkeypatch):
        """Should open browser with correct URL."""
        monkeypatch.chdir(voicerun_project_with_lock)

        with patch("vr_cli.commands.open.print_info"), \
             patch("vr_cli.commands.open.webbrowser") as mock_browser, \
             patch("vr_cli.commands.open.FRONTEND_URL", "https://app.example.com"):

            result = runner.invoke(app, ["open"])

        mock_browser.open.assert_called_once()
        url = mock_browser.open.call_args[0][0]
        assert "test-agent-id-123" in url
        assert "test-function-id-456" in url

    def test_open_url_includes_agent_id(self, voicerun_project_with_lock, monkeypatch):
        """Should include agent ID in URL."""
        monkeypatch.chdir(voicerun_project_with_lock)

        with patch("vr_cli.commands.open.print_info"), \
             patch("vr_cli.commands.open.webbrowser") as mock_browser, \
             patch("vr_cli.commands.open.FRONTEND_URL", "https://app.example.com"):

            runner.invoke(app, ["open"])

        url = mock_browser.open.call_args[0][0]
        assert "/agents/test-agent-id-123" in url

    def test_open_url_includes_function_id_as_param(self, voicerun_project_with_lock, monkeypatch):
        """Should include function ID as query parameter."""
        monkeypatch.chdir(voicerun_project_with_lock)

        with patch("vr_cli.commands.open.print_info"), \
             patch("vr_cli.commands.open.webbrowser") as mock_browser, \
             patch("vr_cli.commands.open.FRONTEND_URL", "https://app.example.com"):

            runner.invoke(app, ["open"])

        url = mock_browser.open.call_args[0][0]
        assert "f=test-function-id-456" in url

    def test_open_without_function_id(self, voicerun_project, monkeypatch):
        """Should work without function ID in lock file."""
        monkeypatch.chdir(voicerun_project)

        # Create lock file with only agent ID
        lock_data = {"id": "agent-only-id"}
        lock_path = voicerun_project / ".voicerun" / AGENT_LOCK_FILE
        lock_path.write_text(json.dumps(lock_data))

        with patch("vr_cli.commands.open.print_info"), \
             patch("vr_cli.commands.open.webbrowser") as mock_browser, \
             patch("vr_cli.commands.open.FRONTEND_URL", "https://app.example.com"):

            result = runner.invoke(app, ["open"])

        url = mock_browser.open.call_args[0][0]
        assert "agent-only-id" in url
        assert "f=" not in url  # No function ID parameter

    def test_open_missing_agent_id(self, voicerun_project, monkeypatch):
        """Should fail when agent ID is missing from lock file."""
        monkeypatch.chdir(voicerun_project)

        # Create lock file without agent ID
        lock_data = {"functionId": "func-only"}
        lock_path = voicerun_project / ".voicerun" / AGENT_LOCK_FILE
        lock_path.write_text(json.dumps(lock_data))

        with patch("vr_cli.commands.open.print_error"):
            result = runner.invoke(app, ["open"])

        assert result.exit_code != 0


class TestOpenCommandUrls:
    """Tests for URL construction in open command."""

    def test_open_uses_frontend_url(self, voicerun_project_with_lock, monkeypatch):
        """Should use configured FRONTEND_URL."""
        monkeypatch.chdir(voicerun_project_with_lock)

        with patch("vr_cli.commands.open.print_info"), \
             patch("vr_cli.commands.open.webbrowser") as mock_browser, \
             patch("vr_cli.commands.open.FRONTEND_URL", "https://custom.frontend.com"):

            runner.invoke(app, ["open"])

        url = mock_browser.open.call_args[0][0]
        assert url.startswith("https://custom.frontend.com")

    def test_open_url_format(self, voicerun_project_with_lock, monkeypatch):
        """Should construct URL in correct format."""
        monkeypatch.chdir(voicerun_project_with_lock)

        with patch("vr_cli.commands.open.print_info"), \
             patch("vr_cli.commands.open.webbrowser") as mock_browser, \
             patch("vr_cli.commands.open.FRONTEND_URL", "https://app.example.com"):

            runner.invoke(app, ["open"])

        url = mock_browser.open.call_args[0][0]
        expected_format = "https://app.example.com/agents/test-agent-id-123/function?f=test-function-id-456"
        assert url == expected_format


class TestOpenCommandEdgeCases:
    """Edge case tests for open command."""

    def test_open_empty_lock_file(self, voicerun_project, monkeypatch):
        """Should handle empty lock file."""
        monkeypatch.chdir(voicerun_project)

        lock_path = voicerun_project / ".voicerun" / AGENT_LOCK_FILE
        lock_path.write_text("{}")

        with patch("vr_cli.commands.open.print_error"):
            result = runner.invoke(app, ["open"])

        assert result.exit_code != 0

    def test_open_prints_url_before_opening(self, voicerun_project_with_lock, monkeypatch):
        """Should print URL before opening browser."""
        monkeypatch.chdir(voicerun_project_with_lock)

        with patch("vr_cli.commands.open.print_info") as mock_print_info, \
             patch("vr_cli.commands.open.webbrowser") as mock_browser, \
             patch("vr_cli.commands.open.FRONTEND_URL", "https://app.example.com"):

            runner.invoke(app, ["open"])

        # Verify print_info was called with the URL
        mock_print_info.assert_called_once()
        call_arg = mock_print_info.call_args[0][0]
        assert "Opening" in call_arg
