#!/usr/bin/env python3
"""Resolve and optionally verify a zhctprompt document-site URL."""

from __future__ import annotations

import argparse
import sys
import time
import urllib.error
import urllib.request
from pathlib import Path
from urllib.parse import quote


BASE_URL = "https://zhctpmt.yyangpt.cn/"


def find_repo_root(start: Path) -> Path:
    for candidate in (start, *start.parents):
        if (candidate / ".git").exists():
            return candidate.resolve()
    raise ValueError("cannot find the zhctprompt Git repository")


def resolve_target(target: str, repo_root: Path) -> tuple[Path, str, bool]:
    candidate = Path(target).expanduser()
    if not candidate.is_absolute():
        candidate = repo_root / candidate
    candidate = candidate.resolve()

    try:
        relative = candidate.relative_to(repo_root)
    except ValueError as exc:
        raise ValueError("target is outside the zhctprompt repository") from exc

    if not candidate.exists():
        raise ValueError("target does not exist")

    relative_path = relative.as_posix()
    is_directory = candidate.is_dir()
    if is_directory and relative_path not in ("", "."):
        relative_path += "/"
    return candidate, relative_path, is_directory


def build_url(relative_path: str) -> str:
    if relative_path in ("", "."):
        return BASE_URL
    return BASE_URL + quote(relative_path, safe="/-._~")


def verify_url(url: str, retries: int, delay: float, timeout: float) -> int:
    last_error = "not attempted"
    for attempt in range(1, retries + 1):
        request = urllib.request.Request(
            url,
            headers={"User-Agent": "zhctprompt-online-address-delivery/1.0"},
        )
        try:
            with urllib.request.urlopen(request, timeout=timeout) as response:
                status = response.getcode()
                if 200 <= status < 300:
                    return status
                last_error = f"HTTP {status}"
        except (urllib.error.URLError, TimeoutError) as exc:
            last_error = str(exc)
        if attempt < retries:
            time.sleep(delay)
    raise ValueError(f"online verification failed after {retries} attempts: {last_error}")


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Map a zhctprompt repository path to its document-site URL."
    )
    parser.add_argument("target", help="Repository-relative or absolute target path")
    parser.add_argument("--repo-root", type=Path, help="Override repository root")
    parser.add_argument("--check", action="store_true", help="Require an HTTP 2xx response")
    parser.add_argument("--retries", type=int, default=1, help="HTTP attempts when --check is used")
    parser.add_argument("--delay", type=float, default=3.0, help="Seconds between attempts")
    parser.add_argument("--timeout", type=float, default=15.0, help="HTTP timeout in seconds")
    return parser.parse_args()


def main() -> int:
    args = parse_args()
    try:
        repo_root = (
            args.repo_root.expanduser().resolve()
            if args.repo_root
            else find_repo_root(Path(__file__).resolve())
        )
        if repo_root.name != "zhctprompt":
            raise ValueError("repository root is not named zhctprompt")
        if args.retries < 1:
            raise ValueError("--retries must be at least 1")
        _, relative_path, _ = resolve_target(args.target, repo_root)
        url = build_url(relative_path)
        if args.check:
            status = verify_url(url, args.retries, args.delay, args.timeout)
            print(f"{url}\tHTTP {status}")
        else:
            print(url)
        return 0
    except ValueError as exc:
        print(f"error: {exc}", file=sys.stderr)
        return 2


if __name__ == "__main__":
    raise SystemExit(main())
