"""Tests for CLI sync commands."""

import pytest
from click.testing import CliRunner
from unittest.mock import patch, MagicMock
from cheshire_cat_cli.cli import cli, sync


@pytest.fixture
def runner():
    """Fixture to create a Click CLI test runner."""
    return CliRunner()


@pytest.fixture
def mock_sync_manager():
    """Fixture to create a mock SyncManager."""
    with patch("cheshire_cat_cli.cli.SyncManager") as mock:
        yield mock


class TestSyncGroup:
    """Tests for the sync command group."""

    def test_sync_group_exists(self, runner):
        """Test that the sync group is accessible."""
        result = runner.invoke(cli, ["sync", "--help"])
        assert result.exit_code == 0
        assert "Manage cloud synchronization" in result.output

    def test_sync_shows_all_commands(self, runner):
        """Test that all sync commands are listed."""
        result = runner.invoke(cli, ["sync", "--help"])
        assert result.exit_code == 0
        assert "configure" in result.output
        assert "disable" in result.output
        assert "status" in result.output
        assert "now" in result.output


class TestSyncConfigure:
    """Tests for sync configure command."""

    @patch("cheshire_cat_cli.cli._ensure_app_directory")
    @patch("cheshire_cat_cli.cli.SyncManager")
    def test_configure_webdav_success(self, mock_manager_class, mock_ensure_dir, runner, tmp_path):
        """Test successful WebDAV configuration."""
        mock_ensure_dir.return_value = tmp_path
        mock_manager = MagicMock()
        mock_manager.configure.return_value = True
        mock_manager_class.return_value = mock_manager

        result = runner.invoke(
            cli,
            ["sync", "configure", "webdav"],
            input="https://example.com/dav\nuser\npass\n"
        )

        assert result.exit_code == 0
        assert "Successfully configured" in result.output
        mock_manager.configure.assert_called_once()

    @patch("cheshire_cat_cli.cli._ensure_app_directory")
    @patch("cheshire_cat_cli.cli.SyncManager")
    def test_configure_webdav_failure(self, mock_manager_class, mock_ensure_dir, runner, tmp_path):
        """Test failed WebDAV configuration."""
        mock_ensure_dir.return_value = tmp_path
        mock_manager = MagicMock()
        mock_manager.configure.return_value = False
        mock_manager_class.return_value = mock_manager

        result = runner.invoke(
            cli,
            ["sync", "configure", "webdav"],
            input="https://example.com/dav\nuser\npass\n"
        )

        assert result.exit_code == 1
        assert "Failed to configure" in result.output

    @patch("cheshire_cat_cli.cli._ensure_app_directory")
    @patch("cheshire_cat_cli.cli.SyncManager")
    def test_configure_with_options(self, mock_manager_class, mock_ensure_dir, runner, tmp_path):
        """Test configuration with command-line options."""
        mock_ensure_dir.return_value = tmp_path
        mock_manager = MagicMock()
        mock_manager.configure.return_value = True
        mock_manager_class.return_value = mock_manager

        result = runner.invoke(
            cli,
            [
                "sync", "configure", "webdav",
                "--url", "https://example.com/dav",
                "--username", "testuser",
                "--password", "testpass",
                "--remote-path", "/backup"
            ]
        )

        assert result.exit_code == 0
        assert "Successfully configured" in result.output


class TestSyncDisable:
    """Tests for sync disable command."""

    @patch("cheshire_cat_cli.cli._ensure_app_directory")
    @patch("cheshire_cat_cli.cli.SyncManager")
    def test_disable(self, mock_manager_class, mock_ensure_dir, runner, tmp_path):
        """Test disabling sync."""
        mock_ensure_dir.return_value = tmp_path
        mock_manager = MagicMock()
        mock_manager_class.return_value = mock_manager

        result = runner.invoke(cli, ["sync", "disable"])

        assert result.exit_code == 0
        assert "disabled" in result.output
        mock_manager.disable.assert_called_once()


class TestSyncStatus:
    """Tests for sync status command."""

    @patch("cheshire_cat_cli.cli._ensure_app_directory")
    @patch("cheshire_cat_cli.cli.SyncManager")
    def test_status_disabled(self, mock_manager_class, mock_ensure_dir, runner, tmp_path):
        """Test status when sync is disabled."""
        mock_ensure_dir.return_value = tmp_path
        mock_manager = MagicMock()
        mock_manager.get_config_info.return_value = {"enabled": False}
        mock_manager_class.return_value = mock_manager

        result = runner.invoke(cli, ["sync", "status"])

        assert result.exit_code == 0
        assert "DISABLED" in result.output

    @patch("cheshire_cat_cli.cli._ensure_app_directory")
    @patch("cheshire_cat_cli.cli.SyncManager")
    def test_status_enabled(self, mock_manager_class, mock_ensure_dir, runner, tmp_path):
        """Test status when sync is enabled."""
        mock_ensure_dir.return_value = tmp_path
        mock_manager = MagicMock()
        mock_manager.get_config_info.return_value = {
            "enabled": True,
            "provider": "webdav",
            "config": {
                "url": "https://example.com",
                "username": "user",
                "password": "***"
            }
        }
        mock_manager_class.return_value = mock_manager

        result = runner.invoke(cli, ["sync", "status"])

        assert result.exit_code == 0
        assert "ENABLED" in result.output
        assert "webdav" in result.output


