"""
OAuth credential management CLI commands.

Provides commands for managing OAuth credential profiles:
- add: Add a new OAuth profile via browser login
- list: List all OAuth profiles
- remove: Remove an OAuth profile
- set-default: Set the default profile for a provider
- refresh: Manually refresh a profile's OAuth token
"""

import os
import subprocess
import sys
from pathlib import Path
from typing import Optional

import click

from marsys.models.credentials import (
    OAuthCredentialStore,
    OAuthProfile,
    OAuthTokenRefresher,
    SUPPORTED_PROVIDERS,
)

_PROVIDER_CHOICES = ["anthropic-oauth", "openai-oauth", "google-oauth"]


@click.group()
def oauth():
    """Manage OAuth credential profiles.

    OAuth profiles allow you to use multiple accounts for Claude Max (anthropic-oauth),
    ChatGPT/Codex (openai-oauth), and Google Antigravity (google-oauth) subscriptions.

    \b
    Examples:
        marsys oauth list
        marsys oauth add work-claude --provider anthropic-oauth
        marsys oauth add my-google --provider google-oauth
        marsys oauth set-default anthropic-oauth work-claude
        marsys oauth refresh work-claude
    """
    pass


@oauth.command()
@click.argument("profile_name")
@click.option(
    "--provider",
    type=click.Choice(_PROVIDER_CHOICES),
    required=True,
    help="OAuth provider for this profile"
)
@click.option(
    "--set-default",
    is_flag=True,
    help="Set this profile as the default for its provider"
)
@click.option(
    "--description",
    default=None,
    help="Optional description for this profile"
)
@click.option(
    "--no-browser",
    is_flag=True,
    help="Manual mode: print auth URL instead of opening browser (google-oauth only)"
)
@click.option(
    "--port",
    default=0,
    type=int,
    help="Local port for OAuth callback (google-oauth only, 0=auto)"
)
def add(profile_name: str, provider: str, set_default: bool,
        description: Optional[str], no_browser: bool, port: int):
    """Add a new OAuth profile via browser login.

    This command will:
    1. Create a profile directory at ~/.marsys/oauth/<profile-name>/
    2. Launch the appropriate authentication flow
    3. Register the profile in the credential store

    \b
    Examples:
        marsys oauth add work-claude --provider anthropic-oauth
        marsys oauth add team-openai --provider openai-oauth --set-default
        marsys oauth add my-google --provider google-oauth
        marsys oauth add my-google --provider google-oauth --no-browser
    """
    store = OAuthCredentialStore.get_instance()

    # Check if profile already exists
    if store.get_profile(profile_name):
        click.echo(f"Error: Profile '{profile_name}' already exists.", err=True)
        click.echo("Use 'marsys oauth remove' first, or choose a different name.", err=True)
        sys.exit(1)

    if provider == "google-oauth":
        _add_google_oauth(profile_name, store, set_default, description, no_browser, port)
        return

    # Determine CLI tool and credential file name
    if provider == "anthropic-oauth":
        cli_tool = "claude"
        cli_login_cmd = "claude login"
        env_var = "CLAUDE_CONFIG_DIR"
        cred_file = ".credentials.json"
    elif provider == "openai-oauth":
        cli_tool = "codex"
        cli_login_cmd = "codex login"
        env_var = "CODEX_HOME"  # May vary, check codex docs
        cred_file = "auth.json"
    else:
        click.echo(f"Error: Unsupported provider '{provider}'", err=True)
        sys.exit(1)

    # Check if CLI tool is installed
    if not _is_command_available(cli_tool):
        click.echo(f"Error: '{cli_tool}' CLI is not installed.", err=True)
        if provider == "anthropic-oauth":
            click.echo("Install it with: npm install -g @anthropic-ai/claude-cli", err=True)
        else:
            click.echo("Install it with: npm install -g @openai/codex-cli", err=True)
        sys.exit(1)

    # Create profile directory
    profile_dir = Path.home() / ".marsys" / "oauth" / profile_name
    profile_dir.mkdir(parents=True, exist_ok=True)

    credentials_path = profile_dir / cred_file

    click.echo(f"\nCreating OAuth profile: {profile_name}")
    click.echo(f"Provider: {provider}")
    click.echo(f"Credentials will be stored at: {credentials_path}\n")

    # Set environment variable to redirect credential storage
    env = os.environ.copy()
    env[env_var] = str(profile_dir)

    click.echo(f"Launching '{cli_login_cmd}' for authentication...")
    click.echo("Please complete the login in your browser.\n")

    try:
        # Run the login command
        result = subprocess.run(
            [cli_tool, "login"],
            env=env,
            check=True,
        )
    except subprocess.CalledProcessError as e:
        click.echo(f"\nError: Login failed with exit code {e.returncode}", err=True)
        sys.exit(1)
    except FileNotFoundError:
        click.echo(f"\nError: '{cli_tool}' command not found", err=True)
        sys.exit(1)

    # Verify credentials were created
    if not credentials_path.exists():
        click.echo(f"\nError: Credentials file was not created at {credentials_path}", err=True)
        click.echo("The login may have failed or the CLI stores credentials elsewhere.", err=True)
        sys.exit(1)

    # Create and register profile
    profile = OAuthProfile(
        name=profile_name,
        provider=provider,
        credentials_path=str(credentials_path),
        description=description or f"Added via CLI",
    )

    store.add_profile(profile, set_as_default=set_default)
    store.save()

    click.echo(f"\nProfile '{profile_name}' created successfully!")
    if set_default:
        click.echo(f"Set as default for {provider}")


