# client.py - RK3588板端激活程序（永久有效）
import os
import sys
import json
import hashlib
import hmac
import requests
import subprocess
import time
import logging
import argparse
from datetime import datetime

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# 配置
CONFIG = {
    'SERVER_URL': 'http://129.211.170.245:5000/',  # 修改为实际服务器地址
    'KEY_FILE': '/etc/device.key',  # 密钥文件存储路径
    'KEY_BACKUP_FILE': '/etc/device.key.bak',  # 密钥备份文件
    'CHIP_ID_SOURCES': [
        '/sys/devices/soc0/serial_number',
        '/sys/devices/platform/ff650000.serial/serial0',
        '/proc/cpuinfo'
    ],
    'ACTIVATE_URL': '/activate',
    'VERIFY_URL': '/verify',
    'ACTIVATE_RETRY_COUNT': 3,
    'SECRET_KEY': '69588cc5e1b701942cda09b33de5a95c02471f3aaaf610d80aaf5681f4b166e4'  # 必须和服务端一致
}


def get_chip_id():
    """
    获取RK3588芯片ID（增强版）
    """
    # 方法1: 从多个系统文件读取
    for source in CONFIG['CHIP_ID_SOURCES']:
        try:
            if os.path.exists(source):
                with open(source, 'r') as f:
                    content = f.read().strip()
                    
                    # 处理cpuinfo的特殊格式
                    if source == '/proc/cpuinfo':
                        for line in content.split('\n'):
                            if 'Serial' in line:
                                chip_id = line.split(':')[1].strip()
                                if chip_id:
                                    logger.info(f"从{source}获取芯片ID: {chip_id}")
                                    return chip_id
                    else:
                        if content:
                            logger.info(f"从{source}获取芯片ID: {content}")
                            return content
        except Exception as e:
            logger.warning(f"读取{source}失败: {e}")
    
    # 方法2: 使用dmidecode命令
    try:
        result = subprocess.run(
            ['dmidecode', '-s', 'system-serial-number'],
            capture_output=True,
            text=True,
            timeout=5
        )
        if result.returncode == 0 and result.stdout.strip():
            chip_id = result.stdout.strip()
            logger.info(f"从dmidecode获取芯片ID: {chip_id}")
            return chip_id
    except Exception as e:
        logger.warning(f"执行dmidecode失败: {e}")
    
    # 方法3: 读取MAC地址
    try:
        import uuid
        mac = uuid.UUID(int=uuid.getnode()).hex[-12:]
        chip_id = f"MAC-{mac}"
        logger.warning(f"使用MAC地址生成ID: {chip_id}")
        return chip_id
    except Exception as e:
        logger.error(f"无法获取任何标识: {e}")
        return None


