#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
install-env.py - 一键安装前置环境 (Node.js + Python + git)

在跑 npx @hupan56/wlkj init 之前, 如果什么都没装, 先跑这个。
它会检测并自动安装缺失的环境。

Usage:
    python install-env.py          # 检测 + 自动装缺失的
    python install-env.py --check  # 只检测, 不装

注意: 这个脚本本身需要 Python 才能跑。如果用户连 Python 都没有:
    Windows: 去 python.org 下载安装 (勾 Add to PATH), 或用 winget:
             winget install Python.Python.3.12
    Mac:     brew install python
"""

import argparse
import os
import platform
import subprocess
import sys
from pathlib import Path

try:
    sys.stdout.reconfigure(encoding='utf-8', errors='replace')
    sys.stderr.reconfigure(encoding='utf-8', errors='replace')
except (AttributeError, TypeError, OSError):
    pass

IS_WIN = sys.platform == 'win32'
IS_MAC = sys.platform == 'darwin'


def run(cmd, **kw):
    kw.setdefault('capture_output', True)
    kw.setdefault('text', True)
    kw.setdefault('encoding', 'utf-8')
    kw.setdefault('errors', 'replace')
    try:
        return subprocess.run(cmd, **kw)
    except FileNotFoundError:
        import types
        return types.SimpleNamespace(returncode=127, stdout='', stderr='not found')


def check(cmd_name, version_flag='--version'):
    """检查某个命令是否存在, 返回 (是否可用, 版本字符串)。"""
    r = run([cmd_name, version_flag])
    if r.returncode == 0:
        return True, r.stdout.strip().split('\n')[0]
    return False, None


def ask(prompt, default='y'):
    if not sys.stdin.isatty():
        return default.lower() in ('y', 'yes')
    try:
        ans = input(f'{prompt} [{default}] ').strip().lower() or default
        return ans in ('y', 'yes')
    except (EOFError, KeyboardInterrupt):
        return default.lower() in ('y', 'yes')


def has_winget():
    return check('winget')[0]

def has_brew():
    return check('brew')[0]

def has_choco():
    return check('choco')[0]


# ============================================================
# 安装器
# ============================================================

def install_node():
    """安装 Node.js。"""
    print('\n--- 安装 Node.js ---')
    if IS_WIN:
        # 优先 winget
        if has_winget():
            print('  用 winget 安装 Node.js LTS...')
            r = run(['winget', 'install', '--id', 'OpenJS.NodeJS.LTS', '-e',
                     '--source', 'winget', '--accept-source-agreements',
                     '--accept-package-agreements'])
            if r.returncode == 0:
                print('  [OK] Node.js 安装成功 (可能需要新终端生效)')
                return True
            print('  winget 失败: ' + (r.stderr or '').strip()[:100])
        # 回退 choco
        if has_choco():
            print('  用 choco 安装...')
            r = run(['choco', 'install', 'nodejs-lts', '-y'])
            if r.returncode == 0:
                return True
        print('  自动安装失败。手动下载: https://nodejs.org (选 LTS)')
        return False
    elif IS_MAC:
        if has_brew():
            print('  用 brew 安装 Node.js...')
            r = run(['brew', 'install', 'node'])
            return r.returncode == 0
        print('  请先装 Homebrew: https://brew.sh')
        return False
    else:
        # Linux
        for mgr, cmd in [('apt', ['sudo', 'apt-get', 'install', '-y', 'nodejs', 'npm']),
                         ('dnf', ['sudo', 'dnf', 'install', '-y', 'nodejs', 'npm']),
                         ('yum', ['sudo', 'yum', 'install', '-y', 'nodejs', 'npm'])]:
            if check(mgr)[0]:
                print(f'  用 {mgr} 安装...')
                r = run(cmd)
                return r.returncode == 0
        print('  请手动安装: https://nodejs.org')
        return False


def install_python():
    """安装 Python 3.9+。"""
    print('\n--- 安装 Python ---')
    if IS_WIN:
        if has_winget():
            print('  用 winget 安装 Python 3.12...')
            r = run(['winget', 'install', '--id', 'Python.Python.3.12', '-e',
                     '--source', 'winget', '--accept-source-agreements',
                     '--accept-package-agreements'])
            if r.returncode == 0:
                print('  [OK] Python 安装成功 (可能需要新终端生效)')
                return True
            print('  winget 失败: ' + (r.stderr or '').strip()[:100])
        print('  自动安装失败。手动下载: https://python.org (勾 Add to PATH)')
        return False
    elif IS_MAC:
        if has_brew():
            print('  用 brew 安装 Python...')
            r = run(['brew', 'install', 'python@3.12'])
            return r.returncode == 0
        print('  请先装 Homebrew: https://brew.sh')
        return False
    else:
        for mgr, cmd in [('apt', ['sudo', 'apt-get', 'install', '-y', 'python3', 'python3-pip']),
                         ('dnf', ['sudo', 'dnf', 'install', '-y', 'python3']),
                         ('yum', ['sudo', 'yum', 'install', '-y', 'python3'])]:
            if check(mgr)[0]:
                print(f'  用 {mgr} 安装...')
                r = run(cmd)
                return r.returncode == 0
        print('  请手动安装: https://python.org')
        return False


def install_git():
    """安装 git。"""
    print('\n--- 安装 git ---')
    if IS_WIN:
        if has_winget():
            print('  用 winget 安装 Git...')
            r = run(['winget', 'install', '--id', 'Git.Git', '-e',
                     '--source', 'winget', '--accept-source-agreements',
                     '--accept-package-agreements'])
            if r.returncode == 0:
                print('  [OK] git 安装成功 (可能需要新终端生效)')
                return True
        print('  自动安装失败。手动下载: https://git-scm.com/download/win')
        return False
    elif IS_MAC:
        # Mac 上 git 通常自带 (装了 Xcode Command Line Tools)
        r = run(['xcode-select', '--install'])
        print('  通过 Xcode Command Line Tools 安装...')
        return True
    else:
        for mgr, cmd in [('apt', ['sudo', 'apt-get', 'install', '-y', 'git']),
                         ('dnf', ['sudo', 'dnf', 'install', '-y', 'git']),
                         ('yum', ['sudo', 'yum', 'install', '-y', 'git'])]:
            if check(mgr)[0]:
                print(f'  用 {mgr} 安装...')
                r = run(cmd)
                return r.returncode == 0
        print('  请手动安装: https://git-scm.com')
        return False


# ============================================================
# 主逻辑
# ============================================================

def main():
    parser = argparse.ArgumentParser(
        description='一键安装前置环境 (Node.js + Python + git)',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog='''安装完后跑:
  npx @hupan56/wlkj init

如果连 Python 都没有 (无法跑本脚本):
  Windows: winget install Python.Python.3.12
  Mac:     brew install python
''')
    parser.add_argument('--check', action='store_true', help='只检测, 不安装')
    args = parser.parse_args()

    print('=' * 50)
    print('  环境检测' + (' (仅检测)' if args.check else ' + 自动安装'))
    print('=' * 50)

    # 检测当前状态
    print('\n--- 当前状态 ---')
    node_ok, node_ver = check('node')
    py_ok, py_ver = check('python') or (sys.version_info >= (3, 9), f'Python {sys.version.split()[0]}')
    git_ok, git_ver = check('git')

    # Python 特殊: 本脚本在跑说明至少有 python, 但可能版本不够
    if not py_ok:
        py_ok = sys.version_info >= (3, 9)
        py_ver = f'Python {sys.version_info[0]}.{sys.version_info[1]}'

    print(f'  Node.js: {"[OK] " + node_ver if node_ok else "[缺失]"}')
    print(f'  Python:  {"[OK] " + py_ver if py_ok else "[缺失或版本低]"}')
    print(f'  git:     {"[OK] " + git_ver if git_ok else "[缺失] (可选, 不装也能用核心功能)"}')

    if args.check:
        print('\n仅检测模式。缺少的环境手动装, 或去掉 --check 自动安装。')
        return 0 if (node_ok and py_ok) else 1

    # 按需安装
    installed = []
    if not node_ok:
        if ask('\nNode.js 缺失 (npx 命令需要它), 自动安装?', 'y'):
            if install_node():
                installed.append('Node.js')
    if not py_ok:
        if ask('\nPython 版本过低或缺失, 自动安装?', 'y'):
            if install_python():
                installed.append('Python')
    if not git_ok:
        if ask('\ngit 缺失 (团队协作用, 核心功能不依赖), 自动安装?', 'y'):
            if install_git():
                installed.append('git')

    # 重新检测
    print('\n--- 安装后状态 ---')
    node_ok2, _ = check('node')
    # Python: 如果新装了, 当前进程还是旧的, 但 PATH 里应该有了
    git_ok2, _ = check('git')

    all_ok = node_ok or node_ok2
    print(f'  Node.js: {"[OK]" if all_ok else "[仍缺失, 可能需要新终端]"}')
    print(f'  Python:  [OK] {py_ver}')
    print(f'  git:     {"[OK]" if (git_ok or git_ok2) else "[缺失, 可选]"}')

    if installed:
        print(f'\n本次安装: {", ".join(installed)}')
        print('  ⚠ 新装的环境可能需要**重新打开终端**才能生效')

    if all_ok:
        print('\n' + '=' * 50)
        print('  环境就绪! 下一步:')
        print('=' * 50)
        print('\n  mkdir 我的项目 && cd 我的项目')
        print('  npx @hupan56/wlkj init')
        print('')
        return 0
    else:
        print('\n  Node.js 仍缺失, 请手动安装: https://nodejs.org')
        return 1


if __name__ == '__main__':
    sys.exit(main())
