"""Shared git helpers used across CLI commands."""

import hashlib
import json
import os
import subprocess
from pathlib import Path

import click
import yaml


def get_repo_root() -> Path:
    """Find git repository root from current directory."""
    cwd = Path.cwd()
    for parent in [cwd, *cwd.parents]:
        if (parent / ".git").exists():
            return parent
    raise click.ClickException("Not in a git repository")


def get_staged_diff_hash() -> str:
    """Get SHA-256 hash of staged changes."""
    result = subprocess.run(
        ["git", "diff", "--staged"],
        capture_output=True,
        text=True,
    )
    return hashlib.sha256(result.stdout.encode()).hexdigest()


def get_git_user_name() -> str:
    """Get git user.name, falling back to 'unknown'."""
    result = subprocess.run(
        ["git", "config", "user.name"],
        capture_output=True,
        text=True,
    )
    return result.stdout.strip() or "unknown"


def _migrate_local_config_json_to_yaml(repo_root: Path) -> None:
    """One-time migration: if config.json exists but config.yaml doesn't, convert."""
    json_path = repo_root / ".gjalla" / "config.json"
    yaml_path = repo_root / ".gjalla" / "config.yaml"

    if json_path.exists() and not yaml_path.exists():
        try:
            config = json.loads(json_path.read_text(encoding="utf-8"))
            yaml_path.write_text(yaml.dump(config, default_flow_style=False), encoding="utf-8")
            json_path.unlink()
        except (json.JSONDecodeError, OSError):
            pass


def load_local_config(repo_root: Path) -> dict:
    """Load .gjalla/config.yaml, auto-migrating from config.json if needed.

    Returns:
        Config dict, or empty dict if no config exists.
    """
    _migrate_local_config_json_to_yaml(repo_root)

    yaml_path = repo_root / ".gjalla" / "config.yaml"
    if not yaml_path.exists():
        return {}

    try:
        return yaml.safe_load(yaml_path.read_text(encoding="utf-8")) or {}
    except yaml.YAMLError:
        return {}


def save_local_config(repo_root: Path, config: dict) -> None:
    """Save config to .gjalla/config.yaml."""
    yaml_path = repo_root / ".gjalla" / "config.yaml"
    yaml_path.parent.mkdir(parents=True, exist_ok=True)
    yaml_path.write_text(yaml.dump(config, default_flow_style=False), encoding="utf-8")


def local_config_exists(repo_root: Path) -> bool:
    """Check if .gjalla/config.yaml (or config.json awaiting migration) exists."""
    return (
        (repo_root / ".gjalla" / "config.yaml").exists()
        or (repo_root / ".gjalla" / "config.json").exists()
    )


def strip_yaml_delimiters(content: str) -> str:
    """Strip leading/trailing YAML --- delimiters from attestation content."""
    stripped = content.strip()
    if stripped.startswith("---"):
        stripped = stripped[3:]
    if stripped.endswith("---"):
        stripped = stripped[:-3]
    return stripped


def migrate_gjalla_file_to_dir(repo_root: Path) -> None:
    """If .gjalla is an old-format plain file, migrate it to a directory with config.yaml."""
    gjalla_path = repo_root / ".gjalla"
    if not gjalla_path.is_file():
        return
    try:
        old_content = gjalla_path.read_text(encoding="utf-8")
        old_data = json.loads(old_content)
        gjalla_path.unlink()
        gjalla_path.mkdir(parents=True, exist_ok=True)
        save_local_config(repo_root, old_data)
    except (json.JSONDecodeError, OSError):
        # Can't parse — just move the file out of the way
        gjalla_path.unlink(missing_ok=True)
        gjalla_path.mkdir(parents=True, exist_ok=True)


def ensure_gitignore(repo_root: Path, entries: list[str]) -> list[str]:
    """Ensure entries exist in .gitignore. Returns list of newly added entries."""
    gitignore = repo_root / ".gitignore"
    existing = gitignore.read_text(encoding="utf-8") if gitignore.exists() else ""
    lines = existing.splitlines()
    added = []
    for entry in entries:
        if entry not in lines:
            lines.append(entry)
            added.append(entry)
    if added:
        gitignore.write_text("\n".join(lines) + "\n", encoding="utf-8")
    return added


def resolve_local_api_key(repo_root: Path) -> tuple[str | None, str | None]:
    """Resolve API key and URL from project-local sources.

    Checks project-local config only (not global config or GJALLA_API_KEY env var,
    which are already handled by Settings.load()). Use this to layer local sources
    on top of Settings.

    Priority order:
    1. Direct api_key in .gjalla/config.yaml
    2. api_key_env (env var reference) in .gjalla/config.yaml

    Returns:
        (api_key, api_url) — either or both may be None.
    """
    local_config = load_local_config(repo_root)
    if not local_config:
        return None, None

    api_url = local_config.get("api_url")

    # 1. Direct api_key field
    direct_key = local_config.get("api_key")
    if direct_key:
        return direct_key, api_url

    # 2. api_key_env (env var reference)
    env_var_name = local_config.get("api_key_env", "")
    if env_var_name:
        key = os.environ.get(env_var_name)
        if key:
            return key, api_url

    return None, api_url