def verify_key_signature(chip_id, key_data):
    """
    验证密钥签名（永久有效）
    """
    try:
        # 构建待签名数据
        data_to_sign = f"{chip_id}|{key_data['activation_id']}|{key_data['activate_time']}"
        
        # 计算期望的签名
        expected_signature = hmac.new(
            CONFIG['SECRET_KEY'].encode('utf-8'),
            data_to_sign.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()
        
        # 比对签名
        if key_data['signature'] != expected_signature:
            logger.error("密钥签名验证失败")
            return False, "密钥签名无效"
        
        logger.info("密钥签名验证通过")
        return True, "签名验证通过"
        
    except Exception as e:
        logger.error(f"签名验证异常: {e}")
        return False, f"验证异常: {str(e)}"


def save_key_file(key_data):
    """
    保存密钥文件到本地（永久有效）
    """
    try:
        # 确保目录存在
        key_dir = os.path.dirname(CONFIG['KEY_FILE'])
        if key_dir and not os.path.exists(key_dir):
            os.makedirs(key_dir, exist_ok=True)
        
        # 如果已有密钥文件，先备份
        if os.path.exists(CONFIG['KEY_FILE']):
            import shutil
            shutil.copy2(CONFIG['KEY_FILE'], CONFIG['KEY_BACKUP_FILE'])
            logger.info(f"已备份旧密钥文件到: {CONFIG['KEY_BACKUP_FILE']}")
        
        # 保存新密钥文件
        with open(CONFIG['KEY_FILE'], 'w') as f:
            json.dump(key_data, f, indent=2)
        
        # 设置文件权限为只读
        os.chmod(CONFIG['KEY_FILE'], 0o600)
        
        logger.info(f"密钥文件已保存: {CONFIG['KEY_FILE']}")
        return True
        
    except Exception as e:
        logger.error(f"保存密钥文件失败: {e}")
        return False


def load_key_file():
    """
    加载本地密钥文件
    """
    try:
        # 尝试加载主密钥文件
        if os.path.exists(CONFIG['KEY_FILE']):
            with open(CONFIG['KEY_FILE'], 'r') as f:
                key_data = json.load(f)
            logger.info("密钥文件加载成功")
            return key_data
        
        # 尝试加载备份密钥文件
        if os.path.exists(CONFIG['KEY_BACKUP_FILE']):
            logger.warning("主密钥文件不存在，尝试加载备份")
            with open(CONFIG['KEY_BACKUP_FILE'], 'r') as f:
                key_data = json.load(f)
            logger.info("备份密钥文件加载成功")
            return key_data
        
        logger.warning("密钥文件不存在")
        return None
        
    except Exception as e:
        logger.error(f"加载密钥文件失败: {e}")
        return None


def verify_local_key(chip_id):
    """
    本地验证密钥（永久有效，无过期检查）
    """
    # 加载密钥文件
    key_data = load_key_file()
    if not key_data:
        return False, "密钥文件不存在"
    
    # 验证芯片ID是否匹配
    if key_data.get('chip_id') != chip_id:
        logger.error(f"芯片ID不匹配: 期望 {key_data.get('chip_id')}, 实际 {chip_id}")
        return False, "芯片ID不匹配"
    
    # 验证签名
    valid, message = verify_key_signature(chip_id, key_data)
    if not valid:
        return False, message
    
    # 验证通过
    logger.info(f"永久激活验证通过！")
    logger.info(f"激活时间: {key_data['activate_time']}")
    logger.info(f"激活ID: {key_data['activation_id']}")
    
    return True, "验证通过（永久有效）"


def activate_device(chip_id):
    """
    联网激活设备（永久激活）
    """
    url = f"{CONFIG['SERVER_URL']}{CONFIG['ACTIVATE_URL']}"
    payload = {'chip_id': chip_id}
    
    for attempt in range(CONFIG['ACTIVATE_RETRY_COUNT']):
        try:
            logger.info(f"正在激活设备 (尝试 {attempt + 1}/{CONFIG['ACTIVATE_RETRY_COUNT']})...")
            response = requests.post(
                url,
                json=payload,
                timeout=10,
                headers={'Content-Type': 'application/json'}
            )
            
            if response.status_code == 200:
                data = response.json()
                if data.get('code') == 200:
                    # 保存密钥文件
                    key_data = data['data']
                    if save_key_file(key_data):
                        logger.info("设备永久激活成功！")
                        return True
                    else:
                        logger.error("保存密钥文件失败")
                else:
                    logger.error(f"激活失败: {data.get('message')}")
            else:
                logger.error(f"HTTP错误: {response.status_code}")
                
        except requests.exceptions.RequestException as e:
            logger.error(f"网络错误: {e}")
        except Exception as e:
            logger.error(f"激活过程中发生错误: {e}")
        
        if attempt < CONFIG['ACTIVATE_RETRY_COUNT'] - 1:
            wait_time = 2 ** attempt
            logger.info(f"等待 {wait_time} 秒后重试...")
            time.sleep(wait_time)
    
    return False


def create_emergency_key(chip_id):
    """
    创建应急密钥（当无法联网时使用，需人工授权）
    警告：此功能仅用于紧急情况
    """
    import secrets
    
    logger.warning("正在创建应急密钥...")
    
    # 生成应急密钥数据
    emergency_key = {
        'chip_id': chip_id,
        'activation_id': f"EMERGENCY-{secrets.token_hex(8)}",
        'activate_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'signature': 'EMERGENCY-MODE',  # 应急模式签名
        'permanent': True,
        'emergency': True,
        'version': '1.0'
    }
    
    # 保存应急密钥
    if save_key_file(emergency_key):
        logger.warning("应急密钥已创建！请确保这是授权操作！")
        return True
    
    return False


def main():
    """
    主函数：程序启动验证（永久有效）
    """
    parser = argparse.ArgumentParser(description='设备永久激活和验证程序')
    parser.add_argument('--force-activate', action='store_true', help='强制重新激活')
    parser.add_argument('--check-only', action='store_true', help='仅检查验证状态')
    parser.add_argument('--emergency', action='store_true', help='创建应急密钥（仅限授权使用）')
    parser.add_argument('--show-info', action='store_true', help='显示激活信息')
    args = parser.parse_args()
    
    # 获取芯片ID
    chip_id = get_chip_id()
    if not chip_id:
        logger.error("无法获取芯片ID")
        sys.exit(1)
    
    logger.info(f"芯片ID: {chip_id}")
    
    # 应急模式
    if args.emergency:
        if create_emergency_key(chip_id):
            logger.info("应急密钥创建成功")
            sys.exit(0)
        else:
            logger.error("应急密钥创建失败")
            sys.exit(1)
    
    # 显示激活信息
    if args.show_info:
        key_data = load_key_file()
        if key_data:
            print("\n" + "="*50)
            print("设备激活信息")
            print("="*50)
            print(f"芯片ID: {key_data.get('chip_id')}")
            print(f"激活时间: {key_data.get('activate_time')}")
            print(f"激活ID: {key_data.get('activation_id')}")
            print(f"激活类型: {'永久有效' if key_data.get('permanent') else '临时'}")
            if key_data.get('emergency'):
                print("警告: 应急模式激活")
            print("="*50)
        else:
            print("设备未激活")
        sys.exit(0)
    
    # 检查是否需要激活
    need_activate = args.force_activate
    
    if not need_activate:
        # 尝试本地验证
        valid, message = verify_local_key(chip_id)
        
        if valid:
            logger.info(f"✅ 验证成功: {message}")
            if not args.check_only:
                logger.info("验证通过，启动主程序...")
                # 在这里调用你的主程序
                # subprocess.run(['python3', 'your_main_program.py'])
            sys.exit(0)
        else:
            logger.warning(f"❌ 本地验证失败: {message}")
            need_activate = True
    
    # 需要联网激活
    if need_activate:
        logger.info("开始联网永久激活...")
        if activate_device(chip_id):
            # 激活后再次验证
            valid, message = verify_local_key(chip_id)
            if valid:
                logger.info(f"✅ 激活验证成功: {message}")
                logger.info("设备已永久激活，无需再次联网！")
                if not args.check_only:
                    logger.info("激活完成，启动主程序...")
                    # subprocess.run(['python3', 'your_main_program.py'])
                sys.exit(0)
            else:
                logger.error(f"❌ 激活后验证失败: {message}")
                sys.exit(1)
        else:
            logger.error("设备激活失败，请检查网络连接")
            sys.exit(1)


def install_service():
    """
    安装为系统服务
    """
    service_content = """[Unit]
Description=Device Permanent Activation Check Service
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/bin/python3 /opt/device_activation/client.py --check-only
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
"""
    
    service_file = '/etc/systemd/system/device-activation.service'
    try:
        # 复制程序到系统目录
        script_dir = '/opt/device_activation'
        os.makedirs(script_dir, exist_ok=True)
        
        import shutil
        shutil.copy2(__file__, os.path.join(script_dir, 'client.py'))
        os.chmod(os.path.join(script_dir, 'client.py'), 0o755)
        
        # 创建服务文件
        with open(service_file, 'w') as f:
            f.write(service_content)
        os.chmod(service_file, 0o644)
        
        logger.info(f"服务文件已创建: {service_file}")
        logger.info("请执行以下命令启用服务:")
        logger.info("sudo systemctl daemon-reload")
        logger.info("sudo systemctl enable device-activation.service")
        logger.info("sudo systemctl start device-activation.service")
        
    except Exception as e:
        logger.error(f"安装服务失败: {e}")


if __name__ == '__main__':
    if len(sys.argv) > 1 and sys.argv[1] == 'install-service':
        install_service()
    else:
        main()