def _add_google_oauth(
    profile_name: str,
    store: OAuthCredentialStore,
    set_default: bool,
    description: Optional[str],
    no_browser: bool,
    port: int,
):
    """Handle Google OAuth PKCE flow for Antigravity gateway."""
    import base64
    import hashlib
    import json
    import secrets
    import socket
    import time
    import webbrowser
    from http.server import HTTPServer, BaseHTTPRequestHandler
    from urllib.parse import urlencode, urlparse, parse_qs

    from marsys.models.credentials import OAUTH_CONFIG

    config = OAUTH_CONFIG["google-oauth"]
    client_id = config["client_id"]
    scopes = config["scopes"]
    token_endpoint = config["token_endpoint"]

    # Generate PKCE code verifier and challenge
    code_verifier = secrets.token_urlsafe(64)[:128]
    code_challenge = base64.urlsafe_b64encode(
        hashlib.sha256(code_verifier.encode()).digest()
    ).rstrip(b"=").decode()

    # Generate CSRF state parameter
    oauth_state = secrets.token_urlsafe(32)

    # Find available port
    if port == 0:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.bind(("localhost", 0))
            port = s.getsockname()[1]

    redirect_uri = f"http://localhost:{port}/oauth-callback"

    # Build authorization URL (v2 endpoint)
    auth_params = {
        "client_id": client_id,
        "redirect_uri": redirect_uri,
        "response_type": "code",
        "scope": " ".join(scopes),
        "code_challenge": code_challenge,
        "code_challenge_method": "S256",
        "access_type": "offline",
        "prompt": "consent",
        "state": oauth_state,
    }
    auth_url = f"https://accounts.google.com/o/oauth2/v2/auth?{urlencode(auth_params)}"

    # Profile directory and credentials path
    profile_dir = Path.home() / ".marsys" / "oauth" / profile_name
    profile_dir.mkdir(parents=True, exist_ok=True)
    credentials_path = profile_dir / "credentials.json"

    click.echo(f"\nCreating OAuth profile: {profile_name}")
    click.echo(f"Provider: google-oauth")
    click.echo(f"Credentials will be stored at: {credentials_path}\n")

    # State for capturing the authorization code
    auth_code = [None]
    auth_error = [None]

    class OAuthCallbackHandler(BaseHTTPRequestHandler):
        def do_GET(self):
            parsed = urlparse(self.path)
            params = parse_qs(parsed.query)

            # Validate CSRF state parameter
            returned_state = params.get("state", [None])[0]
            if returned_state != oauth_state:
                auth_error[0] = "State parameter mismatch (possible CSRF attack)"
                self.send_response(400)
                self.send_header("Content-Type", "text/html")
                self.end_headers()
                self.wfile.write(b"<html><body><h2>Authentication failed</h2>"
                                b"<p>State parameter mismatch.</p></body></html>")
                return

            if "code" in params:
                auth_code[0] = params["code"][0]
                self.send_response(200)
                self.send_header("Content-Type", "text/html")
                self.end_headers()
                self.wfile.write(b"<html><body><h2>Authentication successful!</h2>"
                                b"<p>You can close this tab and return to the terminal.</p>"
                                b"</body></html>")
            elif "error" in params:
                auth_error[0] = params.get("error_description", params["error"])[0]
                self.send_response(400)
                self.send_header("Content-Type", "text/html")
                self.end_headers()
                self.wfile.write(f"<html><body><h2>Authentication failed</h2>"
                                f"<p>{auth_error[0]}</p></body></html>".encode())
            else:
                self.send_response(404)
                self.end_headers()

        def log_message(self, format, *args):
            pass  # Suppress HTTP server logs

    if no_browser:
        # Manual mode: print URL and accept either bare code or full redirect URL
        click.echo("Open the following URL in your browser:")
        click.echo(f"\n  {auth_url}\n")
        click.echo("After authorizing, you will be redirected to a localhost URL.")
        click.echo("Paste the FULL redirect URL or just the authorization code below.\n")
        user_input = click.prompt("Authorization code or redirect URL")

        # Check if user pasted a full URL
        if user_input.startswith("http://") or user_input.startswith("https://"):
            parsed_url = urlparse(user_input)
            url_params = parse_qs(parsed_url.query)
            # Validate state if present in the URL
            returned_state = url_params.get("state", [None])[0]
            if returned_state and returned_state != oauth_state:
                click.echo("\nError: State parameter mismatch (possible CSRF attack).", err=True)
                sys.exit(1)
            code = url_params.get("code", [None])[0]
            if not code:
                click.echo("\nError: No 'code' parameter found in the URL.", err=True)
                sys.exit(1)
            auth_code[0] = code
        else:
            auth_code[0] = user_input.strip()
    else:
        # Start local server to receive callback
        server = HTTPServer(("localhost", port), OAuthCallbackHandler)
        server.timeout = 120

        click.echo("Opening browser for Google authentication...")
        click.echo(f"If the browser doesn't open, visit:\n  {auth_url}\n")
        webbrowser.open(auth_url)

        click.echo("Waiting for authorization (timeout: 120s)...")
        server.handle_request()
        server.server_close()

    if auth_error[0]:
        click.echo(f"\nError: Authentication failed: {auth_error[0]}", err=True)
        sys.exit(1)

    if not auth_code[0]:
        click.echo("\nError: No authorization code received.", err=True)
        sys.exit(1)

    # Exchange authorization code for tokens
    click.echo("Exchanging authorization code for tokens...")

    import requests
    client_secret = config.get("client_secret", "")
    token_response = requests.post(
        token_endpoint,
        data={
            "grant_type": "authorization_code",
            "client_id": client_id,
            "client_secret": client_secret,
            "code": auth_code[0],
            "redirect_uri": redirect_uri,
            "code_verifier": code_verifier,
        },
        headers={"Content-Type": "application/x-www-form-urlencoded"},
        timeout=30,
    )

    if token_response.status_code != 200:
        click.echo(f"\nError: Token exchange failed: {token_response.text}", err=True)
        sys.exit(1)

    tokens = token_response.json()

    # Resolve project ID via loadCodeAssist
    project_id = _resolve_google_project_id(tokens["access_token"])

    # Build credentials file
    cred_data = {
        "access_token": tokens["access_token"],
        "refresh_token": tokens.get("refresh_token"),
        "token_type": tokens.get("token_type", "Bearer"),
        "expires_at": int(time.time()) + tokens.get("expires_in", 3600),
        "project_id": project_id,
        "project_id_resolved_at": int(time.time()) if project_id else 0,
    }

    # Write with secure permissions
    import stat
    with open(credentials_path, "w") as f:
        json.dump(cred_data, f, indent=2)
    os.chmod(credentials_path, stat.S_IRUSR | stat.S_IWUSR)

    # Create and register profile
    profile = OAuthProfile(
        name=profile_name,
        provider="google-oauth",
        credentials_path=str(credentials_path),
        description=description or "Added via CLI (Google OAuth PKCE)",
    )

    store.add_profile(profile, set_as_default=set_default)
    store.save()

    click.echo(f"\nProfile '{profile_name}' created successfully!")
    if set_default:
        click.echo(f"Set as default for google-oauth")


