"""
Test configuration and fixtures for Git Operations MCP Server.
"""

import os
import shutil
import tempfile
from collections.abc import AsyncIterator, Iterator
from pathlib import Path
from unittest.mock import AsyncMock, MagicMock

import pytest
from git import Repo as GitRepo

# Set test environment
os.environ["IS_TEST"] = "true"
os.environ["GIT_OPS_WORKSPACE_BASE_PATH"] = "/tmp/test-workspaces"
os.environ["GIT_OPS_GITEA_BASE_URL"] = "https://gitea.test.com"
os.environ["GIT_OPS_GITEA_TOKEN"] = "test-token"


@pytest.fixture(scope="session", autouse=True)
def reset_settings_session():
    """Reset settings at start and end of test session."""
    from config import reset_settings

    reset_settings()
    yield
    reset_settings()


@pytest.fixture
def reset_settings():
    """Reset settings before each test that needs it."""
    from config import reset_settings

    reset_settings()
    yield
    reset_settings()


@pytest.fixture
def test_settings():
    """Get test settings."""
    from config import Settings

    return Settings(
        workspace_base_path=Path("/tmp/test-workspaces"),
        gitea_base_url="https://gitea.test.com",
        gitea_token="test-token",
        github_token="github-test-token",
        git_author_name="Test Agent",
        git_author_email="test@syndarix.ai",
        enable_force_push=False,
        debug=True,
    )


@pytest.fixture
def temp_dir() -> Iterator[Path]:
    """Create a temporary directory for tests."""
    temp_path = Path(tempfile.mkdtemp())
    yield temp_path
    if temp_path.exists():
        shutil.rmtree(temp_path)


@pytest.fixture
def temp_workspace(temp_dir: Path) -> Path:
    """Create a temporary workspace directory."""
    workspace = temp_dir / "workspace"
    workspace.mkdir(parents=True, exist_ok=True)
    return workspace


@pytest.fixture
def git_repo(temp_workspace: Path) -> GitRepo:
    """Create a git repository in the temp workspace."""
    # Initialize with main branch (Git 2.28+)
    repo = GitRepo.init(temp_workspace, initial_branch="main")

    # Configure git
    with repo.config_writer() as cw:
        cw.set_value("user", "name", "Test User")
        cw.set_value("user", "email", "test@example.com")

    # Create initial commit
    test_file = temp_workspace / "README.md"
    test_file.write_text("# Test Repository\n")
    repo.index.add(["README.md"])
    repo.index.commit("Initial commit")

    return repo


@pytest.fixture
def git_repo_with_remote(git_repo: GitRepo, temp_dir: Path) -> tuple[GitRepo, GitRepo]:
    """Create a git repository with a 'remote' (bare repo)."""
    # Create bare repo as remote
    remote_path = temp_dir / "remote.git"
    remote_repo = GitRepo.init(remote_path, bare=True)

    # Add remote to main repo
    git_repo.create_remote("origin", str(remote_path))

    # Push initial commit
    git_repo.remotes.origin.push("main:main")

    # Set up tracking
    git_repo.heads.main.set_tracking_branch(git_repo.remotes.origin.refs.main)

    return git_repo, remote_repo


@pytest.fixture
def workspace_manager(temp_dir: Path, test_settings):
    """Create a WorkspaceManager with test settings."""
    from workspace import WorkspaceManager

    test_settings.workspace_base_path = temp_dir / "workspaces"
    return WorkspaceManager(test_settings)


@pytest.fixture
def git_wrapper(temp_workspace: Path, test_settings):
    """Create a GitWrapper for the temp workspace."""
    from git_wrapper import GitWrapper

    return GitWrapper(temp_workspace, test_settings)


@pytest.fixture
def git_wrapper_with_repo(git_repo: GitRepo, test_settings):
    """Create a GitWrapper for a repo that's already initialized."""
    from git_wrapper import GitWrapper

    return GitWrapper(Path(git_repo.working_dir), test_settings)


