#!/usr/bin/env python3
"""
leaf_publisher 命令行入口 (lpub)
"""

import argparse
import sys
from pathlib import Path
from getpass import getpass

from leaf_publisher.core import (
    check_readme,
    ensure_pyproject_toml,
    merge_requirements_to_dependencies,
    build_package,
    upload_to_pypi,
    install_local,
    run_tests
)
from leaf_publisher.config import get_publisher_config, load_project_pyproject
from leaf_publisher.toml_utils import dump_toml


def main():
    parser = argparse.ArgumentParser(
        description='leaf_publisher: 自动化 PyPI 发布工具（依赖智能扫描、一键上传）'
    )
    parser.add_argument(
        'project_dir', nargs='?', default='.',
        help='项目根目录（默认：当前目录）'
    )
    parser.add_argument(
        '--no-build', action='store_true',
        help='跳过构建步骤'
    )
    parser.add_argument(
        '--skip-publish', action='store_true',
        help='跳过发布步骤'
    )
    parser.add_argument(
        '--yes', '-y', action='store_true',
        help='自动确认发布，无需交互'
    )
    parser.add_argument(
        '--repository', default=None,
        help='PyPI 仓库名称（覆盖 pyproject.toml 中的配置），默认为 pypi'
    )
    parser.add_argument(
        '--no-deps', action='store_true',
        help='不自动合并 requirements.txt 到 pyproject.toml，并禁用依赖来源处理'
    )
    parser.add_argument(
        '--no-scan-deps', action='store_true',
        help='禁用依赖扫描（仅在创建 pyproject.toml 时生效）'
    )
    parser.add_argument(
        '--dep-version-policy', choices=['minimum', 'exact', 'compatible'],
        default='minimum',
        help='依赖版本策略（默认：minimum，即 >= 当前版本）'
    )
    parser.add_argument(
        '--use-git-version', action='store_true',
        help='从 Git 标签获取版本号（仅创建新 pyproject.toml 时生效）'
    )
    # 前五条新增参数
    parser.add_argument(
        '--install-local', action='store_true',
        help='发布前先将包安装到本地 Python 环境'
    )
    parser.add_argument(
        '--editable', action='store_true',
        help='以可编辑模式安装（需与 --install-local 同时使用）'
    )
    parser.add_argument(
        '--infer-version', action='store_true',
        help='智能推断并更新版本号（基于 Git 提交记录）'
    )
    parser.add_argument(
        '--changelog', action='store_true',
        help='自动生成 CHANGELOG.md'
    )
    parser.add_argument(
        '--test', action='store_true',
        help='发布前运行测试（默认使用 pytest）'
    )
    parser.add_argument(
        '--test-command', default=None,
        help='指定测试命令，如 "pytest tests/"'
    )
    parser.add_argument(
        '--no-cache', action='store_true',
        help='禁用依赖扫描缓存'
    )
    # 后五条新增参数
    parser.add_argument(
        '--deps-from', choices=['auto', 'scan', 'pipfile', 'poetry'], default='auto',
        help='依赖来源（默认 auto：优先 poetry.lock -> Pipfile -> 扫描）'
    )
    parser.add_argument(
        '--repository-url', default=None,
        help='私有 PyPI 仓库地址（覆盖 --repository）'
    )
    parser.add_argument(
        '--username', default=None,
        help='PyPI 用户名（用于密码认证，与 token 方式互斥）'
    )
    parser.add_argument(
        '--license', metavar='LICENSE_ID', default=None,
        help='使用预定义许可证（如 MIT, Apache-2.0, GPL-3.0）'
    )
    parser.add_argument(
        '--license-file', metavar='PATH', default=None,
        help='使用自定义许可证文件'
    )
    parser.add_argument(
        '--version', action='version',
        version=f'leaf_publisher {__import__("leaf_publisher").__version__}'
    )

    args = parser.parse_args()
    project_dir = Path(args.project_dir).resolve()

    if not project_dir.is_dir():
        print(f"❌ 错误：{project_dir} 不是有效的目录。", file=sys.stderr)
        sys.exit(1)

    # 1. 检查 README
    check_readme(project_dir)

    # 2. 加载或生成 pyproject.toml
    pyproject_data = ensure_pyproject_toml(
        project_dir,
        scan_deps=not args.no_scan_deps,
        version_policy=args.dep_version_policy,
        use_git_version=args.use_git_version,
        use_cache=not args.no_cache
    )

    # 3. 读取发布工具配置
    publisher_cfg = get_publisher_config(pyproject_data)

    # 4. 版本推断（若启用）
    if args.infer_version:
        from leaf_publisher.version import get_latest_git_tag, get_commits_since_tag, infer_next_version, prompt_version_update
        current_version = pyproject_data.get("project", {}).get("version")
        if not current_version:
            print("⚠️  项目中未定义版本号，无法推断。")
        else:
            latest_tag = get_latest_git_tag(project_dir)
            if latest_tag:
                commits = get_commits_since_tag(project_dir, latest_tag)
                suggested = infer_next_version(current_version, commits)
                new_version = prompt_version_update(current_version, suggested)
                if new_version and new_version != current_version:
                    pyproject_data["project"]["version"] = new_version
                    pyproject_path = project_dir / 'pyproject.toml'
                    dump_toml(pyproject_data, pyproject_path)
                    print(f"✅ 版本已更新为 {new_version}")
            else:
                print("⚠️  未找到 Git 标签，无法基于提交推断版本。")

    # 5. 生成 CHANGELOG（若启用）
    if args.changelog:
        from leaf_publisher.changelog import generate_changelog
        new_version = pyproject_data.get("project", {}).get("version")
        if new_version:
            generate_changelog(project_dir, new_version)
        else:
            print("⚠️  项目版本号为空，无法生成 CHANGELOG。")

    # 6. 依赖来源处理（除非 --no-deps）
    if not args.no_deps:
        from leaf_publisher.deps import generate_dependencies
        new_deps = generate_dependencies(
            project_dir,
            version_policy=args.dep_version_policy,
            use_cache=not args.no_cache,
            source=args.deps_from
        )
        existing_deps = pyproject_data.get("project", {}).get("dependencies", [])
        if set(new_deps) != set(existing_deps):
            print("\n📋 检测到新的依赖列表：")
            print("现有依赖:", existing_deps)
            print("新依赖:", new_deps)
            if args.yes:
                choice = 'merge'
            else:
                print("请选择操作：")
                print("  [m] 合并（去重）")
                print("  [r] 替换为新依赖")
                print("  [k] 保留现有依赖")
                print("  [c] 取消（退出）")
                resp = input("请选择 [m/r/k/c]: ").strip().lower()
                if resp == 'm':
                    choice = 'merge'
                elif resp == 'r':
                    choice = 'replace'
                elif resp == 'k':
                    choice = 'keep'
                else:
                    print("⏹️  已取消。")
                    sys.exit(0)
            if choice == 'merge':
                merged = list(set(existing_deps + new_deps))
                pyproject_data["project"]["dependencies"] = merged
                dump_toml(pyproject_data, project_dir / 'pyproject.toml')
                print("✅ 依赖已合并。")
            elif choice == 'replace':
                pyproject_data["project"]["dependencies"] = new_deps
                dump_toml(pyproject_data, project_dir / 'pyproject.toml')
                print("✅ 依赖已替换。")
            else:  # keep
                print("⏭️  保留现有依赖。")

    # 7. 合并 requirements.txt（除非明确禁止）
    if not args.no_deps and publisher_cfg.get("auto_merge_requirements", True):
        if merge_requirements_to_dependencies(project_dir, pyproject_data):
            pyproject_path = project_dir / 'pyproject.toml'
            dump_toml(pyproject_data, pyproject_path)
            print("✅ 已将 requirements.txt 中的依赖合并到 pyproject.toml")

    # 8. 处理许可证
    if args.license or args.license_file:
        from leaf_publisher.license import write_license
        if write_license(project_dir, license_id=args.license, license_file=args.license_file):
            # 更新 pyproject.toml 中的 license 字段
            project = pyproject_data.setdefault("project", {})
            project["license"] = {"file": "LICENSE"}
            pyproject_path = project_dir / 'pyproject.toml'
            dump_toml(pyproject_data, pyproject_path)
            print("✅ pyproject.toml 已更新许可证信息。")

    # 9. 构建参数确定（命令行 > 配置文件 > 默认值）
    skip_build = args.no_build
    if not skip_build and "skip_build" in publisher_cfg:
        skip_build = publisher_cfg["skip_build"]

    skip_publish = args.skip_publish
    if not skip_publish and "skip_publish" in publisher_cfg:
        skip_publish = publisher_cfg["skip_publish"]

    auto_yes = args.yes
    if not auto_yes and "auto_yes" in publisher_cfg:
        auto_yes = publisher_cfg["auto_yes"]

    repository = args.repository
    if repository is None:
        repository = publisher_cfg.get("repository", "pypi")

    # 10. 本地安装（若启用）
    if args.install_local:
        install_local(project_dir, editable=args.editable)

    # 11. 运行测试（若启用）
    if args.test:
        run_tests(project_dir, test_command=args.test_command)

    # 12. 构建
    if not skip_build:
        build_package(project_dir)

    # 13. 发布
    if skip_publish:
        print("⏭️  已跳过发布步骤。")
        return

    if not auto_yes:
        resp = input(f"❓ 是否立即上传？(y/N): ").strip().lower()
        if resp != 'y':
            print("⏹️  已取消上传。")
            return

    # 获取 token 或密码（上传函数内部会处理环境变量和交互）
    token = None
    password = None
    if args.username:
        # 用户名密码模式
        password = getpass("🔑 请输入密码: ") if not args.yes else None
    else:
        token = getpass("🔑 请输入 PyPI API token: ") if not args.yes else None

    upload_to_pypi(
        project_dir,
        repository=repository,
        token=token,
        repository_url=args.repository_url,
        username=args.username,
        password=password
    )


if __name__ == '__main__':
    main()