@oauth.command("list")
@click.option(
    "--provider",
    type=click.Choice(_PROVIDER_CHOICES),
    default=None,
    help="Filter by provider"
)
def list_profiles(provider: Optional[str]):
    """List all OAuth profiles.

    Shows profile name, provider, credentials path, and whether it's the default.

    \b
    Examples:
        marsys oauth list
        marsys oauth list --provider anthropic-oauth
    """
    store = OAuthCredentialStore.get_instance()
    profiles = store.list_profiles(provider)

    if not profiles:
        if provider:
            click.echo(f"No profiles found for provider '{provider}'")
        else:
            click.echo("No OAuth profiles configured.")
        click.echo("\nUse 'marsys oauth add <name> --provider <provider>' to add one.")
        return

    # Get defaults for marking
    defaults = {p: store.get_default(p) for p in SUPPORTED_PROVIDERS}

    # Header
    click.echo(f"\n{'Profile':<20} {'Provider':<18} {'Path':<45} {'Status':<10}")
    click.echo("-" * 95)

    for profile in profiles:
        is_default = defaults.get(profile.provider) == profile.name
        status = "default" if is_default else ""
        if profile.exists():
            if not profile.is_valid_format():
                status = "invalid"
        else:
            status = "missing"

        path_str = profile.credentials_path
        if len(path_str) > 43:
            path_str = "..." + path_str[-40:]

        click.echo(f"{profile.name:<20} {profile.provider:<18} {path_str:<45} {status:<10}")

    click.echo()


