#!/usr/bin/env python3
"""run-sprint-report.py — End-to-end sprint report generator.

Resolves team → project key, fetches live Jira data, searches GitHub PRs
for tickets missing dev info, and calls generate-sprint-report.py.

Always queries live data. Never reads from cache.

Usage:
    python3 run-sprint-report.py shark
    python3 run-sprint-report.py --team SQSH --sprint "Shark 60" -o report.md

Requires:
    JIRA_EMAIL + JIRA_API_TOKEN  (for Jira REST)
    gh CLI authenticated          (for GitHub PR search)

Optional:
    JIRA_BASE_URL (default: https://humand.atlassian.net)
"""

import argparse
import json
import os
import re
import subprocess
import sys
import tempfile
from pathlib import Path

SCRIPT_DIR = Path(__file__).resolve().parent
TEAMS_FILE = SCRIPT_DIR.parent / "config" / "teams.json"


def die(msg: str, code: int = 1):
    print(f"Error: {msg}", file=sys.stderr)
    sys.exit(code)


def log(msg: str):
    print(f"==> {msg}", file=sys.stderr)


def resolve_team(team: str) -> str:
    if not TEAMS_FILE.exists():
        die(f"teams.json not found at {TEAMS_FILE}", 2)

    with open(TEAMS_FILE) as f:
        data = json.load(f)

    if team in data and "project_key" in data[team]:
        return data[team]["project_key"]

    team_lower = team.lower()
    for entry in data.values():
        if not isinstance(entry, dict) or "aliases" not in entry:
            continue
        if team_lower in [a.lower() for a in entry.get("aliases", [])]:
            return entry["project_key"]

    if team.isupper() and 2 <= len(team) <= 6 and team.isalpha():
        return team

    die(f"Unknown team '{team}'. Not in teams.json and doesn't look like a Jira key.", 2)


def preflight():
    try:
        subprocess.run(["gh", "--version"], capture_output=True, check=True)
    except (FileNotFoundError, subprocess.CalledProcessError):
        die("gh CLI not found. Install from https://cli.github.com/", 3)

    result = subprocess.run(["gh", "auth", "status"], capture_output=True)
    if result.returncode != 0:
        die("gh not authenticated. Run: gh auth login", 3)

    email = os.environ.get("JIRA_EMAIL") or os.environ.get("ATLASSIAN_EMAIL") or ""
    token = os.environ.get("JIRA_API_TOKEN") or os.environ.get("ATLASSIAN_API_TOKEN") or ""
    if not email or not token:
        die("Jira credentials missing. Set JIRA_EMAIL + JIRA_API_TOKEN.", 3)


def fetch_tickets(project: str, sprint: str | None) -> dict:
    cmd = [str(SCRIPT_DIR / "fetch-jira-sprint-issues.sh"), "--project", project]
    if sprint:
        cmd += ["--sprint", sprint]

    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        die(f"fetch-jira-sprint-issues.sh failed:\n{result.stderr}", 3)

    return json.loads(result.stdout)


def extract_sprint_metadata(issues: list, sprint_override: str | None) -> tuple[str, str, str]:
    """Returns (sprint_name, start_date, end_date)."""
    if sprint_override:
        name = sprint_override
    else:
        name = ""

    start = "unknown"
    end = "unknown"

    for issue in issues:
        sprints = issue.get("fields", {}).get("customfield_10020") or []
        for s in (sprints if isinstance(sprints, list) else []):
            if isinstance(s, dict) and s.get("state") == "active":
                if not name:
                    name = s.get("name", "")
                if s.get("startDate"):
                    start = s["startDate"][:10]
                if s.get("endDate"):
                    end = s["endDate"][:10]
                return name, start, end

    return name, start, end


def keys_missing_dev_info(issues: list) -> list[str]:
    keys = []
    for issue in issues:
        fields = issue.get("fields", {})
        dev = str(fields.get("customfield_10000", "") or "")
        branch = fields.get("customfield_10097") or ""
        has_pr = bool(re.search(r'"count":\s*[1-9]', dev))
        if not has_pr and not branch:
            keys.append(issue["key"])
    return keys


def search_prs_for_keys(keys: list[str]) -> list:
    if not keys:
        return []

    script = str(SCRIPT_DIR / "search-prs-for-keys.sh")
    input_text = " ".join(keys)
    result = subprocess.run(
        [script, "-"],
        input=input_text, capture_output=True, text=True,
    )
    if result.returncode != 0:
        log(f"Warning: PR search failed: {result.stderr.strip()}")
        return []

    try:
        return json.loads(result.stdout)
    except json.JSONDecodeError:
        return []


def main():
    parser = argparse.ArgumentParser(description="End-to-end sprint report generator")
    parser.add_argument("team", nargs="?", default=None, help="Team alias or Jira project key")
    parser.add_argument("--team", dest="team_flag", default=None, help="Team alias or Jira project key")
    parser.add_argument("--sprint", default=None, help="Sprint name (defaults to active sprint)")
    parser.add_argument("-o", "--output", default=None, help="Output file (default: stdout)")

    args = parser.parse_args()
    team = args.team_flag or args.team
    if not team:
        die("team is required. Usage: run-sprint-report.py <team> [--sprint '<NAME>'] [-o out.md]")

    preflight()

    project = resolve_team(team)
    log(f"Team: {team} → Project: {project}")

    log("Fetching sprint tickets from Jira...")
    data = fetch_tickets(project, args.sprint)
    issues = data.get("issues", [])
    log(f"Found {len(issues)} tickets")

    if not issues:
        die(f"No tickets found in the active sprint for {project}. "
            "Verify the project key and that a sprint is active in Jira.", 4)

    sprint_name, start_date, end_date = extract_sprint_metadata(issues, args.sprint)
    log(f"Sprint: {sprint_name} ({start_date} — {end_date})")

    missing_keys = keys_missing_dev_info(issues)
    if missing_keys:
        log(f"Searching GitHub PRs for {len(missing_keys)} tickets missing dev info...")
        prs = search_prs_for_keys(missing_keys)
    else:
        log("All tickets have Jira dev info, skipping GitHub fallback search")
        prs = []

    with tempfile.TemporaryDirectory() as tmpdir:
        tickets_path = os.path.join(tmpdir, "tickets.json")
        prs_path = os.path.join(tmpdir, "prs.json")

        with open(tickets_path, "w") as f:
            json.dump(issues, f)
        with open(prs_path, "w") as f:
            json.dump(prs, f)

        log("Generating report...")
        cmd = [
            sys.executable, str(SCRIPT_DIR / "generate-sprint-report.py"),
            "--tickets", tickets_path,
            "--prs", prs_path,
            "--sprint", sprint_name or f"{project} Sprint",
            "--start", start_date,
            "--end", end_date,
            "--project", project,
        ]
        if args.output:
            cmd += ["--output", args.output]

        result = subprocess.run(cmd)
        if result.returncode != 0:
            die("generate-sprint-report.py failed", 5)

    if args.output:
        log(f"Report written to {args.output}")


if __name__ == "__main__":
    main()
