"""Gitea REST API client — create repos in the 'cases' org and push."""

from __future__ import annotations

import logging
import os
import subprocess
from pathlib import Path

import httpx

logger = logging.getLogger(__name__)

GITEA_ORG = "cases"


def _host() -> str:
    return os.environ.get("GITEA_HOST", "https://gitea.nautilus.marcusgroup.org")


def _token() -> str:
    return os.environ.get("GITEA_ACCESS_TOKEN") or os.environ.get("GITEA_TOKEN", "")


async def create_repo(case_number: str, title: str, description: str = "") -> dict:
    """Create a private repo in the 'cases' org on Gitea."""
    repo_name = case_number  # e.g. "1130-25"
    async with httpx.AsyncClient(verify=False, timeout=30) as client:
        resp = await client.post(
            f"{_host()}/api/v1/orgs/{GITEA_ORG}/repos",
            headers={"Authorization": f"token {_token()}"},
            json={
                "name": repo_name,
                "description": f"ערר {case_number} — {title}"[:255],
                "private": True,
                "auto_init": False,
            },
        )
        if resp.status_code == 409:
            # Repo already exists — fetch it
            resp2 = await client.get(
                f"{_host()}/api/v1/repos/{GITEA_ORG}/{repo_name}",
                headers={"Authorization": f"token {_token()}"},
            )
            resp2.raise_for_status()
            return resp2.json()
        resp.raise_for_status()
        return resp.json()


def _git_env() -> dict:
    return {
        "GIT_AUTHOR_NAME": "Ezer Mishpati",
        "GIT_AUTHOR_EMAIL": "legal@local",
        "GIT_COMMITTER_NAME": "Ezer Mishpati",
        "GIT_COMMITTER_EMAIL": "legal@local",
        "PATH": os.environ.get("PATH", "/usr/bin:/bin"),
        "GIT_TERMINAL_PROMPT": "0",
    }


def _refresh_remote_url(case_dir: Path, env: dict) -> bool:
    """Re-inject current token into existing origin URL.

    Handles the case where the token in Infisical was rotated but the
    case repo's origin URL still has the old token embedded.
    Returns True if origin exists (and was refreshed), False otherwise.
    """
    result = subprocess.run(
        ["git", "remote", "get-url", "origin"],
        cwd=case_dir, capture_output=True, text=True,
    )
    if result.returncode != 0:
        return False
    current_url = result.stdout.strip()
    # Strip any embedded credentials (https://user:token@host -> https://host)
    if "@" in current_url and current_url.startswith("https://"):
        bare_url = "https://" + current_url.split("@", 1)[1]
    else:
        bare_url = current_url
    auth_url = bare_url.replace("https://", f"https://chaim:{_token()}@")
    if auth_url != current_url:
        subprocess.run(
            ["git", "remote", "set-url", "origin", auth_url],
            cwd=case_dir, capture_output=True, env=env,
        )
    return True


def commit_and_push(case_dir: str | Path, message: str) -> bool:
    """Stage, commit, refresh remote URL with current token, and push.

    Best-effort: returns False on any failure, but logs the reason at
    WARNING level so issues are visible (the previous code swallowed
    push failures silently).
    """
    case_dir = Path(case_dir)
    if not (case_dir / ".git").exists():
        return False

    env = _git_env()

    subprocess.run(["git", "add", "."], cwd=case_dir, capture_output=True, env=env)
    commit = subprocess.run(
        ["git", "commit", "-m", message],
        cwd=case_dir, capture_output=True, text=True, env=env,
    )
    if commit.returncode != 0 and "nothing to commit" not in commit.stdout:
        logger.warning("Git commit failed in %s: %s", case_dir, commit.stderr or commit.stdout)
        # Continue anyway — maybe there were no new changes but we still
        # want to push earlier unpushed commits.

    if not _refresh_remote_url(case_dir, env):
        logger.warning("No origin remote configured in %s — skipping push", case_dir)
        return False

    push = subprocess.run(
        ["git", "push"],
        cwd=case_dir, capture_output=True, text=True, env=env,
    )
    if push.returncode != 0:
        logger.warning("Git push failed in %s: %s", case_dir, push.stderr)
        return False
    return True


def setup_remote_and_push(case_dir: str | Path, repo_clone_url: str) -> bool:
    """Add Gitea as remote 'origin' (or update it) and push.

    Used on initial case creation. For routine commits + push on
    existing repos, prefer ``commit_and_push``.
    """
    case_dir = Path(case_dir)
    if not (case_dir / ".git").exists():
        return False

    env = _git_env()

    auth_url = repo_clone_url.replace("https://", f"https://chaim:{_token()}@")

    result = subprocess.run(
        ["git", "remote", "get-url", "origin"],
        cwd=case_dir, capture_output=True, text=True,
    )
    if result.returncode == 0:
        subprocess.run(
            ["git", "remote", "set-url", "origin", auth_url],
            cwd=case_dir, capture_output=True, env=env,
        )
    else:
        subprocess.run(
            ["git", "remote", "add", "origin", auth_url],
            cwd=case_dir, capture_output=True, env=env,
        )

    push_result = subprocess.run(
        ["git", "push", "-u", "origin", "main"],
        cwd=case_dir, capture_output=True, text=True, env=env,
    )
    if push_result.returncode != 0:
        push_result = subprocess.run(
            ["git", "push", "-u", "origin", "master"],
            cwd=case_dir, capture_output=True, text=True, env=env,
        )
    if push_result.returncode != 0:
        logger.warning("Git push failed: %s", push_result.stderr)
        return False
    return True
