#!/usr/bin/env python3
"""
版本自动生成与同步脚本 - 大厂标准版本管控
功能：
1. 单一版本源：VERSION文件作为唯一版本基准
2. 自动同步：VERSION → pom.xml → 子服务pom → 前端package.json
3. 版本校验：检测版本不一致并自动修复
4. 完整版本号生成：BASE-branch-commit-buildNum

使用方式：
  python scripts/update_version.py              # 完整同步+校验
  python scripts/update_version.py --check    # 仅校验，不修复
  python scripts/update_version.py --fix      # 校验+自动修复
  python scripts/update_version.py --single svc  # 更新单个服务
"""

import os
import subprocess
import json
import re
from datetime import datetime
import sys
import argparse

# 设置标准输出为UTF-8编码（兼容Python 3.6）
try:
    sys.stdout.reconfigure(encoding='utf-8')
except AttributeError:
    # Python 3.6 不支持reconfigure，使用默认编码
    pass

# ==================== 版本读取 ====================

def read_pom_version():
    """从pom.xml读取revision版本号"""
    pom_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'pom.xml')
    if os.path.exists(pom_path):
        with open(pom_path, 'r', encoding='utf-8') as f:
            content = f.read()
            match = re.search(r'<revision>([^<]+)</revision>', content)
            if match:
                return match.group(1).strip()
    return None

def read_version_file():
    """从 VERSION 文件读取基础版本号"""
    version_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'VERSION')
    if os.path.exists(version_path):
        with open(version_path, 'r', encoding='utf-8') as f:
            for line in f:
                if line.startswith('BASE_VERSION='):
                    return line.strip().split('=')[1].strip()
    return None

def get_base_version():
    """获取基础版本号（VERSION文件作为单一版本源）"""
    version_from_file = read_version_file()
    if version_from_file:
        return version_from_file
    pom_version = read_pom_version()
    if pom_version:
        return pom_version.replace('-SNAPSHOT', '')
    return "1.1.0"

# ==================== 版本同步 ====================

def sync_version_to_pom():
    """将VERSION文件中的版本号同步到pom.xml（确保单一版本源）"""
    version_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'VERSION')
    pom_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'pom.xml')
    
    if not os.path.exists(version_path) or not os.path.exists(pom_path):
        print("⚠️ VERSION文件或pom.xml不存在，跳过同步")
        return False
    
    base_version = read_version_file()
    if not base_version:
        print("⚠️ 无法读取VERSION文件，跳过同步")
        return False
    
    with open(pom_path, 'r', encoding='utf-8') as f:
        content = f.read()
    
    old_revision = re.search(r'<revision>([^<]+)</revision>', content)
    if old_revision:
        old_version = old_revision.group(1)
        if old_version != f"{base_version}-SNAPSHOT":
            print(f"🔄 同步VERSION到pom.xml: {old_version} → {base_version}-SNAPSHOT")
            content = re.sub(r'<revision>\d+\.\d+\.\d+(-SNAPSHOT)?</revision>', 
                           f'<revision>{base_version}-SNAPSHOT</revision>', content)
            with open(pom_path, 'w', encoding='utf-8') as f:
                f.write(content)
            print(f"✅ pom.xml revision已同步")
            return True
        else:
            print(f"✅ pom.xml revision已是最新: {old_version}")
            return False
    return False

