"""Tests for the config module."""
import json
import os
import tempfile
from pathlib import Path
from unittest.mock import patch, mock_open

import pytest

from pytest_cream.config import (
    get_config_path,
    load_config,
    save_config,
    set_last_workspace,
    get_last_workspace,
    resolve_workspace,
    resolve_python_executable,
    clear_config,
)


@pytest.fixture
def temp_home(tmp_path):
    """Create a temporary home directory for testing."""
@pytest.fixture
def temp_cwd(tmp_path, monkeypatch):
    """Create a temporary current working directory for testing."""
    temp_dir = tmp_path / "test_cwd"
    temp_dir.mkdir()
    monkeypatch.chdir(temp_dir)
    yield temp_dir


@pytest.fixture
def clean_config(temp_cwd):
    """Ensure clean config before and after each test."""
    config_path = temp_cwd / ".pytest-cream.json"
    if config_path.exists():
        config_path.unlink()
    yield
    if config_path.exists():
        config_path.unlink()


class TestConfigPath:
    """Tests for get_config_path function."""
    
    def test_get_config_path(self, temp_cwd):
        """Test that config path points to current working directory."""
        config_path = get_config_path()
        assert config_path == temp_cwd / ".pytest-cream.json"


class TestLoadSaveConfig:
    """Tests for load_config and save_config functions."""
    
    def test_load_config_empty_when_no_file(self, temp_cwd, clean_config):
        """Test loading config when file doesn't exist returns empty dict."""
        config = load_config()
        assert config == {}
    
    def test_save_and_load_config(self, temp_cwd, clean_config):
        """Test saving and loading config data."""
        test_data = {
            "last_workspace": {
                "path": "/test/workspace",
                "repo": "owner/repo",
                "branch": "main"
            }
        }
        
        save_config(test_data)
        loaded = load_config()
        
        assert loaded == test_data
    
    def test_load_config_handles_invalid_json(self, temp_cwd, clean_config):
        """Test that invalid JSON returns empty dict."""
        config_path = get_config_path()
        config_path.write_text("invalid json {")
        
        config = load_config()
        assert config == {}
    
    def test_save_config_creates_file(self, temp_cwd, clean_config):
        """Test that save_config creates the config file."""
        config_path = get_config_path()
        assert not config_path.exists()
        
        save_config({"test": "data"})
        
        assert config_path.exists()
        with open(config_path) as f:
            data = json.load(f)
        assert data == {"test": "data"}


class TestWorkspaceManagement:
    """Tests for workspace management functions."""
    
    def test_set_last_workspace_minimal(self, temp_cwd, clean_config):
        """Test setting workspace with only path."""
        set_last_workspace("/test/workspace")
        
        config = load_config()
        assert "last_workspace" in config
        assert config["last_workspace"]["path"] == os.path.abspath("/test/workspace")
    
    def test_set_last_workspace_with_repo(self, temp_cwd, clean_config):
        """Test setting workspace with repo information."""
        set_last_workspace("/test/workspace", repo="owner/repo")
        
        config = load_config()
        assert config["last_workspace"]["repo"] == "owner/repo"
    
    def test_set_last_workspace_with_all_info(self, temp_cwd, clean_config):
        """Test setting workspace with all information."""
        set_last_workspace("/test/workspace", repo="owner/repo", branch="develop")
        
        config = load_config()
        workspace_info = config["last_workspace"]
        assert workspace_info["path"] == os.path.abspath("/test/workspace")
        assert workspace_info["repo"] == "owner/repo"
        assert workspace_info["branch"] == "develop"
    
    def test_get_last_workspace_empty(self, temp_cwd, clean_config):
        """Test getting workspace when none exists."""
        result = get_last_workspace()
        assert result is None
    
    def test_get_last_workspace_returns_info(self, temp_cwd, clean_config):
        """Test getting workspace returns saved information."""
        set_last_workspace("/test/workspace", repo="owner/repo", branch="main")
        
        result = get_last_workspace()
        assert result is not None
        assert result["path"] == os.path.abspath("/test/workspace")
        assert result["repo"] == "owner/repo"
        assert result["branch"] == "main"


class TestResolveWorkspace:
    """Tests for resolve_workspace function."""
    
    def test_resolve_workspace_with_explicit_path(self, tmp_path):
        """Test resolving workspace when explicit path is provided."""
        workspace = tmp_path / "workspace"
        workspace.mkdir()
        
        result = resolve_workspace(str(workspace))
        assert result == str(workspace.absolute())
    
    def test_resolve_workspace_nonexistent_returns_none(self):
        """Test that nonexistent workspace returns None."""
        result = resolve_workspace("/nonexistent/path")
        assert result is None
    
    def test_resolve_workspace_uses_last_workspace(self, temp_cwd, clean_config, tmp_path):
        """Test resolving workspace from config when not provided."""
        workspace = tmp_path / "workspace"
        workspace.mkdir()
        
        set_last_workspace(str(workspace))
        
        result = resolve_workspace()
        assert result == str(workspace.absolute())
    
    def test_resolve_workspace_no_path_no_config(self, temp_cwd, clean_config):
        """Test resolving workspace with no path and no config."""
        result = resolve_workspace()
        assert result is None
    
    def test_resolve_workspace_finds_timestamped_subdir(self, tmp_path):
        """Test that resolve_workspace finds timestamped subdirectory."""
        workspace = tmp_path / "workspace"
        workspace.mkdir()
        
        # Create timestamped subdirectory
        subdir = workspace / "pytest_cream_main_20251026_143421"
        subdir.mkdir()
        
        result = resolve_workspace(str(workspace))
        assert result == str(subdir.absolute())
    
    def test_resolve_workspace_finds_repo_clone(self, tmp_path):
        """Test that resolve_workspace finds repo_clone subdirectory."""
        workspace = tmp_path / "workspace"
        workspace.mkdir()
        
        # Create timestamped subdirectory with repo_clone
        subdir = workspace / "pytest_cream_main_20251026_143421"
        subdir.mkdir()
        repo_clone = subdir / "repo_clone"
        repo_clone.mkdir()
        
        result = resolve_workspace(str(workspace))
        assert result == str(repo_clone.absolute())
    
    def test_resolve_workspace_picks_newest_timestamp(self, tmp_path):
        """Test that resolve_workspace picks the newest timestamped directory."""
        workspace = tmp_path / "workspace"
        workspace.mkdir()
        
        # Create multiple timestamped subdirectories
        old_subdir = workspace / "pytest_cream_main_20251025_120000"
        old_subdir.mkdir()
        
        new_subdir = workspace / "pytest_cream_main_20251026_143421"
        new_subdir.mkdir()
        
        result = resolve_workspace(str(workspace))
        assert result == str(new_subdir.absolute())


