#!/usr/bin/env python3
"""
Polymarket Betting Script
Place bets programmatically on Polymarket using the py-clob-client library.
"""

import argparse
import sys
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY, SELL


def create_client(private_key: str, proxy_address: str, signature_type: int = 1) -> ClobClient:
    """
    Create and initialize a Polymarket CLOB client.
    
    Args:
        private_key: Your private key (from Magic Link or Web3 wallet)
        proxy_address: Your Polymarket proxy address (shown below profile picture)
        signature_type: 1 for Email/Magic, 2 for Browser Wallet, 0 for EOA
    
    Returns:
        Initialized ClobClient instance
    """
    host = "https://clob.polymarket.com"
    chain_id = 137  # Polygon mainnet
    
    if signature_type == 0:
        # Direct EOA trading (no proxy)
        client = ClobClient(host, key=private_key, chain_id=chain_id)
    else:
        # Trading through Polymarket Proxy
        client = ClobClient(
            host, 
            key=private_key, 
            chain_id=chain_id, 
            signature_type=signature_type, 
            funder=proxy_address
        )
    
    # Create or derive API credentials
    client.set_api_creds(client.create_or_derive_api_creds())
    
    return client


def place_bet(
    client: ClobClient,
    token_id: str,
    price: float,
    size: float,
    side: str = "BUY",
    order_type: str = "GTC",
    negrisk: bool = False
) -> dict:
    """
    Place a bet on Polymarket.
    
    Args:
        client: Initialized ClobClient
        token_id: Token ID for the market outcome (YES or NO token)
        price: Price per token (0.01 to 0.99)
        size: Number of tokens to buy/sell
        side: "BUY" or "SELL"
        order_type: "GTC" (Good-Till-Cancelled), "FOK" (Fill-Or-Kill), or "GTD" (Good-Till-Date)
        negrisk: Set to True for NegRisk markets
    
    Returns:
        Response from the order submission
    """
    # Validate inputs
    if price <= 0 or price >= 1:
        raise ValueError("Price must be between 0.01 and 0.99")
    
    if size <= 0:
        raise ValueError("Size must be greater than 0")
    
    side_constant = BUY if side.upper() == "BUY" else SELL
    
    # Create order arguments
    order_args = OrderArgs(
        price=price,
        size=size,
        side=side_constant,
        token_id=token_id,
        negrisk=negrisk
    )
    
    # Create and sign the order
    signed_order = client.create_order(order_args)
    
    # Map order type string to OrderType enum
    order_type_map = {
        "GTC": OrderType.GTC,
        "FOK": OrderType.FOK,
        "GTD": OrderType.GTD
    }
    
    order_type_enum = order_type_map.get(order_type.upper(), OrderType.GTC)
    
    # Post the order
    response = client.post_order(signed_order, order_type_enum)
    
    return response


def main():
    parser = argparse.ArgumentParser(
        description="Place bets on Polymarket programmatically",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Buy 5 YES tokens at $0.50 each
  python poly_bet.py --key YOUR_KEY --proxy YOUR_PROXY --token TOKEN_ID --price 0.50 --size 5 --side BUY
  
  # Sell 10 tokens at $0.75 each
  python poly_bet.py --key YOUR_KEY --proxy YOUR_PROXY --token TOKEN_ID --price 0.75 --size 10 --side SELL
  
  # Buy on a NegRisk market
  python poly_bet.py --key YOUR_KEY --proxy YOUR_PROXY --token TOKEN_ID --price 0.30 --size 2 --side BUY --negrisk
        """
    )
    
    parser.add_argument(
        "--key",
        required=True,
        help="Your private key (from Magic Link or Web3 wallet)"
    )
    
    parser.add_argument(
        "--proxy",
        help="Your Polymarket proxy address (required for Magic/Wallet login, not for EOA)"
    )
    
    parser.add_argument(
        "--signature-type",
        type=int,
        choices=[0, 1, 2],
        default=1,
        help="Signature type: 1=Email/Magic (default), 2=Browser Wallet, 0=EOA"
    )
    
    parser.add_argument(
        "--token",
        required=True,
        help="Token ID for the market outcome you want to trade"
    )
    
    parser.add_argument(
        "--price",
        type=float,
        required=True,
        help="Price per token (0.01 to 0.99)"
    )
    
    parser.add_argument(
        "--size",
        type=float,
        required=True,
        help="Number of tokens to buy/sell"
    )
    
    parser.add_argument(
        "--side",
        choices=["BUY", "SELL", "buy", "sell"],
        default="BUY",
        help="Order side: BUY or SELL (default: BUY)"
    )
    
    parser.add_argument(
        "--order-type",
        choices=["GTC", "FOK", "GTD"],
        default="GTC",
        help="Order type: GTC (Good-Till-Cancelled), FOK (Fill-Or-Kill), GTD (Good-Till-Date)"
    )
    
    parser.add_argument(
        "--negrisk",
        action="store_true",
        help="Set this flag for NegRisk markets"
    )
    
    args = parser.parse_args()
    
    # Validate proxy address for non-EOA signatures
    if args.signature_type != 0 and not args.proxy:
        parser.error("--proxy is required when signature-type is 1 or 2")
    
    try:
        print("Initializing Polymarket client...")
        client = create_client(args.key, args.proxy, args.signature_type)
        
        print(f"\nPlacing order:")
        print(f"  Token ID: {args.token}")
        print(f"  Side: {args.side.upper()}")
        print(f"  Price: ${args.price:.2f}")
        print(f"  Size: {args.size}")
        print(f"  Order Type: {args.order_type}")
        print(f"  NegRisk: {args.negrisk}")
        
        response = place_bet(
            client=client,
            token_id=args.token,
            price=args.price,
            size=args.size,
            side=args.side,
            order_type=args.order_type,
            negrisk=args.negrisk
        )
        
        print("\n✓ Order placed successfully!")
        print(f"\nResponse: {response}")
        
    except Exception as e:
        print(f"\n✗ Error: {e}", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main()
