"""Shared Looper MCP operations — repo detection, job lookup, build history.

This module is intentionally free of report-URL construction since Karate,
Playwright, and Monocart publish to different CDC paths.
"""
import re
import subprocess
import sys

from .looper_auth import extract_json_block, mcp_call


# ---------------------------------------------------------------------------
# Repo detection
# ---------------------------------------------------------------------------

def detect_scm_url(cwd: str) -> str | None:
    """Auto-detect the SCM URL via git remote in *cwd*."""
    try:
        result = subprocess.run(
            ["git", "remote", "get-url", "origin"],
            capture_output=True, text=True, timeout=5, cwd=cwd,
        )
        if result.returncode != 0:
            return None
        url = result.stdout.strip()
        if not url.endswith(".git"):
            url += ".git"
        ssh_match = re.match(r"git@([^:]+):(.+)", url)
        if ssh_match:
            url = f"https://{ssh_match.group(1)}/{ssh_match.group(2)}"
        return url
    except (subprocess.TimeoutExpired, FileNotFoundError):
        return None


def resolve_scm_url(
    explicit: str | None = None,
    repo_path: str | None = None,
) -> str:
    """Resolve the SCM URL for the repo being monitored.

    Resolution order (first match wins):
      1. ``explicit`` — a hard-coded or CLI-supplied URL
      2. ``repo_path`` — path to a local clone; SCM URL auto-detected via git
    """
    if explicit:
        return explicit
    if repo_path:
        detected = detect_scm_url(cwd=repo_path)
        if detected:
            print(f"Auto-detected repo from {repo_path}: {detected}", file=sys.stderr)
            return detected
        print(
            f"Error: Could not detect git remote in '{repo_path}'. "
            "Ensure it is a valid git repo with an 'origin' remote.",
            file=sys.stderr,
        )
        sys.exit(1)
    print(
        "Error: No SCM URL provided. Use one of:\n"
        "  scm_url in daily_flows.yml\n"
        "  --scm-url <url>      e.g. https://gecgithub01.walmart.com/my-org/my-repo.git\n"
        "  --repo-path <path>   path to a local clone of the target repo",
        file=sys.stderr,
    )
    sys.exit(1)


# ---------------------------------------------------------------------------
# Job lookup
# ---------------------------------------------------------------------------

def _parse_job_item(item: dict) -> dict:
    """Normalise a single job item from the MCP list_ci_jobs response."""
    job = item.get("job", {})
    return {
        "id": job.get("id"),
        "name": job.get("name"),
        "looperFile": job.get("looperFilePath"),
        "latestBuilds": [
            {
                "buildNumber": b.get("buildNumber"),
                "flowName": b.get("flowName"),
                "buildStatus": b.get("buildStatus"),
            }
            for b in item.get("builds", [])[:5]
        ],
    }


def get_job_by_name(job_name: str) -> dict | None:
    """Look up a single job by exact name — one MCP call, exact match."""
    data = mcp_call("list_ci_jobs", {"name": job_name})
    text = data["result"]["content"][0]["text"]
    parsed = extract_json_block(text)
    if not parsed:
        return None
    items = parsed.get("content", [])
    if not items:
        return None
    return _parse_job_item(items[0])


def list_jobs(scm_url: str) -> list[dict]:
    """List all CI jobs for a repo by its SCM URL."""
    data = mcp_call("list_ci_jobs", {"scmUrl": scm_url})
    text = data["result"]["content"][0]["text"]
    parsed = extract_json_block(text)
    if not parsed:
        return []
    return [_parse_job_item(item) for item in parsed.get("content", [])]


# ---------------------------------------------------------------------------
# Build history
# ---------------------------------------------------------------------------

def get_build_history(
    job_id: str,
    branch: str | None = "main",
    size: int = 20,
    flow_name: str | None = None,
) -> list[dict]:
    """Get build history for a job, optionally filtered by flow name.

    Pass ``branch=None`` to fetch builds across all branches.
    """
    params: dict = {"jobId": job_id, "size": size}
    if branch:
        params["branch"] = branch
    data = mcp_call("get_build_history", params)
    text = data["result"]["content"][0]["text"]
    parsed = extract_json_block(text)
    if not parsed:
        return []
    builds = parsed.get("builds", [])
    if flow_name:
        builds = [b for b in builds if b.get("flowName") == flow_name]
    return builds


# ---------------------------------------------------------------------------
# Flow search
# ---------------------------------------------------------------------------

def _rank_match(match: dict) -> tuple:
    """Sort key: prefer real builds over cancelled/empty."""
    b = match.get("matchedBuild", {})
    status = b.get("buildStatus", "")
    status_score = 0 if status in ("CANCELLED", "", None) else 1
    return (status_score, b.get("buildNumber", 0))


def search_flow(
    flow_name: str,
    scm_url: str | None = None,
    repo_path: str | None = None,
) -> list[dict]:
    """Search ALL jobs in a repo to find which ones run a given flow."""
    url = resolve_scm_url(scm_url, repo_path=repo_path)
    jobs = list_jobs(url)
    matches: list[dict] = []

    for job in jobs:
        flow_builds = [
            b for b in job["latestBuilds"]
            if b.get("flowName") == flow_name
        ]
        if flow_builds:
            matches.append({
                "jobId": job["id"],
                "jobName": job["name"],
                "looperFile": job["looperFile"],
                "matchedBuild": flow_builds[0],
            })

    matched_ids = {m["jobId"] for m in matches}
    for job in jobs:
        if job["id"] in matched_ids:
            continue
        builds = get_build_history(job["id"], size=20, flow_name=flow_name)
        if builds:
            matches.append({
                "jobId": job["id"],
                "jobName": job["name"],
                "looperFile": job["looperFile"],
                "matchedBuild": {
                    "buildNumber": builds[0]["buildNumber"],
                    "flowName": builds[0].get("flowName"),
                    "buildStatus": builds[0].get("buildStatus"),
                },
            })

    matches.sort(key=_rank_match, reverse=True)
    return matches
