import os
import subprocess
from datetime import datetime
from pathlib import Path
from unittest.mock import patch

import pytest

from project_hub.core.cache import Cache
from project_hub.core.models import MR, Event, EventType, Issue, Pipeline, Vulnerability


@pytest.fixture(autouse=True)
def _no_real_keyring():
    """Prevent tests from touching the real OS keyring or reading real auth.json."""
    with patch("project_hub.forge.auth._resolve_from_keyring", return_value=None), \
         patch("project_hub.forge.auth._store_to_keyring", return_value=False), \
         patch("project_hub.forge.auth._keyring_available", return_value=False):
        yield

@pytest.fixture
def tmp_workspace(tmp_path: Path) -> Path:
    """Create a temporary workspace with 3 fake git repos."""
    for name in ["repo-alpha", "repo-beta", "repo-gamma"]:
        repo_dir = tmp_path / name
        repo_dir.mkdir()
        subprocess.run(["git", "init"], cwd=repo_dir, capture_output=True)
        subprocess.run(
            ["git", "remote", "add", "origin", f"git@gitlab.com:group/{name}.git"],
            cwd=repo_dir, capture_output=True,
        )
        (repo_dir / "README.md").write_text(f"# {name}")
        subprocess.run(["git", "add", "."], cwd=repo_dir, capture_output=True)
        subprocess.run(
            ["git", "commit", "-m", "init"],
            cwd=repo_dir, capture_output=True,
            env={**os.environ, "GIT_AUTHOR_NAME": "Test", "GIT_AUTHOR_EMAIL": "t@t.com",
                 "GIT_COMMITTER_NAME": "Test", "GIT_COMMITTER_EMAIL": "t@t.com"},
        )
    return tmp_path

@pytest.fixture
def tmp_hub(tmp_workspace: Path) -> Path:
    """Create a workspace with .project-hub initialized."""
    hub_dir = tmp_workspace / ".project-hub"
    hub_dir.mkdir()
    (hub_dir / "config.yaml").write_text("forges:\n  gitlab.com:\n    type: gitlab\n")
    (hub_dir / "workspace.md").write_text("")
    return tmp_workspace


@pytest.fixture
async def cache(tmp_path):
    c = Cache(tmp_path / "cache.db")
    await c.initialize()
    yield c
    await c.close()


def make_mr(iid: int, repo_name: str = "repo-alpha", notes: int = 0, approved: bool = False, sha: str = "abc123") -> MR:
    return MR(
        id=iid * 100,
        iid=iid,
        title=f"MR {iid}",
        author="alice",
        state="opened",
        source_branch=f"feature/{iid}",
        target_branch="main",
        web_url=f"https://gitlab.com/mr/{iid}",
        user_notes_count=notes,
        approved=approved,
        created_at="2024-01-01T00:00:00Z",
        updated_at="2024-01-02T00:00:00Z",
        repo_name=repo_name,
        sha=sha,
    )


def make_pipeline(pid: int, repo_name: str = "repo-alpha", status: str = "success") -> Pipeline:
    return Pipeline(
        id=pid,
        status=status,
        ref="main",
        web_url=f"https://gitlab.com/pipelines/{pid}",
        created_at="2024-01-01T00:00:00Z",
        repo_name=repo_name,
    )


def make_vuln(vid: int, repo_name: str = "repo-alpha") -> Vulnerability:
    return Vulnerability(
        id=vid,
        name=f"CVE-{vid}",
        severity="high",
        state="detected",
        source="sast",
        web_url=f"https://gitlab.com/vulns/{vid}",
        repo_name=repo_name,
    )


def make_issue(iid: int, repo_name: str = "repo-alpha", notes: int = 0, state: str = "opened") -> Issue:
    return Issue(
        id=iid * 100,
        iid=iid,
        title=f"Issue {iid}",
        author="alice",
        state=state,
        web_url=f"https://gitlab.com/issues/{iid}",
        user_notes_count=notes,
        created_at="2024-01-01T00:00:00Z",
        updated_at="2024-01-02T00:00:00Z",
        repo_name=repo_name,
        labels=["bug"],
        assignees=["alice"],
        participants=["alice", "bob"],
    )


def make_event(etype: EventType = EventType.PIPELINE_FAILED, repo_name: str = "repo-alpha") -> Event:
    return Event(
        id=None,
        type=etype,
        repo_name=repo_name,
        summary="Pipeline failed on main",
        detail="Job test-unit exited with code 1",
        created_at=datetime(2024, 1, 1, 12, 0, 0),
    )
