import argparse
import json
import time


def str2bool(v):
    if isinstance(v, bool):
        return v
    if v.lower() in ("yes", "true", "t", "1"):
        return True
    if v.lower() in ("no", "false", "f", "0"):
        return False
    raise argparse.ArgumentTypeError("Boolean value expected.")


def register_commands(subparsers: argparse._SubParsersAction) -> None:
    # ==================== query cli params ====================
    query = subparsers.add_parser("query", help="Query domain (state/orders/fills/meta/mids/kline)")
    qsp = query.add_subparsers(dest="query_cmd", required=True)

    q_state = qsp.add_parser("user-state", help="Query user state (positions + balances)")
    q_state.add_argument("--address", help="Optional address (derived from private key by default)")

    q_orders = qsp.add_parser("open-orders", help="Query open orders")
    q_orders.add_argument("--address", help="Optional address (derived from private key by default)")

    q_fills = qsp.add_parser("fills", help="Query fills / trade history")
    q_fills.add_argument("--address", help="Optional address (derived from private key by default)")

    qsp.add_parser("meta", help="Query asset metadata (all symbols)")
    qsp.add_parser("mids", help="Query mid prices (all symbols)")

    q_kline = qsp.add_parser("kline", help="Query kline/candles for a symbol")
    q_kline.add_argument("--coin", required=True, help="Symbol, e.g. BTC or xyz:TSLA")
    q_kline.add_argument(
        "--period",
        required=True,
        help="Kline period: 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 8h, 12h, 1d, 3d, 1w, 1M",
    )
    end = int(time.time() * 1000)
    start = end - 86400000
    q_kline.add_argument("--start", default=start, type=int, help="Start time (ms). Default: last 24 hours")
    q_kline.add_argument("--end", type=int, default=end, help="End time (ms). Default: now")

    # ==================== exchange cli params ====================
    exchange = subparsers.add_parser("exchange", help="Exchange domain (place/market/close/leverage/cancel/isolated-margein/wallet)")
    esp = exchange.add_subparsers(dest="exchange_cmd", required=True)

    place = esp.add_parser("place", help="Place a limit order (HIP-3 supported)")
    place.add_argument("--coin", required=True, help="Symbol, e.g. BTC or xyz:TSLA")
    place.add_argument("--is-buy", type=str2bool, required=True, help="True=buy (long), False=sell (short)")
    place.add_argument("--qty", type=float, required=True, help="Size/quantity")
    place.add_argument("--limit-px", type=float, required=True, help="Limit price")
    place.add_argument("--tif", choices=["Gtc", "Ioc", "Alo"], default="Gtc", help="Time in force")
    place.add_argument("--reduce-only", action="store_true", help="Reduce-only")

    market = esp.add_parser("market", help="Place a market order (recommended for HIP-3)")
    market.add_argument("--coin", required=True, help="Symbol, e.g. BTC or xyz:TSLA")
    market.add_argument("--is-buy", type=str2bool, required=True, help="True=buy (long), False=sell (short)")
    market.add_argument("--qty", required=True, type=float, help="Size/quantity")
    market.add_argument("--slippage", type=float, default=0.02, help="Slippage tolerance (default: 2%)")

    close = esp.add_parser("close", help="Close a position with a market order (recommended for HIP-3)")
    close.add_argument("--coin", required=True, help="Symbol, e.g. BTC or xyz:TSLA")
    close.add_argument("--qty", required=True, type=float, help="Size/quantity")
    close.add_argument("--slippage", type=float, default=0.02, help="Slippage tolerance (default: 2%)")

    cancel = esp.add_parser("cancel", help="Cancel orders")
    cancel.add_argument("--oid", type=int, help="Order ID")
    cancel.add_argument("--coin", help="Symbol, e.g. BTC or xyz:TSLA")

    lev = esp.add_parser("leverage", help="Update leverage")
    lev.add_argument("--coin", required=True, help="Symbol")
    lev.add_argument("--leverage", type=int, required=True, help="Leverage (integer)")
    lev.add_argument("--is-cross", type=str2bool, default=True, help="True=cross margin")

    iso = esp.add_parser("isolated-margein", aliases=["isolated-margin"], help="Transfer isolated margin for HIP-3")
    iso.add_argument("--amount", type=int, required=True, help="Transfer amount")
    iso.add_argument("--coin", required=True, help="Symbol, e.g. BTC or xyz:TSLA")

    wallet = esp.add_parser("wallet", help="Init wallet with user-provided address + private key")
    wallet.add_argument(
        "--address",
        required=False,
        help="Optional wallet public address (0x...). If omitted, derive from --pri_key",
    )
    wallet.add_argument("--pri_key", required=True, help="Wallet private key (0x...)")


def handle_command(parser: argparse.ArgumentParser, args: argparse.Namespace, env_loaded: bool) -> bool:
    """
    Returns True if handled, False if not in `trade` domain.
    """

    cmd = str(getattr(args, "command", "") or "")

    # query
    if cmd == "query":
        if env_loaded is False:
            print("Warning: env file not found (required for querying)")
            return True
        from .info import query_info

        result = query_info(args)
        print(json.dumps(result, indent=2, default=str))
        return True

    # exchange
    if cmd == "exchange":
        if str(getattr(args, "exchange_cmd", "") or "") == "wallet":
            from .wallet import init_wallet

            init_wallet(args.address, args.pri_key)
            return True

        if env_loaded is False:
            print("Warning: env file not found (required for trading)")
            return True

        from .exchange import exchange_order

        result = exchange_order(args)
        print(json.dumps(result, indent=2, default=str))
        return True

    return False


__all__ = ["register_commands", "handle_command", "str2bool"]