class TestSyncNow:
    """Tests for sync now command."""

    @patch("cheshire_cat_cli.cli._ensure_app_directory")
    @patch("cheshire_cat_cli.cli.SyncManager")
    def test_sync_now_not_enabled(self, mock_manager_class, mock_ensure_dir, runner, tmp_path):
        """Test manual sync when not enabled."""
        mock_ensure_dir.return_value = tmp_path
        mock_manager = MagicMock()
        mock_manager.is_enabled.return_value = False
        mock_manager_class.return_value = mock_manager

        result = runner.invoke(cli, ["sync", "now"])

        assert result.exit_code == 1
        assert "not enabled" in result.output

    @patch("cheshire_cat_cli.cli._ensure_app_directory")
    @patch("cheshire_cat_cli.cli.SyncManager")
    def test_sync_now_success(self, mock_manager_class, mock_ensure_dir, runner, tmp_path):
        """Test successful manual sync."""
        mock_ensure_dir.return_value = tmp_path
        mock_manager = MagicMock()
        mock_manager.is_enabled.return_value = True
        mock_manager.sync.return_value = True
        mock_manager_class.return_value = mock_manager

        result = runner.invoke(cli, ["sync", "now"])

        assert result.exit_code == 0
        assert "completed successfully" in result.output

    @patch("cheshire_cat_cli.cli._ensure_app_directory")
    @patch("cheshire_cat_cli.cli.SyncManager")
    def test_sync_now_failure(self, mock_manager_class, mock_ensure_dir, runner, tmp_path):
        """Test failed manual sync."""
        mock_ensure_dir.return_value = tmp_path
        mock_manager = MagicMock()
        mock_manager.is_enabled.return_value = True
        mock_manager.sync.return_value = False
        mock_manager_class.return_value = mock_manager

        result = runner.invoke(cli, ["sync", "now"])

        assert result.exit_code == 1
        assert "failed" in result.output


class TestStartStopWithSync:
    """Tests for start/stop commands with sync integration."""

    @patch("cheshire_cat_cli.cli.docker.check_docker_availability")
    @patch("cheshire_cat_cli.cli.os.execvp")
    @patch("cheshire_cat_cli.cli.os.chdir")
    @patch("cheshire_cat_cli.cli._ensure_app_directory")
    @patch("cheshire_cat_cli.cli.SyncManager")
    def test_start_with_sync_disabled(
        self, mock_manager_class, mock_ensure_dir, mock_chdir, mock_execvp, mock_docker, runner, tmp_path
    ):
        """Test start command when sync is disabled."""
        mock_ensure_dir.return_value = tmp_path
        mock_docker.return_value = (True, "")
        mock_manager = MagicMock()
        mock_manager.is_enabled.return_value = False
        mock_manager_class.return_value = mock_manager

        result = runner.invoke(cli, ["start"])

        # Should not call sync
        mock_manager.sync.assert_not_called()

    @patch("cheshire_cat_cli.cli.docker.check_docker_availability")
    @patch("cheshire_cat_cli.cli.os.execvp")
    @patch("cheshire_cat_cli.cli.os.chdir")
    @patch("cheshire_cat_cli.cli._ensure_app_directory")
    @patch("cheshire_cat_cli.cli.SyncManager")
    def test_start_with_sync_enabled(
        self, mock_manager_class, mock_ensure_dir, mock_chdir, mock_execvp, mock_docker, runner, tmp_path
    ):
        """Test start command when sync is enabled."""
        mock_ensure_dir.return_value = tmp_path
        mock_docker.return_value = (True, "")
        mock_manager = MagicMock()
        mock_manager.is_enabled.return_value = True
        mock_manager.sync.return_value = True
        mock_manager_class.return_value = mock_manager

        result = runner.invoke(cli, ["start"])

        # Should call sync
        mock_manager.sync.assert_called_once()

    @patch("cheshire_cat_cli.cli.docker.check_docker_availability")
    @patch("cheshire_cat_cli.cli.os.execvp")
    @patch("cheshire_cat_cli.cli.os.chdir")
    @patch("cheshire_cat_cli.cli._ensure_app_directory")
    @patch("cheshire_cat_cli.cli.SyncManager")
    def test_start_with_no_sync_flag(
        self, mock_manager_class, mock_ensure_dir, mock_chdir, mock_execvp, mock_docker, runner, tmp_path
    ):
        """Test start command with --no-sync flag."""
        mock_ensure_dir.return_value = tmp_path
        mock_docker.return_value = (True, "")
        mock_manager = MagicMock()
        mock_manager.is_enabled.return_value = True
        mock_manager_class.return_value = mock_manager

        result = runner.invoke(cli, ["start", "--no-sync"])

        # Should not call sync even if enabled
        mock_manager.sync.assert_not_called()

    @patch("cheshire_cat_cli.cli.docker.check_docker_availability")
    @patch("cheshire_cat_cli.cli.subprocess.run")
    @patch("cheshire_cat_cli.cli.os.chdir")
    @patch("cheshire_cat_cli.cli._ensure_app_directory")
    @patch("cheshire_cat_cli.cli.SyncManager")
    def test_stop_with_sync_enabled(
        self, mock_manager_class, mock_ensure_dir, mock_chdir, mock_subprocess, mock_docker, runner, tmp_path
    ):
        """Test stop command when sync is enabled."""
        mock_ensure_dir.return_value = tmp_path
        mock_docker.return_value = (True, "")
        mock_result = MagicMock()
        mock_result.returncode = 0
        mock_subprocess.return_value = mock_result
        mock_manager = MagicMock()
        mock_manager.is_enabled.return_value = True
        mock_manager.sync.return_value = True
        mock_manager_class.return_value = mock_manager

        result = runner.invoke(cli, ["stop"])

        # Should call sync after stopping
        mock_manager.sync.assert_called_once()
        assert "sync completed" in result.output
