"""Test site points command."""

from unittest.mock import Mock, patch

import click
import pytest
from click.testing import CliRunner

from aceiot_models_cli.commands.site import SitePointsCommand
from aceiot_models_cli.repl.context import ContextType, ReplContext


@pytest.fixture
def mock_context():
    """Create a mock REPL context."""
    context = ReplContext()
    context.enter_context(ContextType.SITE, "test-site")
    return context


def test_site_points_command_basic(mock_context):
    """Test basic site points command."""
    # Create command instance
    cmd = SitePointsCommand()
    cmd.context = mock_context

    # Create mock API client
    mock_client = Mock()
    mock_client.get_site_points.return_value = {
        "items": [
            {
                "name": "point1",
                "display_name": "Point 1",
                "description": "Test point 1",
                "type": "analog",
                "equipment": "AHU-1",
            },
            {
                "name": "point2",
                "display_name": "Point 2",
                "description": "Test point 2",
                "type": "binary",
                "equipment": "VAV-1",
            },
        ],
        "total": 2,
        "page": 1,
        "per_page": 10,
    }

    # Create Click context with mock client
    ctx = click.Context(click.Command("test"))
    ctx.obj = {"client": mock_client}

    # Get the actual command
    site_points_cmd = cmd.get_click_command()

    # Test command execution
    runner = CliRunner()
    with patch.object(cmd, "require_api_client", return_value=mock_client):
        with patch.object(cmd, "format_output") as mock_format:
            result = runner.invoke(
                site_points_cmd,
                [],
                obj={"client": mock_client},
                parent=ctx,
            )

            assert result.exit_code == 0
            mock_client.get_site_points.assert_called_once_with("test-site", page=1, per_page=10)
            mock_format.assert_called_once()


def test_site_points_command_with_search(mock_context):
    """Test site points command with search filter."""
    cmd = SitePointsCommand()
    cmd.context = mock_context

    mock_client = Mock()
    mock_client.get_site_points.return_value = {
        "items": [
            {
                "name": "temp_sensor_1",
                "display_name": "Temperature Sensor 1",
                "description": "Zone temperature",
                "type": "analog",
            },
            {
                "name": "humidity_sensor",
                "display_name": "Humidity Sensor",
                "description": "Zone humidity",
                "type": "analog",
            },
            {
                "name": "pressure_sensor",
                "display_name": "Pressure Sensor",
                "description": "Duct pressure",
                "type": "analog",
            },
        ],
        "total": 3,
    }

    ctx = click.Context(click.Command("test"))
    ctx.obj = {"client": mock_client}

    site_points_cmd = cmd.get_click_command()
    runner = CliRunner()

    with patch.object(cmd, "require_api_client", return_value=mock_client):
        with patch.object(cmd, "format_output") as mock_format:
            result = runner.invoke(
                site_points_cmd,
                ["--search", "temperature"],
                obj={"client": mock_client},
                parent=ctx,
            )

            assert result.exit_code == 0
            # Check that only temperature-related points are in the filtered result
            call_args = mock_format.call_args
            filtered_result = call_args[0][0]
            assert len(filtered_result["items"]) == 1
            assert filtered_result["items"][0]["name"] == "temp_sensor_1"


def test_site_points_command_with_equipment_filter(mock_context):
    """Test site points command with equipment filter."""
    cmd = SitePointsCommand()
    cmd.context = mock_context

    mock_client = Mock()
    mock_client.get_site_points.return_value = {
        "items": [
            {"name": "point1", "equipment": "AHU-1"},
            {"name": "point2", "equipment": "AHU-2"},
            {"name": "point3", "equipment": "VAV-1"},
        ],
        "total": 3,
    }

    ctx = click.Context(click.Command("test"))
    ctx.obj = {"client": mock_client}

    site_points_cmd = cmd.get_click_command()
    runner = CliRunner()

    with patch.object(cmd, "require_api_client", return_value=mock_client):
        with patch.object(cmd, "format_output") as mock_format:
            result = runner.invoke(
                site_points_cmd,
                ["--equipment", "AHU"],
                obj={"client": mock_client},
                parent=ctx,
            )

            assert result.exit_code == 0
            # Check that only AHU points are in the filtered result
            call_args = mock_format.call_args
            filtered_result = call_args[0][0]
            assert len(filtered_result["items"]) == 2
            assert all("AHU" in item["equipment"] for item in filtered_result["items"])


def test_site_points_command_with_type_filter(mock_context):
    """Test site points command with type filter."""
    cmd = SitePointsCommand()
    cmd.context = mock_context

    mock_client = Mock()
    mock_client.get_site_points.return_value = {
        "items": [
            {"name": "point1", "type": "analog"},
            {"name": "point2", "type": "binary"},
            {"name": "point3", "type": "analog"},
        ],
        "total": 3,
    }

    ctx = click.Context(click.Command("test"))
    ctx.obj = {"client": mock_client}

    site_points_cmd = cmd.get_click_command()
    runner = CliRunner()

    with patch.object(cmd, "require_api_client", return_value=mock_client):
        with patch.object(cmd, "format_output") as mock_format:
            result = runner.invoke(
                site_points_cmd,
                ["--type", "analog"],
                obj={"client": mock_client},
                parent=ctx,
            )

            assert result.exit_code == 0
            # Check that only analog points are in the filtered result
            call_args = mock_format.call_args
            filtered_result = call_args[0][0]
            assert len(filtered_result["items"]) == 2
            assert all(item["type"] == "analog" for item in filtered_result["items"])


def test_site_points_command_no_context():
    """Test site points command without site context."""
    cmd = SitePointsCommand()
    cmd.context = ReplContext()  # Empty context

    ctx = click.Context(click.Command("test"))
    ctx.obj = {}

    site_points_cmd = cmd.get_click_command()
    runner = CliRunner()

    result = runner.invoke(site_points_cmd, [], obj={}, parent=ctx)

    assert result.exit_code == 1
    assert "No site context set" in result.output