"""Argument parsing and URL resolution for the Reviewate CLI.

Pure functions, no async — used by main.py to build an argparse.Namespace.
"""

from __future__ import annotations

import argparse
import os
import re
import sys

KNOWN_SUBCOMMANDS = {"review", "summary", "full", "config"}


def _preprocess_argv(argv: list[str] | None = None) -> list[str]:
    """Insert 'review' subcommand if the first arg isn't a known subcommand."""
    if argv is None:
        argv = sys.argv[1:]
    # Don't prepend 'review' for --help/-h/--version so the top-level help is shown
    if not argv or argv[0] in ("-h", "--help", "--version"):
        return argv
    if argv[0] not in KNOWN_SUBCOMMANDS:
        return ["review"] + argv
    return argv


def _parse_pr_url(url: str) -> tuple[str, str, str, str | None]:
    """Parse a PR/MR URL into (platform, repo, pr_number, api_url_or_none).

    Supported formats:
      - GitHub:  https://github.com/owner/repo/pull/123
      - GitLab:  https://gitlab.com/group/project/-/merge_requests/123
      - GitLab (self-hosted): https://gitlab.example.com/group/project/-/merge_requests/123
      - GitLab (subgroups):   https://gitlab.example.com/g/sub/project/-/merge_requests/123
    """
    # GitHub: https://github.com/owner/repo/pull/123 (optional trailing path like /files)
    gh_match = re.match(r"https?://github\.com/([^/]+/[^/]+)/pull/(\d+)(?:/\w+)?/?$", url)
    if gh_match:
        repo, pr = gh_match.group(1), gh_match.group(2)
        return "github", repo, pr, None

    # GitLab: https://{host}/{repo_path}/-/merge_requests/{number}
    gl_match = re.match(r"https?://([^/]+)/(.+?)/-/merge_requests/(\d+)/?$", url)
    if gl_match:
        host, repo_path, pr = gl_match.group(1), gl_match.group(2), gl_match.group(3)
        if "/" not in repo_path:
            raise argparse.ArgumentTypeError(
                f"Invalid GitLab URL: repo path '{repo_path}' must contain at least owner/project"
            )
        api_url = None if host == "gitlab.com" else f"https://{host}/api/v4"
        return "gitlab", repo_path, pr, api_url

    raise argparse.ArgumentTypeError(
        f"Unrecognized PR/MR URL: {url}\n"
        "Expected formats:\n"
        "  GitHub:  https://github.com/owner/repo/pull/123\n"
        "  GitLab:  https://gitlab.com/group/project/-/merge_requests/123"
    )


def _add_common_args(parser: argparse.ArgumentParser) -> None:
    """Add shared flags to a subparser."""
    parser.add_argument(
        "repo",
        help="Repository 'owner/repo' or full PR/MR URL",
    )

    parser.add_argument(
        "-p",
        "--pr",
        required=False,
        default=None,
        help="Pull request or merge request ID/number (auto-detected from URL)",
    )

    parser.add_argument(
        "--platform",
        default="github",
        choices=["github", "gitlab"],
        help="Git platform (default: github)",
    )

    parser.add_argument(
        "--json",
        action="store_true",
        help="Output results as JSON (for benchmarking)",
    )

    parser.add_argument(
        "--disable-thinking",
        action="store_true",
        help="Disable extended thinking/reasoning (for non-thinking models)",
    )

    parser.add_argument(
        "--dry-run",
        action="store_true",
        help="Run review without posting to platform (for benchmarking)",
    )

    parser.add_argument(
        "--debug",
        action="store_true",
        help="Enable debug mode: fact checker explains reasons, reviews are logged",
    )

    parser.add_argument(
        "--review-model",
        help="Model for review agents (format: provider/model, e.g., anthropic/claude-sonnet-4)",
    )

    parser.add_argument(
        "--utility-model",
        help="Model for utility agents (format: provider/model, e.g., gemini/gemini-2.5-flash-lite)",
    )


def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
    """Parse command-line arguments"""
    parser = argparse.ArgumentParser(
        prog="reviewate",
        description="Reviewate - AI-powered code review for GitHub and GitLab",
        epilog=(
            "examples:\n"
            "  reviewate owner/repo -p 123                          review (default)\n"
            "  reviewate https://github.com/org/repo/pull/48        review from URL\n"
            "  reviewate summary owner/repo -p 123                  summary only\n"
            "  reviewate full owner/repo -p 123                     review + summary\n"
            "  reviewate review owner/repo -p 123 --dry-run         review without posting\n"
            "  reviewate config                                     re-run setup wizard\n"
            "\n"
            "docs: https://reviewate.com/docs"
        ),
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    subparsers = parser.add_subparsers(dest="command", title="commands", metavar="<command>")

    review_parser = subparsers.add_parser(
        "review",
        help="Run code review (default when no command specified)",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    _add_common_args(review_parser)

    summary_parser = subparsers.add_parser(
        "summary",
        help="Generate a PR/MR summary",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    _add_common_args(summary_parser)

    full_parser = subparsers.add_parser(
        "full",
        help="Run both review and summary",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    _add_common_args(full_parser)

    subparsers.add_parser("config", help="Re-run interactive model/provider setup")

    args = parser.parse_args(_preprocess_argv(argv))

    # Detect PR/MR URL and extract platform, repo, pr, api_url
    if hasattr(args, "repo") and args.repo and args.repo.startswith(("https://", "http://")):
        try:
            platform, repo, pr, api_url = _parse_pr_url(args.repo)
        except argparse.ArgumentTypeError as e:
            parser.error(str(e))
        args.platform = platform
        args.repo = repo
        args.pr = pr
        if api_url:
            os.environ["GITLAB_API_URL"] = api_url

    if hasattr(args, "pr") and args.pr is None:
        parser.error("-p/--pr is required when not using a PR/MR URL")

    # Map subcommand to review/summary booleans
    if args.command == "review":
        args.review = True
        args.summary = False
    elif args.command == "summary":
        args.review = False
        args.summary = True
    elif args.command == "full":
        args.review = True
        args.summary = True

    return args
