import os
import subprocess
from pathlib import Path

import pytest

from project_hub.core.config import Config
from project_hub.core.discovery import discover_repos


def test_discover_finds_git_repos(tmp_workspace: Path) -> None:
    repos = discover_repos(tmp_workspace, Config())
    assert {r.name for r in repos} == {"repo-alpha", "repo-beta", "repo-gamma"}


def test_discover_skips_non_git_dirs(tmp_workspace: Path) -> None:
    (tmp_workspace / "not-a-repo").mkdir()
    repos = discover_repos(tmp_workspace, Config())
    assert "not-a-repo" not in {r.name for r in repos}
    assert len(repos) == 3


def test_discover_respects_include(tmp_workspace: Path) -> None:
    repos = discover_repos(tmp_workspace, Config(include=["repo-a*"]))
    assert {r.name for r in repos} == {"repo-alpha"}


def test_discover_respects_exclude(tmp_workspace: Path) -> None:
    repos = discover_repos(tmp_workspace, Config(exclude=["repo-gamma"]))
    assert {r.name for r in repos} == {"repo-alpha", "repo-beta"}


def test_discover_parses_remote_url(tmp_workspace: Path) -> None:
    config = Config(forges={"gitlab.com": {"type": "gitlab"}})
    repos = discover_repos(tmp_workspace, config)
    repo = next(r for r in repos if r.name == "repo-alpha")
    assert repo.forge_host == "gitlab.com"
    assert repo.forge_type == "gitlab"
    assert repo.has_forge is True
    assert repo.project_path == "group/repo-alpha"


def test_discover_unknown_forge_host(tmp_path: Path) -> None:
    """Repos on unrecognized hosts have has_forge=False when not in config."""
    repo_dir = tmp_path / "my-repo"
    repo_dir.mkdir()
    subprocess.run(["git", "init"], cwd=repo_dir, capture_output=True)
    subprocess.run(
        ["git", "remote", "add", "origin", "git@forge.internal.corp:team/my-repo.git"],
        cwd=repo_dir, capture_output=True,
    )
    repos = discover_repos(tmp_path, Config(forges={}))
    assert len(repos) == 1
    assert repos[0].has_forge is False


def test_discover_parses_https_remote(tmp_workspace: Path) -> None:
    repo_dir = tmp_workspace / "repo-https"
    repo_dir.mkdir()
    subprocess.run(["git", "init"], cwd=repo_dir, capture_output=True)
    subprocess.run(
        ["git", "remote", "add", "origin", "https://github.com/myorg/myproject.git"],
        cwd=repo_dir,
        capture_output=True,
    )

    config = Config(forges={"github.com": {"type": "github"}})
    repos = discover_repos(tmp_workspace, config)
    repo = next((r for r in repos if r.name == "repo-https"), None)
    assert repo is not None
    assert repo.forge_host == "github.com"
    assert repo.forge_type == "github"
    assert repo.has_forge is True
    assert repo.project_path == "myorg/myproject"


def _init_repo(path: Path, remote: str | None = None) -> None:
    """Helper: git init + optional remote + initial commit."""
    path.mkdir(parents=True, exist_ok=True)
    subprocess.run(["git", "init"], cwd=path, capture_output=True)
    if remote:
        subprocess.run(["git", "remote", "add", "origin", remote], cwd=path, capture_output=True)
    (path / "README.md").write_text(f"# {path.name}")
    subprocess.run(["git", "add", "."], cwd=path, capture_output=True)
    subprocess.run(
        ["git", "commit", "-m", "init"], cwd=path, 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"},
    )


def test_discover_recursive_nested_repos(tmp_path: Path) -> None:
    """Repos nested in subdirectories are discovered."""
    _init_repo(tmp_path / "frontend" / "app-web")
    _init_repo(tmp_path / "backend" / "api-gateway")
    _init_repo(tmp_path / "top-level-repo")
    repos = discover_repos(tmp_path, Config())
    assert {r.name for r in repos} == {"app-web", "api-gateway", "top-level-repo"}


def test_discover_recursive_no_subrepo(tmp_path: Path) -> None:
    """Does not recurse into a directory that already has .git."""
    _init_repo(tmp_path / "monorepo")
    # Create a nested .git inside — should NOT be discovered as separate repo
    (tmp_path / "monorepo" / "packages" / "sub").mkdir(parents=True)
    subprocess.run(["git", "init"], cwd=tmp_path / "monorepo" / "packages" / "sub", capture_output=True)
    repos = discover_repos(tmp_path, Config())
    assert {r.name for r in repos} == {"monorepo"}


def test_discover_recursive_name_collision(tmp_path: Path) -> None:
    """When two repos have the same dir name, use relative path from workspace root."""
    _init_repo(tmp_path / "team-a" / "api")
    _init_repo(tmp_path / "team-b" / "api")
    repos = discover_repos(tmp_path, Config())
    assert {r.name for r in repos} == {"team-a/api", "team-b/api"}


def test_discover_recursive_exclude_applies_at_all_levels(tmp_path: Path) -> None:
    """Exclude filter works on nested repo dir names."""
    _init_repo(tmp_path / "group" / "repo-a")
    _init_repo(tmp_path / "group" / "repo-b")
    repos = discover_repos(tmp_path, Config(exclude=["repo-b"]))
    assert {r.name for r in repos} == {"repo-a"}


def test_discover_recursive_depth_limit(tmp_path: Path) -> None:
    """Repos beyond MAX_DEPTH are not discovered."""
    # Build a path 11 levels deep (beyond _MAX_DEPTH=10)
    deep = tmp_path
    for i in range(11):
        deep = deep / f"level{i}"
    _init_repo(deep / "too-deep")
    # Also add a shallow one to confirm discovery still works
    _init_repo(tmp_path / "shallow")
    repos = discover_repos(tmp_path, Config())
    assert {r.name for r in repos} == {"shallow"}


def test_discover_github_repo_auto_detected(tmp_path):
    """GitHub repos are auto-detected without explicit config."""
    repo = tmp_path / "my-app"
    repo.mkdir()
    (repo / ".git").mkdir()
    subprocess.run(["git", "init"], cwd=repo, capture_output=True, check=True)
    subprocess.run(
        ["git", "remote", "add", "origin", "git@github.com:user/my-app.git"],
        cwd=repo, capture_output=True, check=True,
    )
    from project_hub.core.config import Config
    repos = discover_repos(tmp_path, Config())
    assert len(repos) == 1
    assert repos[0].forge_type == "github"
    assert repos[0].forge_host == "github.com"
    assert repos[0].has_forge is True


def test_discover_config_overrides_auto_detection(tmp_path):
    """Explicit config takes precedence over auto-detection."""
    repo = tmp_path / "my-app"
    repo.mkdir()
    (repo / ".git").mkdir()
    subprocess.run(["git", "init"], cwd=repo, capture_output=True, check=True)
    subprocess.run(
        ["git", "remote", "add", "origin", "git@mygithub.corp.com:org/my-app.git"],
        cwd=repo, capture_output=True, check=True,
    )
    from project_hub.core.config import Config
    config = Config()
    config.forges = {"mygithub.corp.com": {"type": "gitlab"}}
    repos = discover_repos(tmp_path, config)
    assert repos[0].forge_type == "gitlab"  # config wins over auto-detect