@oauth.command()
@click.argument("profile_name")
@click.option(
    "--force", "-f",
    is_flag=True,
    help="Remove without confirmation"
)
def remove(profile_name: str, force: bool):
    """Remove an OAuth profile.

    This removes the profile from the credential store but does NOT delete
    the credentials file. You can re-add the profile later.

    \b
    Examples:
        marsys oauth remove work-claude
        marsys oauth remove work-claude --force
    """
    store = OAuthCredentialStore.get_instance()
    profile = store.get_profile(profile_name)

    if not profile:
        click.echo(f"Error: Profile '{profile_name}' not found.", err=True)
        sys.exit(1)

    if not force:
        click.confirm(
            f"Remove profile '{profile_name}'? (Credentials file will not be deleted)",
            abort=True
        )

    store.remove_profile(profile_name)
    store.save()

    click.echo(f"Profile '{profile_name}' removed.")


@oauth.command("set-default")
@click.argument("provider", type=click.Choice(_PROVIDER_CHOICES))
@click.argument("profile_name")
def set_default(provider: str, profile_name: str):
    """Set the default profile for a provider.

    The default profile is used when no oauth_profile is specified in the
    ModelConfig.

    \b
    Examples:
        marsys oauth set-default anthropic-oauth work-claude
        marsys oauth set-default openai-oauth team-openai
        marsys oauth set-default google-oauth my-google
    """
    store = OAuthCredentialStore.get_instance()

    try:
        store.set_default(provider, profile_name)
        store.save()
        click.echo(f"Set '{profile_name}' as default for {provider}")
    except Exception as e:
        click.echo(f"Error: {e}", err=True)
        sys.exit(1)