def write_version_file(base_version):
    """写入VERSION全局文件"""
    version_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'VERSION')
    with open(version_path, 'w', encoding='utf-8') as f:
        f.write(f"BASE_VERSION={base_version}\n")
        f.write(f"BUILD_NUMBER={get_build_number()}\n")
        f.write(f"LAST_UPDATED={datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
    print(f"✅ 同步写入VERSION文件: BASE_VERSION={base_version}")

# ==================== 版本校验 ====================

def check_version_consistency():
    """检查版本一致性，返回不一致的文件列表"""
    issues = []
    
    version_file_base = read_version_file()
    pom_version = read_pom_version()
    
    if version_file_base and pom_version:
        pom_base = pom_version.replace('-SNAPSHOT', '')
        if pom_base != version_file_base:
            issues.append({
                'file': 'pom.xml',
                'current': pom_base,
                'expected': version_file_base,
                'severity': 'HIGH'
            })
    
    return issues

# ==================== Git信息 ====================

def get_git_commit_hash(length=8):
    """获取固定8位的commit hash"""
    try:
        result = subprocess.run(
            ['git', 'rev-parse', f'--short={length}', 'HEAD'],
            capture_output=True, text=True,
            cwd=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        )
        return result.stdout.strip()
    except Exception:
        return 'unknown'

def get_git_branch():
    try:
        result = subprocess.run(
            ['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
            capture_output=True, text=True,
            cwd=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        )
        return result.stdout.strip()
    except Exception:
        return 'unknown'

def get_build_number():
    """优先使用Jenkins BUILD_NUMBER，否则用时间戳"""
    jenkins_build_num = os.environ.get('BUILD_NUMBER')
    if jenkins_build_num:
        return jenkins_build_num
    try:
        result = subprocess.run(
            ['git', 'rev-list', '--count', 'HEAD'],
            capture_output=True, text=True,
            cwd=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        )
        return result.stdout.strip()
    except Exception:
        return datetime.now().strftime('%Y%m%d%H%M%S')

# ==================== 版本号更新 ====================

def update_service_version(service_name):
    """更新单个服务的版本号"""
    services_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'services')
    pom_path = os.path.join(services_dir, service_name, 'pom.xml')
    
    if not os.path.exists(pom_path):
        return False
    
    with open(pom_path, 'r', encoding='utf-8') as f:
        content = f.read()
    
    build_number = get_build_number()
    new_version = f'{get_base_version()}-{build_number}'
    
    pattern = r'(<artifactId>' + re.escape(service_name.replace('-', '-')) + r'</artifactId>\s*<version>)\d+\.\d+\.\d+(-\d+)?(</version>)'
    if re.search(pattern, content):
        content = re.sub(pattern, f'\\g<1>{new_version}\\g<3>', content)
        with open(pom_path, 'w', encoding='utf-8') as f:
            f.write(content)
        print(f"✅ 更新 {service_name} 版本号: {new_version}")
        return True
    return False

def update_backend_versions():
    """更新所有后端服务版本号
    
    注意：子服务使用 ${revision} 占位符继承父pom版本，
    无需单独修改子服务pom.xml版本号。
    仅在需要独立版本时才需要修改此处。
    """
    # 子服务继承父pom的 ${revision}，构建时自动解析，无需单独更新
    # 如果未来有独立版本的服务，可在此处添加更新逻辑
    pass

def update_web_version(project_path):
    package_json_path = os.path.join(project_path, 'package.json')
    if not os.path.exists(package_json_path):
        return
    
    with open(package_json_path, 'r', encoding='utf-8') as f:
        package = json.load(f)
    
    commit_hash = get_git_commit_hash()
    branch = get_git_branch()
    build_number = get_build_number()
    
    package['version'] = f"{get_base_version()}-{branch.replace('/', '-')}-{commit_hash}-{build_number}"
    
    with open(package_json_path, 'w', encoding='utf-8') as f:
        json.dump(package, f, indent=2, ensure_ascii=False)
    
    print(f"✅ 更新 {os.path.basename(project_path)} 版本号: {package['version']}")

def update_flutter_version(project_path):
    pubspec_path = os.path.join(project_path, 'pubspec.yaml')
    if not os.path.exists(pubspec_path):
        return
    
    with open(pubspec_path, 'r', encoding='utf-8') as f:
        content = f.read()
    
    build_number = get_build_number()
    version_pattern = r'version: \d+\.\d+\.\d+\+.*'
    new_version = f"version: {get_base_version()}+{build_number}"
    content = re.sub(version_pattern, new_version, content)
    
    with open(pubspec_path, 'w', encoding='utf-8') as f:
        f.write(content)
    
    print(f"✅ 更新 {os.path.basename(project_path)} 版本号: {new_version}")

def generate_version_info(output_path):
    """生成版本信息文件"""
    commit_hash = get_git_commit_hash()
    branch = get_git_branch()
    build_number = get_build_number()
    base_version = get_base_version()
    
    version_info = {
        'version': f"v{base_version}-{branch.replace('/', '-')}-{commit_hash}-{build_number}",
        'baseVersion': f"v{base_version}",
        'commit': commit_hash,
        'branch': branch,
        'buildNumber': build_number,
        'buildTime': datetime.now().isoformat(),
        'generatedAt': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'environment': os.getenv('ENV', 'development')
    }
    
    with open(output_path, 'w', encoding='utf-8') as f:
        json.dump(version_info, f, indent=2, ensure_ascii=False)
    
    print(f"✅ 生成版本信息文件: {output_path}")

# ==================== 主流程 ====================

def version_check_only():
    """仅校验版本一致性，不修复"""
    print("🔍 版本一致性校验...")
    print("="*70)
    
    issues = check_version_consistency()
    
    if issues:
        print("❌ 发现版本不一致问题:")
        for issue in issues:
            print(f"   [{issue['severity']}] {issue['file']}: 当前={issue['current']}, 期望={issue['expected']}")
        print("\n💡 使用 --fix 参数自动修复")
        return 1
    else:
        print("✅ 版本一致性校验通过!")
        return 0

def version_sync_and_fix():
    """同步+修复版本不一致"""
    print("🔄 版本同步与修复...")
    print("="*70)
    
    # 第一步：校验
    issues = check_version_consistency()
    
    if issues:
        print("⚠️ 检测到版本不一致，自动修复中...")
        for issue in issues:
            print(f"   [{issue['severity']}] {issue['file']}: {issue['current']} → {issue['expected']}")
    
    # 第二步：同步VERSION到pom.xml
    sync_version_to_pom()
    
    print(f"\n📦 项目基础版本号: v{get_base_version()}")
    print("="*70)
    
    # 第三步：更新子服务版本
    update_backend_versions()
    
    # 第四步：更新前端版本
    root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    web_projects = ['platform_web', 'merchant_web', 'official_website']
    flutter_projects = ['user_app', 'rider_app']
    
    for project in web_projects:
        path = os.path.join(root_dir, 'frontend', project)
        if os.path.exists(path):
            update_web_version(path)
    
    for project in flutter_projects:
        path = os.path.join(root_dir, 'frontend', project)
        if os.path.exists(path):
            update_flutter_version(path)
    
    # 第五步：生成版本信息文件
    generate_version_info(os.path.join(root_dir, 'version.json'))
    
    # 第六步：更新VERSION文件BUILD_NUMBER
    write_version_file(get_base_version())
    
    print("\n🎉 所有项目版本号同步完成!")
    print("="*70)
    print(f"📊 完整版本号: {get_base_version()}-{get_git_branch().replace('/', '-')}-{get_git_commit_hash()}-{get_build_number()}")
    print(f"🔗 Commit: {get_git_commit_hash()}")
    print(f"🌿 分支: {get_git_branch()}")
    print(f"🏗️ 构建号: {get_build_number()}")
    
    return 0

def update_all_versions():
    """完整版本更新流程"""
    return version_sync_and_fix()

def update_single_service(service_name):
    """更新单个服务版本号"""
    print(f"📦 更新单个服务版本号: {service_name}")
    print("="*70)
    
    # 先同步VERSION到pom.xml
    sync_version_to_pom()
    
    # 更新服务版本
    update_service_version(service_name)
    
    # 更新compose文件
    compose_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 
                               'infrastructure', 'compose', 'podman-compose.aliyun-dev.yml')
    if os.path.exists(compose_path):
        with open(compose_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        old_tag = rf'8.140.221.49:5000/fzx/{service_name}:v\d+\.\d+\.\d+'
        new_tag = f"8.140.221.49:5000/fzx/{service_name}:v{get_base_version()}"
        content = re.sub(old_tag, new_tag, content)
        
        with open(compose_path, 'w', encoding='utf-8') as f:
            f.write(content)
        
        print(f"✅ 更新 compose 文件中 {service_name} 镜像标签: {new_tag}")
    
    print(f"\n🎉 {service_name} 版本号更新完成!")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='版本自动生成与同步脚本')
    parser.add_argument('--check', action='store_true', help='仅校验版本一致性，不修复')
    parser.add_argument('--fix', action='store_true', help='校验并自动修复版本不一致')
    parser.add_argument('--single', metavar='SVC', help='更新单个服务版本号')
    
    args = parser.parse_args()
    
    if args.check:
        sys.exit(version_check_only())
    elif args.fix:
        sys.exit(version_sync_and_fix())
    elif args.single:
        update_single_service(args.single)
    else:
        # 默认：完整同步流程（包含自动修复）
        sys.exit(update_all_versions())