class TestResolvePythonExecutable:
    """Tests for resolve_python_executable function."""
    
    def test_resolve_python_explicit_path(self, tmp_path):
        """Test resolving Python when explicit path is provided."""
        python_path = "/usr/bin/python3"
        
        result = resolve_python_executable(str(tmp_path), python_path)
        assert result == python_path
    
    def test_resolve_python_finds_venv(self, tmp_path):
        """Test that resolve_python_executable finds .venv Python."""
        workspace = tmp_path / "workspace"
        workspace.mkdir()
        
        venv_dir = workspace / ".venv" / "bin"
        venv_dir.mkdir(parents=True)
        venv_python = venv_dir / "python"
        venv_python.touch()
        
        result = resolve_python_executable(str(workspace))
        assert result == str(venv_python)
    
    def test_resolve_python_no_venv_returns_none(self, tmp_path):
        """Test that resolve_python_executable returns None when no venv."""
        workspace = tmp_path / "workspace"
        workspace.mkdir()
        
        result = resolve_python_executable(str(workspace))
        assert result is None
    
    def test_resolve_python_explicit_overrides_venv(self, tmp_path):
        """Test that explicit Python path overrides venv detection."""
        workspace = tmp_path / "workspace"
        workspace.mkdir()
        
        venv_dir = workspace / ".venv" / "bin"
        venv_dir.mkdir(parents=True)
        venv_python = venv_dir / "python"
        venv_python.touch()
        
        explicit_python = "/custom/python"
        result = resolve_python_executable(str(workspace), explicit_python)
        assert result == explicit_python


class TestClearConfig:
    """Tests for clear_config function."""
    
    def test_clear_config_removes_file(self, temp_cwd, clean_config):
        """Test that clear_config removes the config file."""
        # Create config
        save_config({"test": "data"})
        config_path = get_config_path()
        assert config_path.exists()
        
        # Clear it
        clear_config()
        assert not config_path.exists()
    
    def test_clear_config_handles_missing_file(self, temp_cwd, clean_config):
        """Test that clear_config doesn't error when file doesn't exist."""
        config_path = get_config_path()
        assert not config_path.exists()
        
        # Should not raise an error
        clear_config()
        assert not config_path.exists()


class TestIntegration:
    """Integration tests for config module."""
    
    def test_full_workflow(self, temp_cwd, clean_config, tmp_path):
        """Test complete workflow: set, get, resolve."""
        # Create workspace structure
        workspace = tmp_path / "workspace"
        workspace.mkdir()
        subdir = workspace / "pytest_cream_main_20251026_143421"
        subdir.mkdir()
        repo_clone = subdir / "repo_clone"
        repo_clone.mkdir()
        venv_dir = repo_clone / ".venv" / "bin"
        venv_dir.mkdir(parents=True)
        venv_python = venv_dir / "python"
        venv_python.touch()
        
        # Set workspace
        set_last_workspace(str(workspace), "owner/repo", "main")
        
        # Verify saved
        last_ws = get_last_workspace()
        assert last_ws is not None
        assert last_ws["repo"] == "owner/repo"
        
        # Resolve workspace (should find repo_clone)
        resolved_ws = resolve_workspace()
        assert resolved_ws == str(repo_clone.absolute())
        
        # Resolve Python (should find venv)
        resolved_python = resolve_python_executable(resolved_ws)
        assert resolved_python == str(venv_python)
    
    def test_multiple_workspaces_uses_last(self, temp_cwd, clean_config, tmp_path):
        """Test that multiple workspace inits use the last one."""
        ws1 = tmp_path / "workspace1"
        ws1.mkdir()
        ws2 = tmp_path / "workspace2"
        ws2.mkdir()
        
        # Set first workspace
        set_last_workspace(str(ws1), "owner/repo1", "main")
        assert get_last_workspace()["repo"] == "owner/repo1"
        
        # Set second workspace
        set_last_workspace(str(ws2), "owner/repo2", "develop")
        last = get_last_workspace()
        assert last["repo"] == "owner/repo2"
        assert last["branch"] == "develop"
        
        # Resolve should use second workspace
        resolved = resolve_workspace()
        assert resolved == str(ws2.absolute())
