"""Tests for the sync command."""

import importlib
import json
from pathlib import Path
from unittest.mock import patch, MagicMock

import pytest
import yaml
from click.testing import CliRunner

sync_module = importlib.import_module("gjalla_precommit.commands.sync")
cli_module = importlib.import_module("gjalla_precommit.cli")
settings_module = importlib.import_module("gjalla_precommit.config.settings")


class TestSyncCommand:
    """Tests for gjalla sync command."""

    def test_sync_command_exists(self):
        """Sync command should be registered."""
        main = cli_module.main
        assert "sync" in main.commands

    def test_sync_not_in_git_repo(self, tmp_path, monkeypatch):
        """Sync should fail when not in a git repo."""
        monkeypatch.chdir(tmp_path)
        runner = CliRunner()
        result = runner.invoke(cli_module.main, ["sync"])
        assert result.exit_code != 0
        assert "Not in a git repository" in result.output or "git repository" in result.output.lower()

    def test_sync_no_api_key(self, temp_repo, home_dir, monkeypatch):
        """Sync should fail when API key is not configured."""
        monkeypatch.chdir(temp_repo)
        monkeypatch.delenv("GJALLA_API_KEY", raising=False)
        runner = CliRunner()
        result = runner.invoke(cli_module.main, ["sync"])
        assert result.exit_code != 0
        assert "API key" in result.output or "not configured" in result.output.lower()

    def test_sync_no_gjalla_config_skips_gracefully(self, temp_repo, home_dir, monkeypatch):
        """Sync should succeed with info message when no .gjalla config exists."""
        monkeypatch.chdir(temp_repo)
        # Set API key but no .gjalla project config
        config_dir = home_dir / ".gjalla"
        config_dir.mkdir(parents=True, exist_ok=True)
        (config_dir / "config.yaml").write_text("api_key: gj_test_key\n")

        runner = CliRunner()
        result = runner.invoke(cli_module.main, ["sync"])
        assert result.exit_code == 0
        assert "No .gjalla config" in result.output or "skipping" in result.output.lower()

    def test_sync_help_flag(self):
        """Sync --help should show help text."""
        runner = CliRunner()
        result = runner.invoke(cli_module.main, ["sync", "--help"])
        assert result.exit_code == 0
        assert "attestation" in result.output.lower() or "upload" in result.output.lower()


class TestGetRepoRoot:
    """Tests for _get_repo_root helper."""

    def test_get_repo_root_finds_git_dir(self, temp_repo, monkeypatch):
        """Should find .git directory in current or parent dirs."""
        # Create a subdirectory
        subdir = temp_repo / "src" / "nested"
        subdir.mkdir(parents=True)
        monkeypatch.chdir(subdir)

        # Should still find repo root
        root = sync_module.get_repo_root()
        assert root == temp_repo

    def test_get_repo_root_raises_not_in_repo(self, tmp_path, monkeypatch):
        """Should raise ClickException when not in a repo."""
        monkeypatch.chdir(tmp_path)
        import click
        with pytest.raises(click.ClickException, match="Not in a git repository"):
            sync_module.get_repo_root()


class TestSyncLocalKeyResolution:
    """Tests for local API key resolution in sync command."""

    def test_sync_uses_local_api_key_env(self, temp_repo, home_dir, monkeypatch):
        """Sync uses api_key_env from .gjalla/config.yaml over global config."""
        monkeypatch.chdir(temp_repo)
        monkeypatch.delenv("GJALLA_API_KEY", raising=False)
        monkeypatch.setenv("MY_PROJECT_KEY", "gj_local_key")

        # Local config with api_key_env reference
        gjalla_dir = temp_repo / ".gjalla"
        gjalla_dir.mkdir(parents=True, exist_ok=True)
        (gjalla_dir / "config.yaml").write_text(yaml.dump({
            "project_id": 42,
            "api_url": "https://gjalla.io",
            "api_key_env": "MY_PROJECT_KEY",
        }, default_flow_style=False))

        # Global config has a different key
        config_dir = home_dir / ".gjalla"
        config_dir.mkdir(parents=True, exist_ok=True)
        (config_dir / "config.yaml").write_text("api_key: gj_global_key\n")

        runner = CliRunner()
        with patch.object(sync_module, "_upload_attestations") as mock_upload, \
             patch.object(sync_module, "_refresh_context_cache"):
            result = runner.invoke(cli_module.main, ["sync"])

        assert result.exit_code == 0, result.output
        # The settings passed to _upload_attestations should have the local key
        settings_used = mock_upload.call_args[0][0]
        assert settings_used.api_key == "gj_local_key"

    def test_sync_falls_back_to_global_when_no_local(self, temp_repo, home_dir, monkeypatch):
        """Sync uses global config when no local api_key_env is available."""
        monkeypatch.chdir(temp_repo)
        monkeypatch.delenv("GJALLA_API_KEY", raising=False)

        # No .gjalla/config.json
        config_dir = home_dir / ".gjalla"
        config_dir.mkdir(parents=True, exist_ok=True)
        (config_dir / "config.yaml").write_text("api_key: gj_global_key\n")

        runner = CliRunner()
        with patch.object(sync_module, "_upload_attestations") as mock_upload, \
             patch.object(sync_module, "_refresh_context_cache"):
            result = runner.invoke(cli_module.main, ["sync"])

        assert result.exit_code == 0, result.output
        settings_used = mock_upload.call_args[0][0]
        assert settings_used.api_key == "gj_global_key"

    def test_sync_local_key_env_unset_falls_back(self, temp_repo, home_dir, monkeypatch):
        """Sync falls back to global config when api_key_env points to unset var."""
        monkeypatch.chdir(temp_repo)
        monkeypatch.delenv("GJALLA_API_KEY", raising=False)
        monkeypatch.delenv("UNSET_VAR", raising=False)

        gjalla_dir = temp_repo / ".gjalla"
        gjalla_dir.mkdir(parents=True, exist_ok=True)
        (gjalla_dir / "config.yaml").write_text(yaml.dump({
            "project_id": 42,
            "api_url": "https://gjalla.io",
            "api_key_env": "UNSET_VAR",
        }, default_flow_style=False))

        config_dir = home_dir / ".gjalla"
        config_dir.mkdir(parents=True, exist_ok=True)
        (config_dir / "config.yaml").write_text("api_key: gj_global_key\n")

        runner = CliRunner()
        with patch.object(sync_module, "_upload_attestations") as mock_upload, \
             patch.object(sync_module, "_refresh_context_cache"):
            result = runner.invoke(cli_module.main, ["sync"])

        assert result.exit_code == 0, result.output
        settings_used = mock_upload.call_args[0][0]
        assert settings_used.api_key == "gj_global_key"