@oauth.command()
@click.argument("profile_name")
@click.option(
    "--force", "-f",
    is_flag=True,
    help="Force refresh even if token is not expiring"
)
def refresh(profile_name: str, force: bool):
    """Manually refresh a profile's OAuth token.

    Tokens are normally refreshed automatically before expiration.
    Use this command to manually trigger a refresh.

    \b
    Examples:
        marsys oauth refresh work-claude
        marsys oauth refresh work-claude --force
    """
    store = OAuthCredentialStore.get_instance()
    profile = store.get_profile(profile_name)

    if not profile:
        click.echo(f"Error: Profile '{profile_name}' not found.", err=True)
        sys.exit(1)

    if not profile.exists():
        click.echo(f"Error: Credentials file not found at {profile.resolved_path}", err=True)
        sys.exit(1)

    click.echo(f"Refreshing OAuth token for '{profile_name}'...")

    try:
        refreshed = OAuthTokenRefresher.refresh_if_needed(
            str(profile.resolved_path),
            profile.provider,
            force=force
        )

        if refreshed:
            click.echo("Token refreshed successfully!")
        else:
            if force:
                click.echo("Token refresh was not needed or failed.")
            else:
                click.echo("Token is still valid, no refresh needed.")
                click.echo("Use --force to refresh anyway.")

    except Exception as e:
        click.echo(f"Error refreshing token: {e}", err=True)
        sys.exit(1)


