from __future__ import annotations

import argparse
import json
import sys
import time
from typing import List, Optional

from .client import GrsAIClient
from .config import build_configs, resolve_prompt
from .downloader import download_image
from .exceptions import GrsAIError
from .logger import Logger

VERSION = "0.1.0"


def _add_draw_arguments(parser: argparse.ArgumentParser) -> None:
    parser.add_argument(
        "--config",
        default=None,
        help="配置文件路径（.toml/.json）。默认自动查找 nbdraw.toml，若不存在回退 grsai_draw.toml",
    )

    parser.add_argument("--base-url", default=None, help="覆盖 base_url")
    parser.add_argument("--api-key", default=None, help="覆盖 api_key")
    parser.add_argument("--timeout", type=float, default=None, help="read timeout（秒）")
    parser.add_argument("--connect-timeout", type=float, default=None, help="connect timeout（秒）")
    parser.add_argument("--retries", type=int, default=None, help="重试次数（429/5xx/网络错误）")
    parser.add_argument("--backoff-base", type=float, default=None, help="退避基数（秒）")
    parser.add_argument("--backoff-cap", type=float, default=None, help="最大退避（秒）")

    parser.add_argument("--model", default=None, help="模型名称（覆盖配置）")
    parser.add_argument("--aspect-ratio", default=None, help="如 16:9 / 1:1 / 9:16")
    parser.add_argument("--image-size", default=None, help="如 1K / 2K / 4K")
    parser.add_argument("--web-hook", default=None, help="webHook，默认 -1")
    parser.add_argument("--set", action="append", help="额外透传参数：key=value（可多次）")

    parser.add_argument("--prompt", default=None, help="直接传 prompt（短内容）")
    parser.add_argument(
        "--prompt-file",
        default=None,
        help="从文件读取 prompt（默认读取 ./prompt.md）",
    )
    parser.add_argument("--stdin", action="store_true", help="从标准输入读取 prompt（支持管道）")

    parser.add_argument("--max-wait", type=float, default=None, help="轮询最大等待时间（秒）")
    parser.add_argument("--poll-interval", type=float, default=None, help="轮询间隔（秒）")
    parser.add_argument(
        "--heartbeat",
        type=float,
        default=None,
        help="状态无变化时的心跳日志间隔（秒）",
    )

    parser.add_argument("--dry-run", action="store_true", help="只打印最终请求 payload，不发请求")
    parser.add_argument("--quiet", action="store_true", help="少输出（仅错误）")
    parser.add_argument("--debug", action="store_true", help="输出调试日志")

    parser.add_argument("--output-dir", default="./outputs", help="自动下载目录，默认 ./outputs")
    parser.add_argument("--no-download", action="store_true", help="生成成功后不下载到本地")
    parser.add_argument("--json", action="store_true", dest="json_output", help="输出机器可读 JSON")


def _build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(prog="nbdraw", description="nbdraw CLI for GRSAI nano banana")
    parser.add_argument("--version", action="version", version=f"nbdraw {VERSION}")

    subparsers = parser.add_subparsers(dest="command")
    draw_parser = subparsers.add_parser("draw", help="generate image by nano banana")
    _add_draw_arguments(draw_parser)

    return parser


def _emit_result(args: argparse.Namespace, result: dict) -> None:
    if args.json_output:
        print(json.dumps(result, ensure_ascii=False, indent=2), flush=True)
        return

    print(f"task_id: {result['task_id']}", flush=True)
    print(f"url: {result['url']}", flush=True)
    print(f"local_path: {result['local_path']}", flush=True)
    print(f"status: {result['status']}", flush=True)


def run_draw(args: argparse.Namespace) -> int:
    logger = Logger(quiet=args.quiet, debug=args.debug)
    prompt = resolve_prompt(args)
    client_cfg, draw_cfg, poll_cfg = build_configs(args)

    payload = draw_cfg.to_payload(prompt)
    if args.dry_run:
        print(json.dumps(payload, ensure_ascii=False, indent=2), flush=True)
        return 0

    if not args.quiet:
        logger.info(f"已读取 prompt，长度：{len(prompt)}")

    client = GrsAIClient(client_cfg, logger=logger)
    started = time.monotonic()
    task_id, url, raw = client.draw_and_wait(
        prompt=prompt,
        draw_cfg=draw_cfg,
        poll_cfg=poll_cfg,
        verbose=(not args.quiet),
    )
    elapsed_seconds = round(time.monotonic() - started, 3)

    local_path = None
    status = str(raw.get("status") or ("succeeded" if url else "failed"))

    if url and not args.no_download:
        try:
            local_path = download_image(
                url,
                output_dir=args.output_dir,
                task_id=task_id,
                timeout=(client_cfg.connect_timeout, client_cfg.timeout),
            )
            if not args.quiet:
                logger.info(f"图片已下载: {local_path}")
        except GrsAIError as exc:
            status = "download_failed"
            logger.error(str(exc))

    result = {
        "task_id": task_id,
        "url": url,
        "local_path": local_path,
        "status": status,
        "model": draw_cfg.model,
        "elapsed_seconds": elapsed_seconds,
        "raw": raw,
    }
    _emit_result(args, result)

    if status == "download_failed":
        return 3
    return 0 if url else 2


def _main(argv: Optional[List[str]] = None) -> int:
    parser = _build_parser()
    args = parser.parse_args(argv)

    if args.command == "draw":
        return run_draw(args)

    parser.print_help()
    return 2


def main(argv: Optional[List[str]] = None) -> int:
    try:
        return _main(argv)
    except GrsAIError as exc:
        print(f"调用失败：{exc}", file=sys.stderr, flush=True)
        return 2


def main_legacy(argv: Optional[List[str]] = None, *, show_warning: bool = True) -> int:
    input_argv = list(sys.argv[1:] if argv is None else argv)

    if show_warning:
        print(
            "[DEPRECATED] grsai_draw.py is kept for compatibility. "
            "Please migrate to: nbdraw draw ...",
            file=sys.stderr,
            flush=True,
        )

    if not input_argv:
        return main(["draw"])

    if input_argv[0] == "draw":
        return main(input_argv)
    if input_argv[0] in {"--help", "-h"}:
        return main(["draw", input_argv[0]])
    if input_argv[0] == "--version":
        return main(["--version"])

    return main(["draw", *input_argv])


if __name__ == "__main__":
    raise SystemExit(main())
