#!/usr/bin/env python3
import argparse
import io
import json
import os
import re
import sys
import urllib.error
import urllib.request
from datetime import datetime, timezone

GITHUB_REPO = "sickn33/antigravity-awesome-skills"
SYNC_COMMENT_RE = re.compile(r"<!-- registry-sync: .*? -->")
SYNC_COMMENT_FIELDS_RE = re.compile(
    r"<!-- registry-sync: version=(?P<version>[^;]+); skills=(?P<skills>\d+); "
    r"stars=(?P<stars>\d+); updated_at=(?P<updated_at>[^ ]+) -->"
)
CURRENT_RELEASE_LINE_RE = re.compile(r"^\*\*Current release: V[\d.]+\.\*\* .*?$", re.MULTILINE)


def configure_utf8_output() -> None:
    """Best-effort UTF-8 stdout/stderr on Windows without dropping diagnostics."""
    if sys.platform != "win32":
        return

    for stream_name in ("stdout", "stderr"):
        stream = getattr(sys, stream_name)
        try:
            stream.reconfigure(encoding="utf-8", errors="backslashreplace")
            continue
        except Exception:
            pass

        buffer = getattr(stream, "buffer", None)
        if buffer is not None:
            setattr(
                sys,
                stream_name,
                io.TextIOWrapper(buffer, encoding="utf-8", errors="backslashreplace"),
            )


def find_repo_root(start_path: str) -> str:
    current = os.path.abspath(start_path)
    while True:
        if os.path.isfile(os.path.join(current, "package.json")) and os.path.isfile(
            os.path.join(current, "README.md")
        ):
            return current
        parent = os.path.dirname(current)
        if parent == current:
            raise FileNotFoundError("Could not locate repository root from script path.")
        current = parent


def format_skill_count(total_skills: int) -> str:
    return f"{total_skills:,}+"


def format_star_badge_count(stars: int) -> str:
    if stars >= 1000:
        rounded = int(round(stars / 1000.0))
        return f"{rounded}%2C000%2B"
    return f"{stars}%2B"


def format_star_milestone(stars: int) -> str:
    if stars >= 1000:
        rounded = int(round(stars / 1000.0))
        return f"{rounded},000+"
    return f"{stars}+"


def format_star_celebration(stars: int) -> str:
    if stars >= 1000:
        rounded = int(round(stars / 1000.0))
        return f"{rounded}k"
    return str(stars)


def fetch_star_count(repo: str) -> int | None:
    url = f"https://api.github.com/repos/{repo}"
    request = urllib.request.Request(
        url,
        headers={
            "Accept": "application/vnd.github+json",
            "User-Agent": "antigravity-awesome-skills-readme-sync",
        },
    )
    try:
        with urllib.request.urlopen(request, timeout=10) as response:
            payload = json.load(response)
    except (urllib.error.URLError, TimeoutError, json.JSONDecodeError):
        return None
    stars = payload.get("stargazers_count")
    return int(stars) if isinstance(stars, int) else None


def parse_existing_sync_metadata(current_readme: str) -> dict[str, str | int] | None:
    match = SYNC_COMMENT_FIELDS_RE.search(current_readme)
    if not match:
        return None

    return {
        "version": match.group("version"),
        "skills": int(match.group("skills")),
        "stars": int(match.group("stars")),
        "updated_at": match.group("updated_at"),
    }


def load_metadata(
    base_dir: str, repo: str = GITHUB_REPO, refresh_volatile: bool = False
) -> dict:
    readme_path = os.path.join(base_dir, "README.md")
    package_path = os.path.join(base_dir, "package.json")
    index_path = os.path.join(base_dir, "skills_index.json")

    with open(index_path, "r", encoding="utf-8") as file:
        skills = json.load(file)

    with open(package_path, "r", encoding="utf-8") as file:
        package = json.load(file)

    with open(readme_path, "r", encoding="utf-8") as file:
        current_readme = file.read()

    existing_sync_metadata = parse_existing_sync_metadata(current_readme)
    current_star_match = re.search(r"⭐%20([\d%2C\+]+)%20Stars", current_readme)
    current_stars = None
    if current_star_match:
        compact = current_star_match.group(1).replace("%2C", "").replace("%2B", "")
        compact = compact.rstrip("+")
        if compact.isdigit():
            current_stars = int(compact)

    existing_stars = None
    existing_updated_at = None
    if existing_sync_metadata:
        stars = existing_sync_metadata.get("stars")
        updated_at = existing_sync_metadata.get("updated_at")
        if isinstance(stars, int):
            existing_stars = stars
        if isinstance(updated_at, str):
            existing_updated_at = updated_at

    live_stars = fetch_star_count(repo) if refresh_volatile else None
    total_stars = (
        live_stars
        if live_stars is not None
        else existing_stars
        if existing_stars is not None
        else current_stars or 0
    )
    updated_at = (
        datetime.now(timezone.utc).replace(microsecond=0).isoformat()
        if refresh_volatile or existing_updated_at is None
        else existing_updated_at
    )

    return {
        "repo": repo,
        "version": str(package.get("version", "0.0.0")),
        "total_skills": len(skills),
        "total_skills_label": format_skill_count(len(skills)),
        "stars": total_stars,
        "star_badge_count": format_star_badge_count(total_stars),
        "star_milestone": format_star_milestone(total_stars),
        "star_celebration": format_star_celebration(total_stars),
        "updated_at": updated_at,
        "used_live_star_count": live_stars is not None,
        "refreshed_volatile": refresh_volatile,
    }


