"""
Tests for proxy CLI commands (setup, dashboard, quickstart).
"""

import json
import os
import sys
from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest

from kvict.cli import proxy_dashboard, proxy_quickstart, proxy_setup


class TestProxySetup:
    """Test proxy setup command."""

    @patch("kvict.cli.getpass")
    @patch("kvict.cli.input")
    @patch("kvict.cli.store_api_key")
    @patch("kvict.cli.Path.home")
    def test_setup_wizard_success(
        self, mock_home, mock_store, mock_input, mock_getpass
    ):
        """Test successful setup wizard flow."""
        # Setup mocks
        mock_home.return_value = Path("/home/test")
        mock_store.return_value = True
        mock_getpass.return_value = "sk-test123456789"
        mock_input.side_effect = ["1", "8080", "y"]  # provider, port, dashboard

        # Create temporary config directory
        config_dir = Path("/home/test/.kvict")
        config_dir.mkdir(parents=True, exist_ok=True)

        # Run setup
        args = MagicMock()
        result = proxy_setup(args)

        # Verify
        assert result == 0
        mock_store.assert_called_once_with("kvict", "sk-test123456789")
        assert (config_dir / "config.json").exists()

        # Verify config contents
        with open(config_dir / "config.json") as f:
            config = json.load(f)
            assert config["provider"] == "openai"
            assert config["port"] == 8080
            assert config["dashboard_enabled"] is True
            assert config["dashboard_port"] == 3000

    @patch("kvict.cli.getpass")
    @patch("kvict.cli.store_api_key")
    def test_setup_invalid_api_key(self, mock_store, mock_getpass):
        """Test setup with invalid API key."""
        mock_getpass.return_value = "invalid-key"
        args = MagicMock()

        result = proxy_setup(args)

        assert result == 1
        mock_store.assert_not_called()

    @patch("kvict.cli.getpass")
    @patch("kvict.cli.input")
    @patch("kvict.cli.store_api_key")
    @patch("kvict.cli.Path.home")
    def test_setup_invalid_port(self, mock_home, mock_store, mock_input, mock_getpass):
        """Test setup with invalid port."""
        mock_home.return_value = Path("/home/test")
        mock_store.return_value = True
        mock_getpass.return_value = "sk-test123"
        mock_input.side_effect = ["1", "invalid", "y"]

        args = MagicMock()
        result = proxy_setup(args)

        assert result == 1

    @patch("kvict.cli.getpass")
    @patch("kvict.cli.input")
    @patch("kvict.cli.store_api_key")
    @patch("kvict.cli.Path.home")
    def test_setup_port_out_of_range(
        self, mock_home, mock_store, mock_input, mock_getpass
    ):
        """Test setup with port out of valid range."""
        mock_home.return_value = Path("/home/test")
        mock_store.return_value = True
        mock_getpass.return_value = "sk-test123"
        mock_input.side_effect = ["1", "100", "y"]  # Port < 1024

        args = MagicMock()
        result = proxy_setup(args)

        assert result == 1


