from __future__ import annotations

import argparse
import json
import os

from . import api
from .client import BlockBeatsError, fetch_free_api_key
from .env import write_blockbeats_api_key_to_state_env


def register_commands(subparsers: argparse._SubParsersAction) -> None:
    p = subparsers.add_parser(
        "news",
        help="BlockBeats news & market data (requires BLOCKBEATS_API_KEY)",
        description="news: BlockBeats Pro API client (news, articles, datasets, and curated scenarios).",
    )
    sp = p.add_subparsers(dest="news_cmd", required=True, title="Subcommands")

    set_p = sp.add_parser("set", help="Set BLOCKBEATS_API_KEY")
    set_p.add_argument("api_key", help="Your BlockBeats Pro API key")

    refresh_p = sp.add_parser(
        "refresh",
        help="Refresh BLOCKBEATS_API_KEY (from env var or explicit --api-key)",
    )
    refresh_p.add_argument(
        "--api-key",
        dest="api_key",
        default=None,
        help="API key to set. If omitted, reads from process env BLOCKBEATS_API_KEY.",
    )

    snap = sp.add_parser("snapshot", help="Scenario: market snapshot")
    snap.add_argument("--lang", default="cn", choices=["cn", "en"], help="Language (cn/en). Default: cn")

    ff = sp.add_parser("fund-flow", help="Scenario: fund flow analysis")
    ff.add_argument("--network", default="solana", choices=["solana", "base", "ethereum"], help="Network name")

    macro = sp.add_parser("macro", help="Scenario: macro environment")
    macro.add_argument("--timeframe", default="1M", choices=["1D", "1W", "1M"], help="Timeframe")

    der = sp.add_parser("derivatives", help="Scenario: derivatives market")
    der.add_argument(
        "--data-type",
        dest="data_type",
        default="1D",
        choices=["1D", "1W", "1M", "3M", "6M", "12M"],
        help="Time window for derivatives datasets",
    )
    der.add_argument("--exchanges-size", type=int, default=10, help="Number of exchanges to include")

    nf = sp.add_parser("newsflash", help="Get newsflashes list")
    nf.add_argument("--type", dest="kind", default="all", choices=api.NEWSFLASH_TYPES, help="Newsflash category/type")
    nf.add_argument("--page", type=int, default=1, help="Page number (1-based)")
    nf.add_argument("--size", type=int, default=10, help="Page size")
    nf.add_argument("--lang", default="cn", choices=["cn", "en"], help="Language (cn/en). Default: cn")

    ar = sp.add_parser("article", help="Get articles list")
    ar.add_argument("--type", dest="kind", default="all", choices=api.ARTICLE_TYPES, help="Article category/type")
    ar.add_argument("--page", type=int, default=1, help="Page number (1-based)")
    ar.add_argument("--size", type=int, default=10, help="Page size")
    ar.add_argument("--lang", default="cn", choices=["cn", "en"], help="Language (cn/en). Default: cn")

    s = sp.add_parser("search", help="Keyword search")
    s.add_argument("--keyword", required=True, help="Search keyword")
    s.add_argument("--size", type=int, default=10, help="Number of results to return")
    s.add_argument("--lang", default="cn", choices=["cn", "en"], help="Language (cn/en). Default: cn")

    d = sp.add_parser("data", help="Single data endpoint")
    d.add_argument("--name", required=True, choices=api.DATASETS, help="Dataset name")
    d.add_argument("--type", dest="type_", default=None, help="Dataset type (dataset-specific)")  # for us10y/dxy/m2_supply/bitfinex_long
    d.add_argument("--data-type", dest="data_type", default=None, help="Data type / interval (dataset-specific)")  # for contract
    d.add_argument("--symbol", default=None, help="Symbol (dataset-specific)")  # for bitfinex_long
    d.add_argument("--network", default=None, help="Network (dataset-specific)")  # for top10_netflow
    d.add_argument("--page", type=int, default=None, help="Page number (dataset-specific)")  # for exchanges
    d.add_argument("--size", type=int, default=None, help="Page size (dataset-specific)")  # for exchanges
    d.add_argument("--exchange-name", dest="exchange_name", default=None, help="Exchange name filter (dataset-specific)")  # for exchanges 'name'


def handle_command(args: argparse.Namespace) -> bool:
    if getattr(args, "command", None) != "news":
        return False

    try:
        cmd = str(getattr(args, "news_cmd", "") or "")
        if cmd == "set":
            write_blockbeats_api_key_to_state_env(str(getattr(args, "api_key", "") or ""))
            print(json.dumps({"set": True}, ensure_ascii=False))
            return True
        if cmd == "refresh":
            key = str(getattr(args, "api_key", "") or "").strip() or None
            if not key:
                key = str(os.environ.get("BLOCKBEATS_API_KEY") or "").strip() or None
            if not key:
                # Best-effort auto refresh (free/trial key).
                key = fetch_free_api_key()
            write_blockbeats_api_key_to_state_env(key)
            print(json.dumps({"refreshed": True}, ensure_ascii=False))
            return True

        if cmd == "snapshot":
            out = api.market_snapshot(lang=args.lang)
        elif cmd == "fund-flow":
            out = api.fund_flow_analysis(network=args.network)
        elif cmd == "macro":
            out = api.macro_environment(timeframe=args.timeframe)
        elif cmd == "derivatives":
            out = api.derivatives_market(data_type=args.data_type, exchanges_size=int(args.exchanges_size))
        elif cmd == "newsflash":
            out = api.get_newsflash(kind=args.kind, page=int(args.page), size=int(args.size), lang=args.lang)
        elif cmd == "article":
            out = api.get_article(kind=args.kind, page=int(args.page), size=int(args.size), lang=args.lang)
        elif cmd == "search":
            out = api.search(keyword=str(args.keyword), size=int(args.size), lang=args.lang)
        elif cmd == "data":
            params = {}
            if args.exchange_name is not None:
                params["name"] = args.exchange_name
            if args.page is not None:
                params["page"] = int(args.page)
            if args.size is not None:
                params["size"] = int(args.size)
            if args.network is not None:
                params["network"] = str(args.network)
            if args.symbol is not None:
                params["symbol"] = str(args.symbol)
            if args.type_ is not None:
                params["type"] = str(args.type_)
            if args.data_type is not None:
                params["dataType"] = str(args.data_type)
            out = api.get_data(str(args.name), params=params)
        else:
            raise SystemExit(f"unknown news command: {cmd}")

        print(json.dumps(out, ensure_ascii=False, indent=2, default=str))
        return True
    except BlockBeatsError as e:
        raise SystemExit(f"news error: {e}") from e


__all__ = ["register_commands", "handle_command"]