def apply_metadata(content: str, metadata: dict) -> str:
    total_skills = metadata["total_skills"]
    total_skills_label = metadata["total_skills_label"]
    version = metadata["version"]
    star_badge_count = metadata["star_badge_count"]
    star_milestone = metadata["star_milestone"]
    star_celebration = metadata["star_celebration"]
    sync_comment = (
        f"<!-- registry-sync: version={version}; skills={total_skills}; "
        f"stars={metadata['stars']}; updated_at={metadata['updated_at']} -->"
    )

    content = re.sub(
        r"^# 🌌 Antigravity Awesome Skills: .*?$",
        (
            f"# 🌌 Antigravity Awesome Skills: {total_skills_label} "
            "Agentic Skills for Claude Code, Gemini CLI, Cursor, Copilot & More"
        ),
        content,
        count=1,
        flags=re.MULTILINE,
    )
    content = re.sub(
        r"^> \*\*The Ultimate Collection of .*?\*\*$",
        (
            f"> **The Ultimate Collection of {total_skills_label} Universal Agentic "
            "Skills for AI Coding Assistants — Claude Code, Gemini CLI, Codex CLI, "
            "Antigravity IDE, GitHub Copilot, Cursor, OpenCode, AdaL**"
        ),
        content,
        count=1,
        flags=re.MULTILINE,
    )
    content = re.sub(
        r"https://img\.shields\.io/badge/⭐%20[\dA-Fa-f%,\+]+%20Stars-gold\?style=for-the-badge",
        f"https://img.shields.io/badge/⭐%20{star_badge_count}%20Stars-gold?style=for-the-badge",
        content,
        count=1,
    )
    content = re.sub(
        CURRENT_RELEASE_LINE_RE,
        (
            f"**Current release: V{version}.** Trusted by {star_celebration}+ GitHub stargazers, "
            "this repository combines official and community skill collections with bundles, "
            "workflows, installation paths, and docs that help you go from first install to daily use quickly."
        ),
        content,
        count=1,
    )
    content = re.sub(
        r"^\*\*Antigravity Awesome Skills\*\* is a curated, battle-tested library of \*\*.*?\*\* designed",
        (
            f"**Antigravity Awesome Skills** is a curated, battle-tested library of "
            f"**{total_skills_label} high-performance agentic skills** designed"
        ),
        content,
        count=1,
        flags=re.MULTILINE,
    )
    content = re.sub(
        r"\[📚 Browse \d[\d,]*\+ Skills\]\(#browse-[^)]+\)",
        f"[📚 Browse {total_skills_label} Skills](#browse-{total_skills}-skills)",
        content,
        count=1,
    )
    content = re.sub(
        r"\*\*Welcome to the V[\d.]+ .*? Stars Celebration Release!\*\*",
        f"**Welcome to the V{version} {star_celebration} Stars Celebration Release!**",
        content,
        count=1,
    )
    content = re.sub(
        r"> \*\*🌟 .*? GitHub Stars Milestone!\*\*",
        f"> **🌟 {star_milestone} GitHub Stars Milestone!**",
        content,
        count=1,
    )
    content = re.sub(
        r"\*\*Antigravity Awesome Skills\*\* \(Release [\d.]+\) is a massive upgrade to your AI's capabilities, now featuring \*\*.*?\*\* skills",
        (
            f"**Antigravity Awesome Skills** (Release {version}) is a massive upgrade "
            f"to your AI's capabilities, now featuring **{total_skills_label} skills**"
        ),
        content,
        count=1,
    )
    content = re.sub(
        r"## Browse \d[\d,]*\+ Skills",
        f"## Browse {total_skills_label} Skills",
        content,
        count=1,
    )
    content = re.sub(
        r"<!-- registry-sync: .*? -->\n?",
        "",
        content,
        count=1,
    )
    return f"{sync_comment}\n{content.lstrip()}"


def update_readme(dry_run: bool = False, refresh_volatile: bool = False) -> dict:
    base_dir = find_repo_root(os.path.dirname(__file__))
    readme_path = os.path.join(base_dir, "README.md")
    metadata = load_metadata(base_dir, refresh_volatile=refresh_volatile)

    print(f"📖 Reading README from: {readme_path}")
    print(f"🔢 Total skills found: {metadata['total_skills']}")
    print(f"🏷️ Version found: {metadata['version']}")
    if metadata["used_live_star_count"]:
        print(f"⭐ Live GitHub stars found: {metadata['stars']}")
    else:
        print(f"⭐ Using existing README star count: {metadata['stars']}")

    with open(readme_path, "r", encoding="utf-8") as file:
        content = file.read()

    updated_content = apply_metadata(content, metadata)
    if dry_run:
        print("🧪 Dry run enabled; README.md not written.")
        return metadata

    with open(readme_path, "w", encoding="utf-8", newline="\n") as file:
        file.write(updated_content)

    print("✅ README.md updated successfully.")
    return metadata


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Sync generated metadata into README.md.")
    parser.add_argument("--dry-run", action="store_true", help="Compute metadata without writing files.")
    parser.add_argument(
        "--refresh-volatile",
        action="store_true",
        help="Refresh live star count and updated_at instead of preserving existing values.",
    )
    return parser.parse_args()


if __name__ == "__main__":
    configure_utf8_output()
    args = parse_args()
    update_readme(dry_run=args.dry_run, refresh_volatile=args.refresh_volatile)