class TestProxyDashboard:
    """Test proxy dashboard command."""

    @patch("kvict.cli.Path.home")
    def test_dashboard_with_config(self, mock_home):
        """Test dashboard with existing config."""
        mock_home.return_value = Path("/home/test")
        config_dir = Path("/home/test/.kvict")
        config_dir.mkdir(parents=True, exist_ok=True)
        config_file = config_dir / "config.json"
        config_file.write_text(json.dumps({"dashboard_port": 3001, "port": 8080}))

        # Mock uvicorn module
        mock_uvicorn = MagicMock()
        with patch.dict(sys.modules, {"uvicorn": mock_uvicorn}):
            args = MagicMock()
            args.port = None
            args.proxy_port = None
            result = proxy_dashboard(args)

        assert result == 0
        mock_uvicorn.run.assert_called_once()
        call_args = mock_uvicorn.run.call_args
        assert call_args[1]["port"] == 3001
        assert call_args[1]["host"] == "127.0.0.1"

    @patch("kvict.cli.Path.home")
    def test_dashboard_without_config(self, mock_home):
        """Test dashboard without config file."""
        mock_home.return_value = Path("/home/test")
        config_dir = Path("/home/test/.kvict")
        if config_dir.exists():
            # Remove config if it exists
            config_file = config_dir / "config.json"
            if config_file.exists():
                config_file.unlink()

        # Mock uvicorn module
        mock_uvicorn = MagicMock()
        with patch.dict(sys.modules, {"uvicorn": mock_uvicorn}):
            args = MagicMock()
            args.port = None
            args.proxy_port = None
            result = proxy_dashboard(args)

        assert result == 0
        mock_uvicorn.run.assert_called_once()
        call_args = mock_uvicorn.run.call_args
        assert call_args[1]["port"] == 3000  # Default

    @patch("builtins.__import__")
    def test_dashboard_import_error(self, mock_import):
        """Test dashboard when uvicorn is not available."""
        # Make uvicorn import raise ImportError
        original_import = __import__

        def import_side_effect(name, *args, **kwargs):
            if name == "uvicorn":
                raise ImportError("No module named 'uvicorn'")
            return original_import(name, *args, **kwargs)

        mock_import.side_effect = import_side_effect

        args = MagicMock()
        args.port = None
        args.proxy_port = None
        result = proxy_dashboard(args)
        assert result == 1


class TestProxyQuickstart:
    """Test proxy quickstart command."""

    @patch("kvict.cli.getpass")
    @patch("kvict.cli.input")
    @patch("kvict.cli.store_api_key")
    @patch("kvict.cli.get_api_key")
    @patch("kvict.cli.Path.home")
    def test_quickstart_without_config(
        self, mock_home, mock_get_key, mock_store, mock_input, mock_getpass
    ):
        """Test quickstart when not configured."""
        mock_home.return_value = Path("/home/test")
        config_dir = Path("/home/test/.kvict")
        config_dir.mkdir(parents=True, exist_ok=True)
        if (config_dir / "config.json").exists():
            (config_dir / "config.json").unlink()

        # First call returns None (no key), subsequent calls return key after setup
        call_count = [0]

        def get_key_side_effect(*args):
            call_count[0] += 1
            if call_count[0] == 1:
                return None  # First check - no key
            # After setup, return key
            return "sk-test123"

        mock_get_key.side_effect = get_key_side_effect
        mock_store.return_value = True
        mock_getpass.return_value = "sk-test123"
        mock_input.side_effect = ["1", "8080", "y"]

        args = MagicMock()
        result = proxy_quickstart(args)

        assert result == 0
        # Verify config was created
        assert (config_dir / "config.json").exists()

    @patch("kvict.cli.get_api_key")
    @patch("kvict.cli.Path.home")
    def test_quickstart_with_config(self, mock_home, mock_get_key):
        """Test quickstart with existing config."""
        mock_home.return_value = Path("/home/test")
        config_dir = Path("/home/test/.kvict")
        config_dir.mkdir(parents=True, exist_ok=True)
        config_file = config_dir / "config.json"
        config_file.write_text(json.dumps({"port": 8080, "dashboard_port": 3000}))

        mock_get_key.return_value = "sk-test123"

        args = MagicMock()
        result = proxy_quickstart(args)

        assert result == 0

    @patch("kvict.cli.getpass")
    @patch("kvict.cli.input")
    @patch("kvict.cli.store_api_key")
    @patch("kvict.cli.get_api_key")
    @patch("kvict.cli.Path.home")
    def test_quickstart_no_api_key(
        self, mock_home, mock_get_key, mock_store, mock_input, mock_getpass
    ):
        """Test quickstart when API key is missing."""
        mock_home.return_value = Path("/home/test")
        config_dir = Path("/home/test/.kvict")
        config_dir.mkdir(parents=True, exist_ok=True)
        config_file = config_dir / "config.json"
        config_file.write_text(json.dumps({"port": 8080}))

        # Always return None for API key (even after setup attempt)
        mock_get_key.return_value = None
        mock_getpass.return_value = ""  # Empty key will fail validation
        mock_input.side_effect = ["1", "8080", "y"]
        mock_store.return_value = True

        args = MagicMock()
        result = proxy_quickstart(args)

        assert result == 1
