#!/usr/bin/env python3
"""
shebang - CLI tool for shebang.run
"""

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

try:
    from shebangrun import ShebangClient, run
except ImportError:
    print("Error: shebangrun library not found", file=sys.stderr)
    print("Install with: pip install shebangrun", file=sys.stderr)
    sys.exit(1)

CONFIG_FILE = Path.home() / '.shebangrc'


def substitute_secrets(content, config):
    """Substitute ${SECRET:name} with actual secret values"""
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Warning: Not logged in, cannot substitute secrets", file=sys.stderr)
        return content
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    # Find all ${SECRET:name} patterns
    pattern = re.compile(r'\$\{SECRET:([A-Za-z0-9_]+)\}')
    
    def replace_secret(match):
        secret_name = match.group(1)
        try:
            value = client.get_secret(secret_name)
            return value
        except Exception as e:
            print(f"Warning: Could not retrieve secret '{secret_name}': {e}", file=sys.stderr)
            return match.group(0)  # Return original if failed
    
    return pattern.sub(replace_secret, content)


def load_config():
    """Load configuration from ~/.shebangrc"""
    config = {}
    if CONFIG_FILE.exists():
        with open(CONFIG_FILE) as f:
            for line in f:
                line = line.strip()
                if line and not line.startswith('#') and '=' in line:
                    key, value = line.split('=', 1)
                    config[key] = value.strip('"')
    return config

def save_config(config):
    """Save configuration to ~/.shebangrc"""
    with open(CONFIG_FILE, 'w') as f:
        f.write('# shebang.run CLI configuration\n')
        for key, value in config.items():
            f.write(f'{key}="{value}"\n')
    CONFIG_FILE.chmod(0o600)

def cmd_login(args):
    """Login and generate API credentials"""
    print("shebang.run Login")
    print("=" * 50)
    print()
    
    url = input("Server URL [https://shebang.run]: ").strip() or "https://shebang.run"
    username = input("Username: ").strip()
    if not username:
        print("Error: Username required", file=sys.stderr)
        sys.exit(1)
    
    import getpass
    password = getpass.getpass("Password: ")
    if not password:
        print("Error: Password required", file=sys.stderr)
        sys.exit(1)
    
    key_path = input("Private Key Path (optional): ").strip()
    
    # Login
    print("Logging in...")
    client = ShebangClient(url=url.replace('https://', '').replace('http://', ''))
    
    try:
        response = client.login(username, password)
        token = response['token']
    except Exception as e:
        print(f"Error: Login failed - {e}", file=sys.stderr)
        sys.exit(1)
    
    # Generate API token
    print("Generating API credentials...")
    try:
        import datetime
        token_name = f"CLI-{datetime.datetime.now().strftime('%Y%m%d-%H%M%S')}"
        api_token = client.create_api_token(token_name)
        
        config = {
            'SHEBANG_URL': url,
            'SHEBANG_USERNAME': username,
            'SHEBANG_CLIENT_ID': api_token['client_id'],
            'SHEBANG_CLIENT_SECRET': api_token['client_secret'],
            'SHEBANG_KEY_PATH': key_path
        }
        save_config(config)
        
        print("✓ API credentials generated!")
        print()
        print(f"Client ID: {api_token['client_id']}")
        print(f"Client Secret: {api_token['client_secret'][:20]}...")
        print()
        print(f"Config saved to {CONFIG_FILE}")
        print("Keep your credentials secure!")
        
    except Exception as e:
        print(f"Error: Failed to generate API credentials - {e}", file=sys.stderr)
        sys.exit(1)

