from __future__ import annotations

import re
import subprocess
from pathlib import Path
from typing import Any
from uuid import uuid4

from app.agents.isolation.strategy_selector import IsolationDecision


class WorktreeIsolationError(RuntimeError):
    pass


def _slugify(value: str, *, fallback: str) -> str:
    slug = re.sub(r"[^a-zA-Z0-9._-]+", "-", (value or "").strip()).strip("-").lower()
    return slug or fallback


def _resolve_git_root() -> Path:
    try:
        result = subprocess.run(
            ["git", "rev-parse", "--show-toplevel"],
            check=True,
            capture_output=True,
            text=True,
        )
    except subprocess.CalledProcessError as exc:
        raise WorktreeIsolationError(exc.stderr.strip() or exc.stdout.strip() or "git_root_unavailable") from exc
    git_root = Path(result.stdout.strip())
    if not git_root.exists():
        raise WorktreeIsolationError("git_root_not_found")
    return git_root


def prepare_worktree_isolation(
    *,
    state: dict[str, Any],
    decision: IsolationDecision,
    role_value: str,
    sub_commander: str,
    create_workspace: bool = True,
) -> dict[str, Any]:
    isolation_id = f"worktree-{uuid4().hex[:8]}"
    conversation_slug = _slugify(str(state.get("conversation_id") or "conversation"), fallback="conversation")
    role_slug = _slugify(role_value, fallback="agent")
    git_root = _resolve_git_root()
    workspace_root = git_root / ".worktrees" / "jarvis" / conversation_slug
    workspace_path = workspace_root / f"{role_slug}-{isolation_id}"
    branch = f"jarvis/{conversation_slug}/{role_slug}-{isolation_id}"

    if create_workspace and not workspace_path.exists():
        workspace_root.mkdir(parents=True, exist_ok=True)
        try:
            subprocess.run(
                ["git", "-C", str(git_root), "worktree", "add", "-b", branch, str(workspace_path), "HEAD"],
                check=True,
                capture_output=True,
                text=True,
            )
        except subprocess.CalledProcessError as exc:
            raise WorktreeIsolationError(exc.stderr.strip() or exc.stdout.strip() or "worktree_add_failed") from exc

    return {
        "mode": "worktree",
        "isolation_id": isolation_id,
        "workspace_path": str(workspace_path),
        "parent_conversation_id": str(state.get("conversation_id") or "") or None,
        "metadata": {
            **dict(decision.metadata or {}),
            "reason": decision.reason,
            "role": role_value,
            "sub_commander": sub_commander,
            "tool_names": list(decision.tool_names),
            "capability_ids": list(decision.capability_ids),
            "repo_root": str(git_root),
            "branch": branch,
            "workspace_strategy": "ephemeral_worktree",
            "cleanup_status": "pending",
            "materialized": workspace_path.exists(),
        },
    }