@oauth.command("test")
@click.argument("profile_name", default=None, required=False)
def test_oauth(profile_name: Optional[str]):
    """Run diagnostics on a Google OAuth profile.

    Tests token validity, calls loadCodeAssist to inspect project/tier info,
    and makes test inference requests to verify model access.

    \b
    Examples:
        marsys oauth test
        marsys oauth test my-google
    """
    import json
    import time

    store = OAuthCredentialStore.get_instance()

    # Find profile: explicit name, default google-oauth, or first google-oauth profile
    profile = None
    if profile_name:
        profile = store.get_profile(profile_name)
        if not profile:
            click.echo(f"Error: Profile '{profile_name}' not found.", err=True)
            sys.exit(1)
    else:
        profile = store.get_default_profile("google-oauth")
        if not profile:
            profiles = store.list_profiles("google-oauth")
            if profiles:
                profile = profiles[0]
        if not profile:
            click.echo("Error: No google-oauth profiles found.", err=True)
            click.echo("Add one with: marsys oauth add <name> --provider google-oauth", err=True)
            sys.exit(1)

    if profile.provider != "google-oauth":
        click.echo(f"Error: Profile '{profile.name}' is not a google-oauth profile (provider: {profile.provider}).", err=True)
        sys.exit(1)

    click.echo(f"\n=== Google OAuth Diagnostic ===")
    click.echo(f"Profile: {profile.name}")

    # Load credentials
    cred_path = profile.resolved_path
    if not cred_path or not Path(cred_path).exists():
        click.echo(f"Error: Credentials file not found at {cred_path}", err=True)
        sys.exit(1)

    with open(cred_path) as f:
        creds = json.load(f)

    access_token = creds.get("access_token")
    refresh_token = creds.get("refresh_token")
    expires_at = creds.get("expires_at", 0)
    stored_project_id = creds.get("project_id")
    resolved_at = creds.get("project_id_resolved_at", 0)

    # Token status
    now = time.time()
    expires_at_sec = expires_at / 1000 if expires_at > 10**12 else expires_at
    remaining = expires_at_sec - now
    if remaining > 0:
        click.echo(f"Token: valid (expires in {int(remaining)}s)")
    else:
        click.echo(f"Token: EXPIRED ({int(-remaining)}s ago)")
        if refresh_token:
            click.echo("Attempting token refresh...")
            try:
                refreshed = OAuthTokenRefresher.refresh_if_needed(
                    str(cred_path), "google-oauth", force=True
                )
                if refreshed:
                    click.echo("Token refreshed successfully.")
                    with open(cred_path) as f:
                        creds = json.load(f)
                    access_token = creds.get("access_token")
                else:
                    click.echo("Warning: Token refresh did not succeed.", err=True)
            except Exception as e:
                click.echo(f"Token refresh failed: {e}", err=True)
                sys.exit(1)

    # Stored project info
    if stored_project_id:
        age = int(now - resolved_at) if resolved_at else 0
        age_str = f"{age // 3600}h{(age % 3600) // 60}m ago" if age else "unknown"
        click.echo(f"Stored project_id: {stored_project_id} (resolved {age_str})")
    else:
        click.echo("Stored project_id: (none)")

    # Discovery test
    click.echo(f"\nDiscovery (loadCodeAssist):")
    import requests as _requests
    import platform as _platform

    sys_name = _platform.system().lower()
    machine = _platform.machine().lower()
    arch = "amd64" if machine in ("x86_64", "amd64") else ("arm64" if machine in ("arm64", "aarch64") else machine)

    version = "1.16.5"
    try:
        vr = _requests.get(
            "https://antigravity-auto-updater-974169037036.us-central1.run.app",
            timeout=3,
        )
        if vr.status_code == 200 and vr.text.strip() and vr.text.strip()[0].isdigit():
            version = vr.text.strip()
    except Exception:
        pass

    metadata = {
        "ideType": "ANTIGRAVITY",
        "platform": "PLATFORM_UNSPECIFIED",
        "pluginType": "GEMINI",
    }
    discovery_headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json",
        "User-Agent": f"antigravity/{version} {sys_name}/{arch}",
        "X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
        "Client-Metadata": json.dumps(metadata),
    }
    discovery_body = {"metadata": metadata}

    endpoints = [
        ("production", "https://cloudcode-pa.googleapis.com"),
        ("daily", "https://daily-cloudcode-pa.sandbox.googleapis.com"),
        ("autopush", "https://autopush-cloudcode-pa.sandbox.googleapis.com"),
    ]

    discovery_project = None
    discovery_data = None
    for label, ep in endpoints:
        try:
            resp = _requests.post(
                f"{ep}/v1internal:loadCodeAssist",
                json=discovery_body, headers=discovery_headers, timeout=10,
            )
            if resp.status_code == 200:
                data = resp.json()
                discovery_data = data
                project = data.get("cloudaicompanionProject")
                if isinstance(project, dict):
                    project = project.get("id")
                current_tier = data.get("currentTier")
                if isinstance(current_tier, dict):
                    current_tier = current_tier.get("id") or current_tier.get("tierId")
                paid_tier = data.get("paidTier")
                if isinstance(paid_tier, dict):
                    paid_tier = paid_tier.get("id") or paid_tier.get("tierId")
                allowed = data.get("allowedTiers", [])
                click.echo(
                    f"  {label}: {resp.status_code} — "
                    f"project={project}, currentTier={current_tier}, "
                    f"paidTier={paid_tier}, allowedTiers={len(allowed)}"
                )
                if project and not discovery_project:
                    discovery_project = project
            else:
                click.echo(f"  {label}: {resp.status_code} — {resp.text[:200]}")
        except Exception as e:
            click.echo(f"  {label}: FAILED — {e}")

    # Inference tests
    click.echo(f"\nInference Test:")
    test_models = [
        ("gemini-2.5-flash", "Free-tier model"),
        ("claude-sonnet-4-6", "Pro-tier model"),
    ]

    inference_headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json",
        "User-Agent": f"antigravity/{version} {sys_name}/{arch}",
        "Accept": "text/event-stream",
        "X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
        "Client-Metadata": json.dumps(metadata),
    }

    test_project = discovery_project or stored_project_id
    if not test_project:
        click.echo("  Skipping inference tests (no project_id available)")
    else:
        inference_ep = "https://cloudcode-pa.googleapis.com"
        for model_name, tier_label in test_models:
            payload = {
                "project": test_project,
                "model": model_name,
                "request": {
                    "contents": [{"role": "user", "parts": [{"text": "Say hello"}]}],
                    "generationConfig": {"maxOutputTokens": 50, "temperature": 0.1},
                },
                "requestType": "agent",
                "userAgent": "antigravity",
                "requestId": f"diag-{model_name}",
            }
            try:
                resp = _requests.post(
                    f"{inference_ep}/v1internal:streamGenerateContent?alt=sse",
                    json=payload, headers=inference_headers, timeout=15,
                )
                if resp.status_code == 200:
                    click.echo(f"  {model_name}: \u2713 {resp.status_code} OK ({tier_label})")
                else:
                    # Try to extract error detail
                    detail = ""
                    try:
                        err_data = resp.json()
                        detail = err_data.get("error", {}).get("status", resp.text[:150])
                    except Exception:
                        detail = resp.text[:150]
                    click.echo(f"  {model_name}: \u2717 {resp.status_code} {detail} ({tier_label})")
            except Exception as e:
                click.echo(f"  {model_name}: \u2717 FAILED — {e}")

    # Diagnosis
    click.echo(f"\nDiagnosis:")
    if discovery_data:
        paid = discovery_data.get("paidTier")
        if isinstance(paid, dict):
            paid = paid.get("id") or paid.get("tierId")
        current = discovery_data.get("currentTier")
        if isinstance(current, dict):
            current = current.get("id") or current.get("tierId")

        if paid and "pro" in str(paid).lower():
            click.echo(f"  Paid tier detected: {paid}")
            if stored_project_id and stored_project_id != discovery_project:
                click.echo(f"  WARNING: Stored project_id ({stored_project_id}) differs from discovery ({discovery_project}).")
                click.echo(f"  Run 'marsys oauth reset-project {profile.name}' to clear stale project.")
            else:
                click.echo("  Project and tier look correct.")
        elif current and "free" in str(current).lower() and not paid:
            click.echo(f"  Current tier is '{current}' with no paid tier detected.")
            click.echo(f"  If you have AI Pro, try: marsys oauth reset-project {profile.name}")
            click.echo("  Then re-run: marsys oauth test")
        else:
            click.echo(f"  currentTier={current}, paidTier={paid}")
    else:
        click.echo("  Could not retrieve discovery data from any endpoint.")
    click.echo()