def cmd_list(args):
    """List scripts"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    print("Your Scripts:")
    print("=" * 50)
    
    try:
        scripts = client.list_scripts()
        if not scripts:
            print("(no scripts)")
        else:
            for s in scripts:
                vis = s['visibility']
                color = '\033[0;32m' if vis == 'public' else '\033[1;33m' if vis == 'unlisted' else '\033[0;31m'
                print(f"{color}{s['name']}\033[0m (v{s['version']}) - {s.get('description', 'No description')} [{vis}]")
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)
    
    # Show shared scripts unless hidden
    if not args.hide_shared:
        print()
        print("Shared With You:")
        print("=" * 50)
        
        try:
            shared = client.list_shared_scripts()
            if not shared:
                print("(no shared scripts)")
            else:
                for s in shared:
                    print(f"\033[1;33m{s['owner']}/{s['name']}\033[0m (v{s['version']}) - {s.get('description', 'No description')}")
        except Exception as e:
            print(f"Error loading shared scripts: {e}", file=sys.stderr)
    
    if args.community:
        print()
        print("Community Scripts:")
        print("=" * 50)
        
        try:
            import requests
            response = requests.get(
                f"{config['SHEBANG_URL']}/api/community/scripts",
                auth=(config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
            )
            response.raise_for_status()
            scripts = response.json()
            
            if not scripts:
                print("(no community scripts)")
            else:
                for s in scripts:
                    print(f"\033[0;32m{s['username']}/{s['name']}\033[0m (v{s['version']}) - {s.get('description', 'No description')}")
        except Exception as e:
            print(f"Error loading community scripts: {e}", file=sys.stderr)

def cmd_search(args):
    """Search scripts"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    if not args.query:
        print("Error: Search query required", file=sys.stderr)
        sys.exit(1)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    query = args.query.lower()
    
    print(f"Searching for: {args.query}")
    print()
    
    try:
        scripts = client.list_scripts()
        found = False
        for s in scripts:
            if query in s['name'].lower() or query in s.get('description', '').lower():
                found = True
                vis = s['visibility']
                color = '\033[0;32m' if vis == 'public' else '\033[1;33m' if vis == 'unlisted' else '\033[0;31m'
                print(f"{color}{s['name']}\033[0m (v{s['version']}) - {s.get('description', 'No description')} [{vis}]")
        
        if not found:
            print("No matches in your scripts")
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
    
    if args.community:
        print()
        print("Community Results:")
        
        try:
            import requests
            response = requests.get(
                f"{config['SHEBANG_URL']}/api/community/scripts",
                auth=(config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
            )
            scripts = response.json()
            found = False
            for s in scripts:
                if query in s['name'].lower() or query in s.get('description', '').lower() or query in s['username'].lower():
                    found = True
                    print(f"\033[0;32m{s['username']}/{s['name']}\033[0m (v{s['version']}) - {s.get('description', 'No description')}")
            
            if not found:
                print("No matches in community")
        except Exception as e:
            print(f"Error: {e}", file=sys.stderr)

def cmd_get(args):
    """Get a script"""
    config = load_config()
    
    user = args.user or config.get('SHEBANG_USERNAME')
    if not user:
        print("Error: Username required. Use -u or login first.", file=sys.stderr)
        sys.exit(1)
    
    key_path = args.key or config.get('SHEBANG_KEY_PATH')
    key_content = None
    if key_path:
        if not os.path.exists(key_path):
            print(f"Error: Private key not found at: {key_path}", file=sys.stderr)
            print("Update SHEBANG_KEY_PATH in ~/.shebangrc or use -k to specify key", file=sys.stderr)
            sys.exit(1)
        try:
            with open(key_path) as f:
                key_content = f.read()
        except Exception as e:
            print(f"Error: Could not read private key: {e}", file=sys.stderr)
            sys.exit(1)
    
    try:
        content = run(
            username=user,
            script=args.script,
            key=key_content,
            url=config.get('SHEBANG_URL', 'shebang.run').replace('https://', '').replace('http://', '')
        )
        
        # Substitute secrets if requested
        if args.secrets:
            content = substitute_secrets(content, config)
        
        if args.output:
            with open(args.output, 'w') as f:
                f.write(content)
            print(f"✓ Script saved to: {args.output}")
        else:
            print(content)
            
    except Exception as e:
        error_msg = str(e)
        if "encrypted" in error_msg.lower() or "decrypt" in error_msg.lower():
            print(f"Error: Failed to decrypt script", file=sys.stderr)
            if not key_content:
                print("This appears to be an encrypted script. Provide a private key with -k or set SHEBANG_KEY_PATH", file=sys.stderr)
            else:
                print(f"Decryption failed. Verify the key at {key_path} is correct for this script", file=sys.stderr)
        else:
            print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_run(args):
    """Run a script"""
    config = load_config()
    
    user = args.user or config.get('SHEBANG_USERNAME')
    if not user:
        print("Error: Username required. Use -u or login first.", file=sys.stderr)
        sys.exit(1)
    
    key_path = args.key or config.get('SHEBANG_KEY_PATH')
    key_content = None
    if key_path:
        if not os.path.exists(key_path):
            print(f"Error: Private key not found at: {key_path}", file=sys.stderr)
            print("Update SHEBANG_KEY_PATH in ~/.shebangrc or use -k to specify key", file=sys.stderr)
            sys.exit(1)
        try:
            with open(key_path) as f:
                key_content = f.read()
        except Exception as e:
            print(f"Error: Could not read private key: {e}", file=sys.stderr)
            sys.exit(1)
    
    try:
        content = run(
            username=user,
            script=args.script,
            key=key_content,
            url=config.get('SHEBANG_URL', 'shebang.run').replace('https://', '').replace('http://', '')
        )
        
        # Always substitute secrets for run
        content = substitute_secrets(content, config)
        
        # Save to temp file or specified output
        import tempfile
        if args.output:
            script_file = args.output
        else:
            fd, script_file = tempfile.mkstemp(suffix=f'-{args.script}')
            os.close(fd)
        
        with open(script_file, 'w') as f:
            f.write(content)
        os.chmod(script_file, 0o755)
        
        # Show script and prompt if not auto-accept
        if not args.accept:
            print()
            print("Script content:")
            print("=" * 60)
            print(content)
            print("=" * 60)
            print()
            confirm = input("Execute this script? (y/N): ").strip().lower()
            if confirm != 'y':
                if not args.output:
                    os.unlink(script_file)
                print("Execution cancelled")
                sys.exit(0)
        
        # Execute script
        print("Executing script...")
        print()
        
        import subprocess
        result = subprocess.run(
            [script_file] + (args.script_args or []),
            capture_output=False
        )
        
        # Cleanup
        if args.delete or not args.output:
            os.unlink(script_file)
        elif not args.output:
            print(f"\n✓ Script saved to: {script_file}")
        
        sys.exit(result.returncode)
        
    except Exception as e:
        error_msg = str(e)
        if "encrypted" in error_msg.lower() or "decrypt" in error_msg.lower():
            print(f"Error: Failed to decrypt script", file=sys.stderr)
            if not key_content:
                print("This appears to be an encrypted script. Provide a private key with -k or set SHEBANG_KEY_PATH", file=sys.stderr)
            else:
                print(f"Decryption failed. Verify the key at {key_path} is correct for this script", file=sys.stderr)
        else:
            print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_list_keys(args):
    """List keypairs"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    try:
        keys = client.list_keys()
        if not keys:
            print("No keys found")
            return
        
        print("Your Keys:")
        print("=" * 50)
        for k in keys:
            print(f"{k['name']}")
            print(f"  Created: {k['created_at']}")
            print()
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_create_key(args):
    """Create a new keypair"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    name = input("Key name: ").strip()
    if not name:
        print("Error: Key name required", file=sys.stderr)
        sys.exit(1)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    try:
        print("Generating RSA-4096 keypair...")
        key = client.generate_key(name)
        
        if args.output:
            with open(args.output, 'w') as f:
                f.write(key['private_key'])
            print(f"✓ Private key saved to: {args.output}")
            print(f"✓ Public key stored in account: {name}")
        else:
            print(key['private_key'])
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_delete_key(args):
    """Delete a keypair"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    try:
        # Find key by name
        keys = client.list_keys()
        key = next((k for k in keys if k['name'] == args.keyname), None)
        
        if not key:
            print(f"Error: Key '{args.keyname}' not found", file=sys.stderr)
            sys.exit(1)
        
        confirm = input(f"Delete key '{args.keyname}'? (y/N): ").strip().lower()
        if confirm != 'y':
            print("Cancelled")
            sys.exit(0)
        
        client.delete_key(key['id'])
        print(f"✓ Key '{args.keyname}' deleted")
        
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_put(args):
    """Upload a script"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    # Read content
    if args.stdin:
        content = sys.stdin.read()
    elif args.file:
        with open(args.file) as f:
            content = f.read()
    else:
        print("Error: Must specify -s/--stdin or -f/--file", file=sys.stderr)
        sys.exit(1)
    
    # Validate visibility
    visibility_map = {'priv': 'private', 'unlist': 'unlisted', 'public': 'public'}
    visibility = visibility_map.get(args.visibility, args.visibility)
    if visibility not in ['private', 'unlisted', 'public']:
        print("Error: Visibility must be priv, unlist, or public", file=sys.stderr)
        sys.exit(1)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    try:
        # Get keypair ID if specified
        keypair_id = None
        if args.keyname:
            keys = client.list_keys()
            key = next((k for k in keys if k['name'] == args.keyname), None)
            if not key:
                print(f"Error: Key '{args.keyname}' not found", file=sys.stderr)
                sys.exit(1)
            keypair_id = key['id']
        elif visibility == 'private':
            print("Error: Private scripts require -k/--keyname", file=sys.stderr)
            sys.exit(1)
        
        # Check if script exists
        scripts = client.list_scripts() or []
        existing = next((s for s in scripts if s['name'] == args.name), None)
        
        if existing:
            # Update existing script
            print(f"Updating script '{args.name}'...")
            client.update_script(
                script_id=existing['id'],
                content=content,
                description=args.description or existing.get('description'),
                visibility=visibility,
                keypair_id=keypair_id
            )
            print(f"✓ Script updated: {args.name} (v{existing['version'] + 1})")
        else:
            # Create new script
            print(f"Creating script '{args.name}'...")
            result = client.create_script(
                name=args.name,
                content=content,
                description=args.description or "",
                visibility=visibility,
                keypair_id=keypair_id
            )
            print(f"✓ Script created: {args.name} (v{result['version']})")
        
        print(f"  URL: {config['SHEBANG_URL']}/{config['SHEBANG_USERNAME']}/{args.name}")
        
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_delete(args):
    """Delete a script"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    try:
        # Find script by name
        scripts = client.list_scripts()
        script = next((s for s in scripts if s['name'] == args.script), None)
        
        if not script:
            print(f"Error: Script '{args.script}' not found", file=sys.stderr)
            sys.exit(1)
        
        # Confirm deletion
        if not args.accept:
            confirm = input(f"Delete script '{args.script}'? This cannot be undone. (y/N): ").strip().lower()
            if confirm != 'y':
                print("Cancelled")
                sys.exit(0)
        
        client.delete_script(script['id'])
        print(f"✓ Script '{args.script}' deleted")
        
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_list_secrets(args):
    """List secrets"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    try:
        secrets = client.list_secrets()
        if not secrets:
            print("No secrets found")
            return
        
        for secret in secrets:
            print(f"{secret['key_name']}")
            print(f"  Last accessed: {secret.get('last_accessed', 'Never')}")
            if secret.get('expires_at'):
                print(f"  Expires: {secret['expires_at']}")
            print()
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_get_secret(args):
    """Get secret value"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    try:
        value = client.get_secret(args.name)
        
        # Format output
        if args.format == 'env':
            output = f'{args.name}="{value}"'
        elif args.format == 'json':
            import json
            output = json.dumps({args.name: value})
        else:  # value
            output = value
        
        # Write to file or stdout
        if args.output:
            with open(args.output, 'w') as f:
                f.write(output)
            print(f"✓ Secret written to {args.output}", file=sys.stderr)
        else:
            print(output)
            
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_put_secret(args):
    """Create or update secret"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    # Get value
    if args.stdin:
        value = sys.stdin.read().strip()
    elif args.value:
        value = args.value
    else:
        print("Error: Must specify -v/--value or -s/--stdin", file=sys.stderr)
        sys.exit(1)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    try:
        client.create_secret(args.name, value, args.expires)
        print(f"✓ Secret '{args.name}' saved")
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_delete_secret(args):
    """Delete secret"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    if not args.accept:
        confirm = input(f"Delete secret '{args.name}'? (y/N): ").strip().lower()
        if confirm != 'y':
            print("Cancelled")
            sys.exit(0)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    try:
        client.delete_secret(args.name)
        print(f"✓ Secret '{args.name}' deleted")
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_audit_secret(args):
    """View secret audit log"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    try:
        logs = client.get_secret_audit(args.name)
        if not logs:
            print("No audit logs found")
            return
        
        print(f"Audit log for '{args.name}':")
        print()
        for log in logs:
            print(f"{log['accessed_at']} - {log['action']} from {log['ip_address']}")
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_list_shares(args):
    """List script access control"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    try:
        # Find script by name
        scripts = client.list_scripts() or []
        script = next((s for s in scripts if s['name'] == args.script), None)
        
        if not script:
            print(f"Error: Script '{args.script}' not found", file=sys.stderr)
            sys.exit(1)
        
        access_list = client.list_script_access(script['id'])
        
        if not access_list:
            print(f"Script '{args.script}' is not shared")
            return
        
        print(f"Access for '{args.script}':")
        print("=" * 50)
        for access in access_list:
            if access['access_type'] == 'link':
                print("• Anyone with link")
            else:
                print(f"• {access['username']}")
                
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_share(args):
    """Manage script sharing"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    if not args.user and not args.link:
        print("Error: Must specify -u/--user or -l/--link", file=sys.stderr)
        sys.exit(1)
    
    client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    try:
        # Find script by name
        scripts = client.list_scripts() or []
        script = next((s for s in scripts if s['name'] == args.script), None)
        
        if not script:
            print(f"Error: Script '{args.script}' not found", file=sys.stderr)
            sys.exit(1)
        
        if args.link:
            if args.remove:
                # Remove link sharing
                access_list = client.list_script_access(script['id'])
                link_access = next((a for a in access_list if a['access_type'] == 'link'), None)
                if link_access:
                    client.remove_script_access(script['id'], link_access['id'])
                    print(f"✓ Removed 'anyone with link' access")
                else:
                    print("Link sharing is not enabled")
            else:
                # Add link sharing
                import requests
                response = requests.post(
                    f"{config['SHEBANG_URL']}/api/scripts/{script['id']}/access",
                    auth=(config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET']),
                    json={"access_type": "link"}
                )
                response.raise_for_status()
                print(f"✓ Enabled 'anyone with link' sharing")
        
        elif args.user:
            if args.remove:
                # Remove user access
                access_list = client.list_script_access(script['id'])
                for username in args.user:
                    access = next((a for a in access_list if a.get('username') == username), None)
                    if access:
                        client.remove_script_access(script['id'], access['id'])
                        print(f"✓ Removed access for {username}")
                    else:
                        print(f"Warning: {username} doesn't have access", file=sys.stderr)
            else:
                # Add user access
                client.add_script_access(script['id'], args.user)
                print(f"✓ Shared '{args.script}' with {', '.join(args.user)}")
            
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def cmd_infer(args):
    """Handle infer command"""
    config = load_config()
    client = ShebangClient(url=config.get('SHEBANG_URL', 'shebang.run'))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    result = client.generate_script(args.prompt, args.args, args.provider)
    script = result['script']
    
    if args.output:
        with open(args.output, 'w') as f:
            f.write(script)
        print(f"Script saved to {args.output}")
    elif args.save:
        if not args.name:
            print("Error: --name required with --save")
            sys.exit(1)
        visibility_map = {'priv': 'private', 'unlist': 'unlisted', 'public': 'public'}
        visibility = visibility_map.get(args.visibility, 'private')
        client.create_script(args.name, script, args.description or '', visibility)
        print(f"Script saved as {args.name}")
    elif args.eval:
        if not args.accept:
            print("Generated script:")
            print("=" * 60)
            print(script)
            print("=" * 60)
            confirm = input("\nExecute this script? (y/N): ").strip().lower()
            if confirm != 'y':
                print("Cancelled")
                return
        
        # Execute script
        import tempfile
        import subprocess
        with tempfile.NamedTemporaryFile(mode='w', suffix='.sh', delete=False) as f:
            f.write(script)
            temp_path = f.name
        
        try:
            import os
            os.chmod(temp_path, 0o755)
            subprocess.run([temp_path])
        finally:
            os.unlink(temp_path)
    else:
        print(script)

def cmd_files(args):
    """Handle files command"""
    config = load_config()
    client = ShebangClient(url=config.get('SHEBANG_URL', 'shebang.run'))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    if args.files_command == 'list':
        files = client.list_files(args.folder)
        if not files:
            print("No files found")
            return
        for f in files:
            folder_info = f" (folder: {f['folder_id']})" if f.get('folder_id') else ""
            print(f"{f['id']}\t{f['original_filename']}\t{format_size(f['size'])}\t{f['visibility']}{folder_info}")
    
    elif args.files_command == 'upload':
        result = client.upload_file(args.file, args.folder, args.visibility)
        print(f"Uploaded: {result['original_filename']} (ID: {result['id']})")
    
    elif args.files_command == 'download':
        output = args.output or client.get_file(args.file_id)['original_filename']
        client.download_file(args.file_id, output)
        print(f"Downloaded to {output}")
    
    elif args.files_command == 'delete':
        client.delete_file(args.file_id)
        print(f"Deleted file {args.file_id}")
    
    elif args.files_command == 'versions':
        versions = client.list_file_versions(args.file_id)
        if not versions:
            print("No versions found (versioning requires Ultimate tier)")
            return
        for v in versions:
            current = " (current)" if v == versions[0] else ""
            print(f"v{v['version_number']}{current}\t{format_size(v['size'])}\t{v['created_at']}")
    
    elif args.files_command == 'share':
        if args.link:
            client.share_file(args.file_id, link=True)
        elif args.user:
            client.share_file(args.file_id, usernames=args.user)
        else:
            print("Specify --user or --link")
            return
        print("File shared")

def cmd_folders(args):
    """Handle folders command"""
    config = load_config()
    client = ShebangClient(url=config.get('SHEBANG_URL', 'shebang.run'))
    client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
    
    if args.folders_command == 'list':
        folders = client.list_folders(args.parent)
        if not folders:
            print("No folders found")
            return
        for f in folders:
            parent_info = f" (parent: {f['parent_id']})" if f.get('parent_id') else ""
            print(f"{f['id']}\t{f['name']}\t{f['path']}{parent_info}")
    
    elif args.folders_command == 'create':
        result = client.create_folder(args.name, args.parent)
        print(f"Created folder: {result['name']} (ID: {result['id']})")
    
    elif args.folders_command == 'delete':
        client.delete_folder(args.folder_id)
        print(f"Deleted folder {args.folder_id}")
    
    elif args.folders_command == 'share':
        if args.link:
            client.share_folder(args.folder_id, link=True)
        elif args.user:
            client.share_folder(args.folder_id, usernames=args.user)
        else:
            print("Specify --user or --link")
            return
        print("Folder shared (includes all contents)")

def format_size(bytes):
    """Format bytes to human readable"""
    for unit in ['B', 'KB', 'MB', 'GB']:
        if bytes < 1024:
            return f"{bytes:.1f} {unit}"
        bytes /= 1024
    return f"{bytes:.1f} TB"

def main():
    """Generate script with AI"""
    config = load_config()
    if not config.get('SHEBANG_CLIENT_ID'):
        print("Error: Not logged in. Run: shebang login", file=sys.stderr)
        sys.exit(1)
    
    if args.save and (not args.name or not args.visibility):
        print("Error: -s/--save requires -n/--name and -v/--visibility", file=sys.stderr)
        sys.exit(1)
    
    import requests
    
    # Generate script
    payload = {
        "prompt": args.prompt,
        "args": args.args or []
    }
    if args.provider:
        payload["provider"] = args.provider
    
    print("Generating script...", file=sys.stderr)
    
    try:
        response = requests.post(
            f"{config['SHEBANG_URL']}/api/ai/generate",
            auth=(config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET']),
            json=payload
        )
        response.raise_for_status()
        result = response.json()
        
        script = result['script']
        print(f"✓ Generated with {result['provider']} ({result['tokens']} tokens)", file=sys.stderr)
        print(file=sys.stderr)
        
        # Save to account if requested
        if args.save:
            client = ShebangClient(url=config['SHEBANG_URL'].replace('https://', '').replace('http://', ''))
            client.session.auth = (config['SHEBANG_CLIENT_ID'], config['SHEBANG_CLIENT_SECRET'])
            
            visibility_map = {'priv': 'private', 'unlist': 'unlisted', 'public': 'public'}
            visibility = visibility_map.get(args.visibility, args.visibility)
            
            client.create_script(
                name=args.name,
                content=script,
                description=args.description or f"AI generated: {args.prompt[:50]}",
                visibility=visibility
            )
            print(f"✓ Saved as '{args.name}'", file=sys.stderr)
            print(f"  URL: {config['SHEBANG_URL']}/{config['SHEBANG_USERNAME']}/{args.name}", file=sys.stderr)
            return
        
        # Save to file if requested
        if args.output:
            with open(args.output, 'w') as f:
                f.write(script)
            print(f"✓ Saved to {args.output}", file=sys.stderr)
            if args.eval:
                import os
                os.chmod(args.output, 0o755)
        
        # Execute if requested
        if args.eval:
            import tempfile
            import subprocess
            
            if not args.output:
                fd, script_file = tempfile.mkstemp(suffix='.sh')
                os.close(fd)
                with open(script_file, 'w') as f:
                    f.write(script)
                os.chmod(script_file, 0o755)
            else:
                script_file = args.output
            
            if not args.accept:
                print("Generated script:")
                print("=" * 60)
                print(script)
                print("=" * 60)
                print()
                confirm = input("Execute this script? (y/N): ").strip().lower()
                if confirm != 'y':
                    if not args.output:
                        os.unlink(script_file)
                    print("Cancelled")
                    sys.exit(0)
            
            print("Executing...", file=sys.stderr)
            result = subprocess.run([script_file] + (args.args or []))
            
            if not args.output:
                os.unlink(script_file)
            
            sys.exit(result.returncode)
        else:
            # Just print the script
            print(script)
            
    except requests.HTTPError as e:
        if e.response.status_code == 403:
            print("Error: AI generation not available in your tier or limit reached", file=sys.stderr)
        else:
            print(f"Error: {e.response.text}", file=sys.stderr)
        sys.exit(1)
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def main():
    parser = argparse.ArgumentParser(
        prog='shebang',
        description='CLI tool for shebang.run',
        formatter_class=argparse.RawDescriptionHelpFormatter
    )
    
    subparsers = parser.add_subparsers(dest='command', help='Commands')
    
    # Login
    subparsers.add_parser('login', help='Login and generate API credentials')
    
    # List
    list_parser = subparsers.add_parser('list', help='List scripts')
    list_parser.add_argument('-c', '--community', action='store_true', help='Include community scripts')
    list_parser.add_argument('-i', '--hide-shared', action='store_true', help='Hide shared scripts')
    
    # Search
    search_parser = subparsers.add_parser('search', help='Search scripts')
    search_parser.add_argument('query', help='Search query')
    search_parser.add_argument('-c', '--community', action='store_true', help='Include community scripts')
    
    # Get
    get_parser = subparsers.add_parser('get', help='Download a script')
    get_parser.add_argument('script', help='Script name')
    get_parser.add_argument('-u', '--user', help='Username')
    get_parser.add_argument('-O', '--output', help='Output file')
    get_parser.add_argument('-k', '--key', help='Private key path')
    get_parser.add_argument('-s', '--secrets', action='store_true', help='Substitute ${SECRET:name} with actual values')
    
    # Run
    run_parser = subparsers.add_parser('run', help='Download and execute a script')
    run_parser.add_argument('script', help='Script name')
    run_parser.add_argument('-u', '--user', help='Username')
    run_parser.add_argument('-O', '--output', help='Output file')
    run_parser.add_argument('-k', '--key', help='Private key path')
    run_parser.add_argument('-a', '--accept', action='store_true', help='Auto-accept execution')
    run_parser.add_argument('-d', '--delete', action='store_true', help='Delete after execution')
    run_parser.add_argument('script_args', nargs='*', help='Arguments to pass to script')
    
    # List keys
    subparsers.add_parser('list-keys', help='List your keypairs')
    
    # Create key
    create_key_parser = subparsers.add_parser('create-key', help='Generate a new keypair')
    create_key_parser.add_argument('-O', '--output', help='Save private key to file')
    
    # Delete key
    delete_key_parser = subparsers.add_parser('delete-key', help='Delete a keypair')
    delete_key_parser.add_argument('keyname', help='Key name to delete')
    
    # Put (upload script)
    put_parser = subparsers.add_parser('put', help='Upload a script')
    put_parser.add_argument('-n', '--name', required=True, help='Script name')
    put_parser.add_argument('-v', '--visibility', required=True, choices=['priv', 'unlist', 'public'], help='Visibility')
    put_parser.add_argument('-d', '--description', default='', help='Description')
    put_parser.add_argument('-k', '--keyname', help='Key name for encryption (required for private)')
    put_parser.add_argument('-s', '--stdin', action='store_true', help='Read from stdin')
    put_parser.add_argument('-f', '--file', help='Read from file')
    
    # Delete
    delete_parser = subparsers.add_parser('delete', help='Delete a script')
    delete_parser.add_argument('script', help='Script name')
    delete_parser.add_argument('-a', '--accept', action='store_true', help='Skip confirmation')
    
    # List secrets
    subparsers.add_parser('list-secrets', help='List your secrets')
    
    # Get secret
    get_secret_parser = subparsers.add_parser('get-secret', help='Get secret value')
    get_secret_parser.add_argument('name', help='Secret name')
    get_secret_parser.add_argument('-O', '--output', help='Output to file')
    get_secret_parser.add_argument('-f', '--format', choices=['value', 'env', 'json'], default='value', 
                                   help='Output format (default: value)')
    
    # Put secret
    put_secret_parser = subparsers.add_parser('put-secret', help='Create or update a secret')
    put_secret_parser.add_argument('name', help='Secret name')
    put_secret_parser.add_argument('-v', '--value', help='Secret value')
    put_secret_parser.add_argument('-s', '--stdin', action='store_true', help='Read value from stdin')
    put_secret_parser.add_argument('-e', '--expires', help='Expiration date (ISO format)')
    
    # Delete secret
    delete_secret_parser = subparsers.add_parser('delete-secret', help='Delete a secret')
    delete_secret_parser.add_argument('name', help='Secret name')
    delete_secret_parser.add_argument('-a', '--accept', action='store_true', help='Skip confirmation')
    
    # Audit secret
    audit_secret_parser = subparsers.add_parser('audit-secret', help='View secret audit log')
    audit_secret_parser.add_argument('name', help='Secret name')
    
    # List shares
    list_shares_parser = subparsers.add_parser('list-shares', help='List script access control')
    list_shares_parser.add_argument('script', help='Script name')
    
    # Share
    share_parser = subparsers.add_parser('share', help='Manage script sharing')
    share_parser.add_argument('script', help='Script name')
    share_parser.add_argument('-u', '--user', action='append', help='Username to share with (can specify multiple)')
    share_parser.add_argument('-l', '--link', action='store_true', help='Enable "anyone with link" sharing')
    share_parser.add_argument('-r', '--remove', action='store_true', help='Remove access instead of adding')
    
    # Infer (AI generation)
    infer_parser = subparsers.add_parser('infer', help='Generate script with AI')
    infer_parser.add_argument('prompt', help='Description of what the script should do')
    infer_parser.add_argument('args', nargs='*', help='Script arguments')
    infer_parser.add_argument('-e', '--eval', action='store_true', help='Execute the generated script')
    infer_parser.add_argument('-a', '--accept', action='store_true', help='Auto-accept execution')
    infer_parser.add_argument('-O', '--output', help='Save to file')
    infer_parser.add_argument('-s', '--save', action='store_true', help='Save to shebang account')
    infer_parser.add_argument('-n', '--name', help='Script name (required with -s)')
    infer_parser.add_argument('-v', '--visibility', choices=['priv', 'unlist', 'public'], help='Visibility (required with -s)')
    infer_parser.add_argument('-d', '--description', help='Description (for -s)')
    infer_parser.add_argument('-p', '--provider', choices=['claude', 'openai', 'bedrock'], help='AI provider')
    
    # File commands
    files_parser = subparsers.add_parser('files', help='File management')
    files_subparsers = files_parser.add_subparsers(dest='files_command', help='File commands')
    
    # files list
    files_list = files_subparsers.add_parser('list', help='List files')
    files_list.add_argument('-f', '--folder', type=int, help='Folder ID')
    
    # files upload
    files_upload = files_subparsers.add_parser('upload', help='Upload file')
    files_upload.add_argument('file', help='File path')
    files_upload.add_argument('-f', '--folder', type=int, help='Folder ID')
    files_upload.add_argument('-v', '--visibility', choices=['private', 'unlisted', 'public'], default='private')
    
    # files download
    files_download = files_subparsers.add_parser('download', help='Download file')
    files_download.add_argument('file_id', type=int, help='File ID')
    files_download.add_argument('-o', '--output', help='Output path')
    
    # files delete
    files_delete = files_subparsers.add_parser('delete', help='Delete file')
    files_delete.add_argument('file_id', type=int, help='File ID')
    
    # files versions
    files_versions = files_subparsers.add_parser('versions', help='List file versions')
    files_versions.add_argument('file_id', type=int, help='File ID')
    
    # files share
    files_share = files_subparsers.add_parser('share', help='Share file')
    files_share.add_argument('file_id', type=int, help='File ID')
    files_share.add_argument('-u', '--user', action='append', help='Username')
    files_share.add_argument('-l', '--link', action='store_true', help='Enable link sharing')
    
    # Folder commands
    folders_parser = subparsers.add_parser('folders', help='Folder management')
    folders_subparsers = folders_parser.add_subparsers(dest='folders_command', help='Folder commands')
    
    # folders list
    folders_list = folders_subparsers.add_parser('list', help='List folders')
    folders_list.add_argument('-p', '--parent', type=int, help='Parent folder ID')
    
    # folders create
    folders_create = folders_subparsers.add_parser('create', help='Create folder')
    folders_create.add_argument('name', help='Folder name')
    folders_create.add_argument('-p', '--parent', type=int, help='Parent folder ID')
    
    # folders delete
    folders_delete = folders_subparsers.add_parser('delete', help='Delete folder')
    folders_delete.add_argument('folder_id', type=int, help='Folder ID')
    
    # folders share
    folders_share = folders_subparsers.add_parser('share', help='Share folder')
    folders_share.add_argument('folder_id', type=int, help='Folder ID')
    folders_share.add_argument('-u', '--user', action='append', help='Username')
    folders_share.add_argument('-l', '--link', action='store_true', help='Enable link sharing')
    
    args = parser.parse_args()
    
    if not args.command:
        parser.print_help()
        sys.exit(0)
    
    if args.command == 'login':
        cmd_login(args)
    elif args.command == 'list':
        cmd_list(args)
    elif args.command == 'search':
        cmd_search(args)
    elif args.command == 'get':
        cmd_get(args)
    elif args.command == 'run':
        cmd_run(args)
    elif args.command == 'list-keys':
        cmd_list_keys(args)
    elif args.command == 'create-key':
        cmd_create_key(args)
    elif args.command == 'delete-key':
        cmd_delete_key(args)
    elif args.command == 'put':
        cmd_put(args)
    elif args.command == 'delete':
        cmd_delete(args)
    elif args.command == 'list-secrets':
        cmd_list_secrets(args)
    elif args.command == 'get-secret':
        cmd_get_secret(args)
    elif args.command == 'put-secret':
        cmd_put_secret(args)
    elif args.command == 'delete-secret':
        cmd_delete_secret(args)
    elif args.command == 'audit-secret':
        cmd_audit_secret(args)
    elif args.command == 'list-shares':
        cmd_list_shares(args)
    elif args.command == 'share':
        cmd_share(args)
    elif args.command == 'infer':
        cmd_infer(args)
    elif args.command == 'files':
        cmd_files(args)
    elif args.command == 'folders':
        cmd_folders(args)

if __name__ == '__main__':
    main()