@pytest.fixture
def mock_gitea_provider():
    """Create a mock Gitea provider."""
    provider = AsyncMock()
    provider.name = "gitea"
    provider.is_connected = AsyncMock(return_value=True)
    provider.get_authenticated_user = AsyncMock(return_value="test-user")
    provider.parse_repo_url = MagicMock(return_value=("owner", "repo"))
    return provider


@pytest.fixture
def mock_httpx_client():
    """Create a mock httpx client for provider tests."""
    from unittest.mock import AsyncMock

    mock_response = AsyncMock()
    mock_response.status_code = 200
    mock_response.json = MagicMock(return_value={})
    mock_response.text = ""

    mock_client = AsyncMock()
    mock_client.request = AsyncMock(return_value=mock_response)
    mock_client.get = AsyncMock(return_value=mock_response)
    mock_client.post = AsyncMock(return_value=mock_response)
    mock_client.patch = AsyncMock(return_value=mock_response)
    mock_client.delete = AsyncMock(return_value=mock_response)

    return mock_client


@pytest.fixture
async def gitea_provider(test_settings, mock_httpx_client):
    """Create a GiteaProvider with mocked HTTP client."""
    from providers.gitea import GiteaProvider

    provider = GiteaProvider(
        base_url=test_settings.gitea_base_url,
        token=test_settings.gitea_token,
        settings=test_settings,
    )
    provider._client = mock_httpx_client

    yield provider

    await provider.close()


@pytest.fixture
def sample_pr_data():
    """Sample PR data from Gitea API."""
    return {
        "number": 42,
        "title": "Test PR",
        "body": "This is a test pull request",
        "state": "open",
        "head": {"ref": "feature-branch"},
        "base": {"ref": "main"},
        "user": {"login": "test-user"},
        "created_at": "2024-01-15T10:00:00Z",
        "updated_at": "2024-01-15T12:00:00Z",
        "merged_at": None,
        "closed_at": None,
        "html_url": "https://gitea.test.com/owner/repo/pull/42",
        "labels": [{"name": "enhancement"}],
        "assignees": [{"login": "assignee1"}],
        "requested_reviewers": [{"login": "reviewer1"}],
        "mergeable": True,
        "draft": False,
    }


@pytest.fixture
def sample_commit_data():
    """Sample commit data."""
    return {
        "sha": "abc123def456",
        "short_sha": "abc123d",
        "message": "Test commit message",
        "author": {
            "name": "Test Author",
            "email": "author@test.com",
            "date": "2024-01-15T10:00:00Z",
        },
        "committer": {
            "name": "Test Committer",
            "email": "committer@test.com",
            "date": "2024-01-15T10:00:00Z",
        },
    }


@pytest.fixture
def mock_fastapi_app():
    """Create a test FastAPI app."""
    from fastapi import FastAPI
    from fastapi.testclient import TestClient

    app = FastAPI()

    @app.get("/health")
    def health():
        return {"status": "healthy"}

    return TestClient(app)


# Async fixtures


@pytest.fixture
async def async_workspace_manager(temp_dir: Path, test_settings) -> AsyncIterator:
    """Async fixture for workspace manager."""
    from workspace import WorkspaceManager

    test_settings.workspace_base_path = temp_dir / "workspaces"
    manager = WorkspaceManager(test_settings)
    yield manager


# Test data fixtures


@pytest.fixture
def valid_project_id() -> str:
    """Valid project ID for tests."""
    return "test-project-123"


@pytest.fixture
def valid_agent_id() -> str:
    """Valid agent ID for tests."""
    return "agent-456"


@pytest.fixture
def invalid_ids() -> list[str]:
    """Invalid IDs for validation tests."""
    return [
        "",
        " ",
        "a" * 200,  # Too long
        "test@invalid",  # Invalid character
        "test!invalid",
        "../path/traversal",
    ]


@pytest.fixture
def sample_repo_url() -> str:
    """Sample repository URL."""
    return "https://gitea.test.com/owner/repo.git"


@pytest.fixture
def sample_ssh_repo_url() -> str:
    """Sample SSH repository URL."""
    return "git@gitea.test.com:owner/repo.git"