@oauth.command("reset-project")
@click.argument("profile_name", default=None, required=False)
def reset_project(profile_name: Optional[str]):
    """Clear the cached project_id to force re-discovery.

    Use this when you suspect a stale free-tier project is being used
    despite having an AI Pro subscription. After reset, the next API call
    will re-run loadCodeAssist to resolve the correct project.

    \b
    Examples:
        marsys oauth reset-project
        marsys oauth reset-project my-google
    """
    import json

    store = OAuthCredentialStore.get_instance()

    # Find profile
    profile = None
    if profile_name:
        profile = store.get_profile(profile_name)
        if not profile:
            click.echo(f"Error: Profile '{profile_name}' not found.", err=True)
            sys.exit(1)
    else:
        profile = store.get_default_profile("google-oauth")
        if not profile:
            profiles = store.list_profiles("google-oauth")
            if profiles:
                profile = profiles[0]
        if not profile:
            click.echo("Error: No google-oauth profiles found.", err=True)
            sys.exit(1)

    if profile.provider != "google-oauth":
        click.echo(f"Error: Profile '{profile.name}' is not a google-oauth profile.", err=True)
        sys.exit(1)

    cred_path = Path(profile.resolved_path)
    if not cred_path.exists():
        click.echo(f"Error: Credentials file not found at {cred_path}", err=True)
        sys.exit(1)

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

    old_project = data.get("project_id")

    if isinstance(data, dict):
        data["project_id"] = None
        data["project_id_resolved_at"] = 0
    elif isinstance(data, list) and data:
        data[0]["projectId"] = None
        data[0]["project_id"] = None

    import stat as _stat
    with open(cred_path, "w") as f:
        json.dump(data, f, indent=2)
    os.chmod(cred_path, _stat.S_IRUSR | _stat.S_IWUSR)

    click.echo(f"Cleared project_id for profile '{profile.name}'.")
    if old_project:
        click.echo(f"  Previous: {old_project}")
    click.echo("The project will be re-resolved on next API call via loadCodeAssist.")
    click.echo(f"Run 'marsys oauth test {profile.name}' to verify.")


