"""Factory functions for creating ErkContext instances.

This module provides factory functions for creating production contexts
with real implementations. Used by CLI entry points.
"""

from __future__ import annotations

import subprocess
from pathlib import Path
from typing import TYPE_CHECKING

from erk_shared.core.fakes import (
    FakeCodespaceRegistry,
    FakePlanListService,
    FakePromptExecutor,
    FakeScriptWriter,
)

if TYPE_CHECKING:
    from erk_shared.context.context import ErkContext
    from erk_shared.gateway.git.abc import Git
    from erk_shared.gateway.github.types import RepoInfo


def get_repo_info(git: Git, repo_root: Path) -> RepoInfo | None:
    """Detect repository info from git remote URL.

    Parses the origin remote URL to extract owner/name for GitHub API calls.
    Returns None if no origin remote is configured or URL cannot be parsed.

    Args:
        git: Git interface for operations
        repo_root: Repository root path

    Returns:
        RepoInfo with owner/name, or None if not determinable
    """
    from erk_shared.gateway.github.parsing import parse_git_remote_url
    from erk_shared.gateway.github.types import RepoInfo

    try:
        remote_url = git.remote.get_remote_url(repo_root, "origin")
        owner, name = parse_git_remote_url(remote_url)
        return RepoInfo(owner=owner, name=name)
    except ValueError:
        return None


def create_minimal_context(*, debug: bool, cwd: Path | None = None) -> ErkContext:
    """Create production context with real implementations for erk-kits.

    This factory creates a minimal context suitable for erk-kits commands.
    It uses real implementations for GitHub, git, and session store, but uses
    fake implementations for erk-specific services (PromptExecutor, etc.) that
    erk-kits doesn't need.

    Detects repository root using git rev-parse. Returns context with
    NoRepoSentinel if not in a git repository.

    Args:
        debug: If True, enable debug mode (full stack traces in error handling)
        cwd: Current working directory (defaults to Path.cwd())

    Returns:
        ErkContext with real GitHub integrations and detected repo context

    Example:
        >>> ctx = create_minimal_context(debug=False)
        >>> issue_number = ctx.issues.create_issue(ctx.repo_root, title, body, labels)
    """
    from erk_shared.context.context import ErkContext
    from erk_shared.context.types import LoadedConfig, NoRepoSentinel, RepoContext
    from erk_shared.gateway.claude_installation.real import RealClaudeInstallation
    from erk_shared.gateway.codespace.fake import FakeCodespace
    from erk_shared.gateway.completion.fake import FakeCompletion
    from erk_shared.gateway.console.real import ScriptConsole
    from erk_shared.gateway.erk_installation.real import RealErkInstallation
    from erk_shared.gateway.git.real import RealGit
    from erk_shared.gateway.github.issues.real import RealGitHubIssues
    from erk_shared.gateway.github.real import RealGitHub
    from erk_shared.gateway.github_admin.fake import FakeGitHubAdmin
    from erk_shared.gateway.graphite.fake import FakeGraphite

    # Note: For minimal contexts, use FakePromptExecutor since the real
    # ClaudePromptExecutor lives in erk (not erk-shared)
    from erk_shared.gateway.shell.fake import FakeShell
    from erk_shared.gateway.time.fake import FakeTime
    from erk_shared.gateway.time.real import RealTime
    from erk_shared.plan_store.github import GitHubPlanStore

    resolved_cwd = cwd if cwd is not None else Path.cwd()

    # Detect repo root using git rev-parse
    result = subprocess.run(
        ["git", "rev-parse", "--show-toplevel"],
        capture_output=True,
        text=True,
        check=False,
    )

    # Create git instance and erk installation
    git = RealGit()
    erk_installation = RealErkInstallation()

    if result.returncode != 0:
        # Not in a git repository
        repo: RepoContext | NoRepoSentinel = NoRepoSentinel()
        repo_info = None
    else:
        repo_root = Path(result.stdout.strip())
        repo_info = get_repo_info(git, repo_root)
        repo_dir = erk_installation.root() / "repos" / repo_root.name
        repo = RepoContext(
            root=repo_root,
            repo_name=repo_root.name,
            repo_dir=repo_dir,
            worktrees_dir=repo_dir / "worktrees",
            pool_json_path=repo_dir / "pool.json",
        )

    # Use fake implementations for erk-specific services that erk-kits doesn't need
    fake_graphite = FakeGraphite()
    # Create issues first, then compose into github
    time = RealTime()
    github_issues = RealGitHubIssues(target_repo=None, time=time)
    fake_time = FakeTime()
    return ErkContext(
        git=git,
        github=RealGitHub(time=time, repo_info=repo_info, issues=github_issues),
        github_admin=FakeGitHubAdmin(),
        claude_installation=RealClaudeInstallation(),
        prompt_executor=FakePromptExecutor(),
        graphite=fake_graphite,
        graphite_branch_ops=None,  # Graphite disabled, so None
        console=ScriptConsole(),
        time=fake_time,
        erk_installation=erk_installation,
        plan_store=GitHubPlanStore(github_issues, fake_time),
        shell=FakeShell(),
        completion=FakeCompletion(),
        codespace=FakeCodespace(),
        script_writer=FakeScriptWriter(),
        codespace_registry=FakeCodespaceRegistry(),
        plan_list_service=FakePlanListService(),
        cwd=resolved_cwd,
        repo=repo,
        repo_info=repo_info,
        global_config=None,
        local_config=LoadedConfig.test(),
        dry_run=False,
        debug=debug,
    )
