"""Space bootstrap — first-load setup for spaces.

Handles cloning repos and installing packs when a space is first loaded.
"""

from __future__ import annotations

import logging
import subprocess
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any

from .pack_sources import _sanitize_git_stderr, _validate_url_scheme

logger = logging.getLogger(__name__)

_CLONE_TIMEOUT = 120


@dataclass
class CloneResult:
    url: str
    success: bool
    local_path: str = ""
    error: str = ""


@dataclass
class BootstrapResult:
    success: bool
    packs_installed: list[str] = field(default_factory=list)
    errors: list[str] = field(default_factory=list)
    clone_results: list[CloneResult] = field(default_factory=list)


def _extract_repo_name(url: str) -> str:
    """Extract repository name from a git URL."""
    url = url.rstrip("/")
    if url.endswith(".git"):
        url = url[:-4]

    # SSH git@host:org/repo format
    if ":" in url and not url.startswith(("http://", "https://", "ssh://")):
        url = url.split(":")[-1]

    name = url.rsplit("/", 1)[-1]
    return name if name else "repo"


def clone_repos(repos: list[str], repos_root: Path) -> list[CloneResult]:
    """Clone a list of repo URLs into repos_root. Graceful per-repo."""
    results: list[CloneResult] = []
    repos_root.mkdir(parents=True, exist_ok=True)

    for url in repos:
        url_err = _validate_url_scheme(url)
        if url_err:
            results.append(CloneResult(url=url, success=False, error=f"URL scheme not allowed: {url}"))
            continue

        repo_name = _extract_repo_name(url)
        dest = repos_root / repo_name

        if dest.exists():
            results.append(CloneResult(url=url, success=True, local_path=str(dest)))
            continue

        try:
            subprocess.run(
                ["git", "clone", "--depth", "1", "--", url, str(dest)],
                capture_output=True,
                text=True,
                timeout=_CLONE_TIMEOUT,
                check=True,
            )
            results.append(CloneResult(url=url, success=True, local_path=str(dest)))
        except FileNotFoundError:
            results.append(CloneResult(url=url, success=False, error="git binary not found"))
        except subprocess.TimeoutExpired:
            results.append(CloneResult(url=url, success=False, error=f"Clone timed out after {_CLONE_TIMEOUT}s"))
        except subprocess.CalledProcessError as exc:
            stderr = _sanitize_git_stderr(exc.stderr or "")
            results.append(CloneResult(url=url, success=False, error=f"git clone failed: {stderr[:200]}"))

    return results


def install_space_packs(
    db: Any,
    pack_sources: list[dict[str, str]],
    packs: list[str],
    data_dir: Path,
) -> list[str]:
    """Install packs for a space. Returns list of installed pack references."""
    installed: list[str] = []

    for ps in pack_sources:
        url = ps.get("url", "")
        branch = ps.get("branch", "main")
        try:
            from .pack_sources import clone_source

            result = clone_source(url, data_dir, branch=branch)
            if result.success and result.path:
                from .pack_refresh import install_from_source

                install_from_source(db, result.path)
        except Exception as exc:
            logger.warning("Failed to install pack source %s: %s", url, exc)

    for pack_ref in packs:
        installed.append(pack_ref)

    return installed


def bootstrap_space(
    db: Any,
    space_config: Any,
    local_config: Any | None,
    data_dir: Path,
) -> BootstrapResult:
    """Bootstrap a space: clone repos, install packs."""
    errors: list[str] = []
    clone_results: list[CloneResult] = []

    # Clone repos
    if space_config.repos:
        repos_root = Path(local_config.repos_root) if local_config and local_config.repos_root else data_dir / "repos"
        clone_results = clone_repos(space_config.repos, repos_root)
        for cr in clone_results:
            if not cr.success:
                errors.append(f"Clone failed for {cr.url}: {cr.error}")

    # Install packs
    pack_sources_dicts = [{"url": ps.url, "branch": ps.branch} for ps in space_config.pack_sources]
    packs_installed = install_space_packs(db, pack_sources_dicts, space_config.packs, data_dir)

    return BootstrapResult(
        success=len(errors) == 0,
        packs_installed=packs_installed,
        errors=errors,
        clone_results=clone_results,
    )