def _resolve_google_project_id(access_token: str) -> Optional[str]:
    """
    Resolve the user's GCP project ID via loadCodeAssist.

    Tries production endpoint first, then daily sandbox and autopush.
    Only calls onboardUser if loadCodeAssist indicates the user has no
    currentTier AND allowedTiers are available (uses the default tier,
    NOT a hardcoded "free-tier").

    Uses ideType=ANTIGRAVITY / PLATFORM_UNSPECIFIED metadata matching
    the Antigravity IDE's discovery calls.
    """
    import json
    import platform as _platform
    import requests as _requests

    endpoints = [
        "https://cloudcode-pa.googleapis.com",
        "https://daily-cloudcode-pa.sandbox.googleapis.com",
        "https://autopush-cloudcode-pa.sandbox.googleapis.com",
    ]

    # Detect platform for User-Agent (matching adapter)
    sys_name = _platform.system().lower()
    machine = _platform.machine().lower()
    if machine in ("x86_64", "amd64"):
        arch = "amd64"
    elif machine in ("arm64", "aarch64"):
        arch = "arm64"
    else:
        arch = machine

    # Fetch version (best-effort)
    version = "1.16.5"
    try:
        vr = _requests.get(
            "https://antigravity-auto-updater-974169037036.us-central1.run.app",
            timeout=3,
        )
        if vr.status_code == 200 and vr.text.strip() and vr.text.strip()[0].isdigit():
            version = vr.text.strip()
    except Exception:
        pass

    metadata = {
        "ideType": "ANTIGRAVITY",
        "platform": "PLATFORM_UNSPECIFIED",
        "pluginType": "GEMINI",
    }
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json",
        "User-Agent": f"antigravity/{version} {sys_name}/{arch}",
        "X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
        "Client-Metadata": json.dumps(metadata),
    }
    body = {"metadata": metadata}

    def _extract_project(data):
        project = data.get("cloudaicompanionProject")
        if isinstance(project, dict):
            return project.get("id")
        if isinstance(project, str) and project:
            return project
        return None

    def _extract_tier(data, key):
        tier_data = data.get(key)
        if isinstance(tier_data, dict):
            return tier_data.get("id") or tier_data.get("tierId")
        if isinstance(tier_data, str):
            return tier_data
        return None

    def _find_default_tier(allowed_tiers):
        if not allowed_tiers:
            return None
        for tier in allowed_tiers:
            if tier.get("isDefault", False):
                return tier.get("id") or tier.get("tierId")
        first = allowed_tiers[0]
        return first.get("id") or first.get("tierId")

    # Try loadCodeAssist on each endpoint
    last_discovery_data = None
    for ep in endpoints:
        try:
            resp = _requests.post(
                f"{ep}/v1internal:loadCodeAssist",
                json=body, headers=headers, timeout=10,
            )
            if resp.status_code == 200:
                data = resp.json()
                last_discovery_data = data
                pid = _extract_project(data)
                if pid:
                    effective_tier = _extract_tier(data, "paidTier") or _extract_tier(data, "currentTier")
                    click.echo(f"Resolved project ID: {pid} (tier: {effective_tier or 'unknown'})")
                    return pid
            else:
                click.echo(f"  loadCodeAssist {ep} returned {resp.status_code}: {resp.text[:300]}", err=True)
        except Exception:
            continue

    # Only attempt onboardUser when loadCodeAssist returned data but no
    # project/currentTier AND allowedTiers are available
    if last_discovery_data is not None:
        current_tier = _extract_tier(last_discovery_data, "currentTier")
        project_id = _extract_project(last_discovery_data)
        allowed_tiers = last_discovery_data.get("allowedTiers", [])

        if current_tier is None and project_id is None and allowed_tiers:
            default_tier = _find_default_tier(allowed_tiers)
            if default_tier:
                click.echo(f"No current tier found, onboarding with default tier: {default_tier}")
                onboard_body = {"tierId": default_tier, "metadata": metadata}
                for ep in endpoints:
                    try:
                        resp = _requests.post(
                            f"{ep}/v1internal:onboardUser",
                            json=onboard_body, headers=headers, timeout=15,
                        )
                        if resp.status_code == 200:
                            pid = _extract_project(resp.json())
                            if pid:
                                click.echo(f"Provisioned and resolved project ID: {pid}")
                                return pid
                        else:
                            click.echo(f"  onboardUser {ep} returned {resp.status_code}: {resp.text[:300]}", err=True)
                    except Exception:
                        continue

    click.echo("Warning: Could not resolve project ID. It will be resolved on first API call.", err=True)
    return None


def _is_command_available(cmd: str) -> bool:
    """Check if a command is available in PATH."""
    import shutil
    return shutil.which(cmd) is not None
