"""Keep the cloud's copy of each app in step with Library Mode (the source of truth)."""
from __future__ import annotations

import os
import subprocess
from pathlib import Path
from urllib.parse import quote, urlsplit, urlunsplit

from .config import CLOUD, load_env
from .projects import Project

SCOUT_NAME = os.environ.get("SCOUT_GIT_NAME", "Feature Scout")
SCOUT_EMAIL = os.environ.get("SCOUT_GIT_EMAIL", "feature-scout@localhost")


def auth_url(url: str, token: str, user: str = "scout") -> str:
    """Library Mode accepts the device token as HTTP Basic with any username."""
    parts = urlsplit(url)
    return urlunsplit((parts.scheme, f"{quote(user)}:{quote(token, safe='')}@{parts.netloc}", parts.path, "", ""))


def _git(repo: Path, *args: str, check: bool = True, timeout: int = 600) -> subprocess.CompletedProcess:
    return subprocess.run(["git", "-C", str(repo), *args], capture_output=True, text=True, check=check, timeout=timeout)


def ensure_clone(project: Project, env: dict[str, str] | None = None) -> Path:
    """Clone the app from Library Mode if this machine doesn't have it yet."""
    repo = project.folder
    if (repo / ".git").exists():
        return repo
    if not project.librarymode_url:
        raise RuntimeError(f"{project.name}: no Library Mode address configured")
    env = env or load_env()
    token = env.get("LIBRARYMODE_TOKEN")
    if not token:
        raise RuntimeError("LIBRARYMODE_TOKEN is not set, so I cannot fetch the app's code")
    repo.parent.mkdir(parents=True, exist_ok=True)
    subprocess.run(["git", "clone", "-q", "--origin", "librarymode", auth_url(project.librarymode_url, token), str(repo)],
                   check=True, capture_output=True, text=True, timeout=900)
    _git(repo, "config", "user.name", SCOUT_NAME)
    _git(repo, "config", "user.email", SCOUT_EMAIL)
    return repo


def sync_main(project: Project) -> str:
    """Cloud only: make the mirror's main exactly Library Mode's main. Returns the new HEAD."""
    if not CLOUD:
        raise RuntimeError("sync_main must never run against Ken's own checkout")
    repo = ensure_clone(project)
    _git(repo, "fetch", "-q", "librarymode")
    _git(repo, "checkout", "-q", "-B", "main", "librarymode/main")
    return _git(repo, "rev-parse", "HEAD").stdout.strip()


def push_main(project: Project) -> tuple[bool, str]:
    """Send the mirror's main to Library Mode as a new version. (ok, message)."""
    p = _git(project.folder, "push", "-q", "librarymode", "main:main", check=False)
    return p.returncode == 0, (p.stderr + p.stdout).strip()
