import jingrow
import os
import sys
import json
import random
import time
import uuid
from datetime import datetime
from typing import Dict, Any

from alibabacloud_swas_open20200601.client import Client as SWAS_OPEN20200601Client
from alibabacloud_credentials.client import Client as CredentialClient
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_swas_open20200601 import models as swas__open20200601_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_util.client import Client as UtilClient

from jcloud.utils import get_current_team


class AliyunLightServerManager:
    """阿里云轻量应用服务器管理器"""
    _instance = None
    _clients = {}  # 缓存不同地域的客户端
    
    @classmethod
    def get_instance(cls):
        """获取单例实例"""
        if cls._instance is None:
            cls._instance = cls()
        return cls._instance
    
    def __init__(self):
        """初始化管理器"""
        if AliyunLightServerManager._instance is not None:
            raise Exception("请使用 AliyunLightServerManager.get_instance() 获取实例")
        
        # 初始化配置
        self._initialize_credentials()
    
    def _initialize_credentials(self):
        """初始化阿里云凭据"""
        try:
            settings = jingrow.get_single("Jcloud Settings")
            if not settings:
                jingrow.log_error("阿里云凭据初始化失败", "无法获取Jcloud Settings配置")
                raise Exception("Jcloud Settings配置不存在")
            
            self.access_key_id = settings.get("aliyun_access_key_id")
            self.access_secret = settings.get_password("aliyun_access_secret") if settings.get("aliyun_access_secret") else None
            
            if not self.access_key_id or not self.access_secret:
                jingrow.log_error("阿里云凭据初始化失败", "阿里云凭据未配置，请在Jcloud Settings中配置aliyun_access_key_id和aliyun_access_secret")
                raise Exception("阿里云凭据未配置")
                
        except Exception as e:
            jingrow.log_error(f"阿里云凭据初始化失败: {str(e)}")
            self.access_key_id = None
            self.access_secret = None
            raise
    
    def _get_client(self, region_id: str = 'cn-shanghai') -> SWAS_OPEN20200601Client:
        """获取指定地域的客户端，使用缓存机制"""
        if region_id not in self._clients:
            try:
                # 直接使用凭据创建配置
                config = open_api_models.Config(
                    access_key_id=self.access_key_id,
                    access_key_secret=self.access_secret
                )
                config.endpoint = f'swas.{region_id}.aliyuncs.com'
                self._clients[region_id] = SWAS_OPEN20200601Client(config)
            except Exception as e:
                jingrow.log_error("阿里云客户端创建失败", f"创建客户端时发生错误: {str(e)}")
                raise
        
        return self._clients[region_id]
    
    def _convert_response_to_dict(self, response_body):
        """将阿里云SDK响应对象转换为可序列化的字典"""
        if response_body is None:
            return None
        
        result = {}
        # 获取所有公共属性
        for attr_name in dir(response_body):
            if not attr_name.startswith('_') and not callable(getattr(response_body, attr_name)):
                attr_value = getattr(response_body, attr_name)
                if attr_value is not None:
                    if hasattr(attr_value, '__dict__') and not isinstance(attr_value, (str, int, float, bool)):
                        # 如果是复杂对象，递归转换
                        result[attr_name] = self._convert_response_to_dict(attr_value)
                    elif isinstance(attr_value, list):
                        # 如果是列表，转换列表中的每个元素
                        converted_list = []
                        for item in attr_value:
                            if hasattr(item, '__dict__') and not isinstance(item, (str, int, float, bool)):
                                converted_list.append(self._convert_response_to_dict(item))
                            else:
                                converted_list.append(item)
                        result[attr_name] = converted_list
                    else:
                        # 基本类型直接赋值
                        result[attr_name] = attr_value
        
        return result
    
    def create_instance(self, plan_id, image_id, period=1, region_id='cn-shanghai'):
        """创建轻量应用服务器实例"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.CreateInstancesRequest(
                region_id=region_id,
                plan_id=plan_id,
                image_id=image_id,
                period=period
            )
            runtime = util_models.RuntimeOptions()
            response = client.create_instances_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例创建成功'}
        except Exception as e:
            jingrow.log_error("创建实例失败", f"创建实例时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '实例创建失败'}
    
    def start_instance(self, instance_id, region_id='cn-shanghai'):
        """启动实例"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.StartInstanceRequest(
                region_id=region_id,
                instance_id=instance_id
            )
            runtime = util_models.RuntimeOptions()
            response = client.start_instance_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例启动成功'}
        except Exception as e:
            jingrow.log_error("启动实例失败", f"启动实例 {instance_id} 时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '实例启动失败'}
    
    def stop_instance(self, instance_id, region_id='cn-shanghai'):
        """停止实例"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.StopInstanceRequest(
                region_id=region_id,
                instance_id=instance_id
            )
            runtime = util_models.RuntimeOptions()
            response = client.stop_instance_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例停止成功'}
        except Exception as e:
            jingrow.log_error("停止实例失败", f"停止实例 {instance_id} 时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '实例停止失败'}
    
    def reboot_instance(self, instance_id, region_id='cn-shanghai'):
        """重启实例"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.RebootInstanceRequest(
                region_id=region_id,
                instance_id=instance_id
            )
            runtime = util_models.RuntimeOptions()
            response = client.reboot_instance_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例重启成功'}
        except Exception as e:
            jingrow.log_error("重启实例失败", f"重启实例 {instance_id} 时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '实例重启失败'}

    def force_reboot_instances(self, instance_ids, region_id='cn-shanghai'):
        """强制重启实例（支持批量）"""
        client = self._get_client(region_id)
        try:
            if isinstance(instance_ids, list):
                instance_ids_str = json.dumps(instance_ids)
            else:
                instance_ids_str = instance_ids

            request = swas__open20200601_models.RebootInstancesRequest(
                region_id=region_id,
                force_reboot=True,
                instance_ids=instance_ids_str
            )
            runtime = util_models.RuntimeOptions()
            response = client.reboot_instances_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例强制重启命令已发送'}
        except Exception as e:
            jingrow.log_error("强制重启实例失败", f"强制重启实例 {instance_ids} 时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '实例强制重启失败'}
    
    def upgrade_instance(self, instance_id, plan_id, region_id='cn-shanghai'):
        """升级实例配置"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.UpgradeInstanceRequest(
                region_id=region_id,
                instance_id=instance_id,
                plan_id=plan_id
            )
            runtime = util_models.RuntimeOptions()
            response = client.upgrade_instance_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例升级成功'}
        except Exception as e:
            jingrow.log_error("升级实例失败", f"升级实例 {instance_id} 时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '实例升级失败'}
    
    def renew_instance(self, instance_id, period=1, region_id='cn-shanghai'):
        """续费实例"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.RenewInstanceRequest(
                region_id=region_id,
                instance_id=instance_id,
                period=period
            )
            runtime = util_models.RuntimeOptions()
            response = client.renew_instance_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例续费成功'}
        except Exception as e:
            jingrow.log_error("续费实例失败", f"续费实例 {instance_id} 时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '实例续费失败'}
    
    def reset_system(self, instance_id, image_id=None, password=None, region_id='cn-shanghai'):
        """重置系统"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.ResetSystemRequest(
                region_id=region_id,
                instance_id=instance_id
            )
            if image_id:
                request.image_id = image_id
            if password:
                request.password = password
            runtime = util_models.RuntimeOptions()
            response = client.reset_system_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '系统重置成功'}
        except Exception as e:
            jingrow.log_error("重置系统失败", f"重置实例 {instance_id} 系统时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '系统重置失败'}
    
    def update_instance_password(self, instance_id, password, region_id='cn-shanghai'):
        """更新实例密码"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.UpdateInstanceAttributeRequest(
                region_id=region_id,
                instance_id=instance_id,
                password=password
            )
            runtime = util_models.RuntimeOptions()
            response = client.update_instance_attribute_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '密码更新成功'}
        except Exception as e:
            jingrow.log_error("更新实例密码失败", f"更新实例 {instance_id} 密码时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '密码更新失败'}


    
    def list_instances(self, page_number=1, page_size=20, region_id='cn-shanghai'):
        """获取实例列表"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.ListInstancesRequest(
                region_id=region_id,
                page_number=page_number,
                page_size=page_size
            )
            runtime = util_models.RuntimeOptions()
            response = client.list_instances_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '获取实例列表成功'}
        except Exception as e:
            jingrow.log_error("获取实例列表失败", f"获取实例列表时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '获取实例列表失败'}
    
    def delete_instance(self, instance_id, region_id='cn-shanghai'):
        """删除实例"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.DeleteInstanceRequest(
                region_id=region_id,
                instance_id=instance_id
            )
            runtime = util_models.RuntimeOptions()
            response = client.delete_instance_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例删除成功'}
        except Exception as e:
            jingrow.log_error("删除实例失败", f"删除实例 {instance_id} 时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '实例删除失败'}
    
    def get_plans(self, region_id='cn-shanghai'):
        """获取可用套餐列表"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.ListPlansRequest(
                region_id=region_id
            )
            runtime = util_models.RuntimeOptions()
            response = client.list_plans_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '获取套餐列表成功'}
        except Exception as e:
            jingrow.log_error("获取套餐列表失败", f"获取套餐列表时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '获取套餐列表失败'}
    
    def get_images(self, image_type='system', region_id='cn-shanghai'):
        """获取可用镜像列表"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.ListImagesRequest(
                region_id=region_id,
                image_type=image_type
            )
            runtime = util_models.RuntimeOptions()
            response = client.list_images_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '获取镜像列表成功'}
        except Exception as e:
            jingrow.log_error("获取镜像列表失败", f"获取镜像列表时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '获取镜像列表失败'}
    
    def get_regions(self):
        """获取可用地域列表"""
        try:
            # 直接使用凭据创建配置
            config = open_api_models.Config(
                access_key_id=self.access_key_id,
                access_key_secret=self.access_secret
            )
            # 默认用上海endpoint，获取所有地域
            config.endpoint = 'swas.cn-shanghai.aliyuncs.com'
            client = SWAS_OPEN20200601Client(config)
            request = swas__open20200601_models.ListRegionsRequest(accept_language='zh-CN')
            runtime = util_models.RuntimeOptions()
            response = client.list_regions_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '获取地域列表成功'}
        except Exception as e:
            jingrow.log_error("获取地域列表失败", f"获取地域列表时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '获取地域列表失败'}

    def create_instance_key_pair(self, instance_id, key_pair_name, region_id='cn-shanghai'):
        """为实例创建密钥对"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.CreateInstanceKeyPairRequest(
                region_id=region_id,
                instance_id=instance_id,
                key_pair_name=key_pair_name
            )
            runtime = util_models.RuntimeOptions()
            response = client.create_instance_key_pair_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '密钥对创建成功'}
        except Exception as e:
            jingrow.log_error("创建密钥对失败", f"为实例 {instance_id} 创建密钥对 {key_pair_name} 时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '密钥对创建失败'}



    def delete_instance_key_pair(self, instance_id, region_id='cn-shanghai'):
        """解绑实例的密钥对"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.DeleteInstanceKeyPairRequest(
                region_id=region_id,
                instance_id=instance_id
            )
            runtime = util_models.RuntimeOptions()
            response = client.delete_instance_key_pair_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '密钥对解绑成功'}
        except Exception as e:
            jingrow.log_error("解绑密钥对失败", f"解绑实例 {instance_id} 密钥对时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '密钥对解绑失败'}

    def delete_key_pairs(self, key_pair_names, region_id='cn-shanghai'):
        """删除密钥对"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.DeleteKeyPairsRequest(
                region_id=region_id,
                key_pair_names=key_pair_names
            )
            runtime = util_models.RuntimeOptions()
            response = client.delete_key_pairs_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '密钥对删除成功'}
        except Exception as e:
            jingrow.log_error("删除密钥对失败", f"删除密钥对 {key_pair_names} 时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '密钥对删除失败'}

    def get_instance_key_pair(self, instance_id, region_id='cn-shanghai'):
        """获取实例的密钥对详细信息"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.DescribeInstanceKeyPairRequest(
                region_id=region_id,
                instance_id=instance_id
            )
            runtime = util_models.RuntimeOptions()
            response = client.describe_instance_key_pair_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '获取密钥对详细信息成功'}
        except Exception as e:
            jingrow.log_error("获取密钥对详细信息失败", f"获取实例 {instance_id} 密钥对详细信息时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '获取密钥对详细信息失败'}

    def get_instance_details(self, instance_ids, region_id='cn-shanghai'):
        """获取实例详细信息（支持批量查询）"""
        client = self._get_client(region_id)
        try:
            # 如果instance_ids是列表，转换为JSON字符串
            if isinstance(instance_ids, list):
                instance_ids_str = json.dumps(instance_ids)
            else:
                instance_ids_str = instance_ids
                
            request = swas__open20200601_models.ListInstancesRequest(
                region_id=region_id,
                instance_ids=instance_ids_str
            )
            runtime = util_models.RuntimeOptions()
            response = client.list_instances_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '获取实例详细信息成功'}
        except Exception as e:
            jingrow.log_error("获取实例详细信息失败", f"获取实例详细信息时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '获取实例详细信息失败'}

    def get_instance_upgrade_plans(self, instance_id, region_id='cn-shanghai'):
        """获取指定实例可升级的套餐列表"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.ListInstancePlansModificationRequest(
                region_id=region_id,
                instance_id=instance_id
            )
            runtime = util_models.RuntimeOptions()
            response = client.list_instance_plans_modification_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '获取可升级套餐列表成功'}
        except Exception as e:
            jingrow.log_error("获取可升级套餐列表失败", f"获取实例 {instance_id} 可升级套餐时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '获取可升级套餐列表失败'}

    def run_command(self, instance_id, command_content, parameters=None, command_name='CustomCommand', region_id='cn-shanghai', timeout=3600):
        """在实例上执行命令"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.RunCommandRequest(
                region_id=region_id,
                command_content=command_content,
                type='RunShellScript',
                enable_parameter=True if parameters else False,
                parameters=parameters or {},
                instance_id=instance_id,
                name=command_name,
                timeout=timeout
            )
            runtime = util_models.RuntimeOptions()
            response = client.run_command_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '命令执行成功'}
        except Exception as e:
            jingrow.log_error("执行命令失败", f"在实例 {instance_id} 上执行命令时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '命令执行失败'}

    def create_firewall_rule(self, instance_id, rule_protocol, port, remark=None, region_id='cn-shanghai'):
        """为实例创建防火墙规则"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.CreateFirewallRuleRequest(
                region_id=region_id,
                instance_id=instance_id,
                rule_protocol=rule_protocol,
                port=port,
                remark=remark
            )
            runtime = util_models.RuntimeOptions()
            response = client.create_firewall_rule_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '防火墙规则创建成功'}
        except Exception as e:
            jingrow.log_error("创建防火墙规则失败", f"为实例 {instance_id} 创建防火墙规则时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '创建防火墙规则失败'}

    def list_firewall_rules(self, instance_id, region_id='cn-shanghai', page_size=10, page_number=1):
        """获取实例的防火墙规则列表
        Args:
            instance_id: 实例ID
            region_id: 地域ID
            page_size: 每页记录数，默认10，如果设置为-1则获取全部数据
            page_number: 页码，默认1
        """
        client = self._get_client(region_id)
        try:
            if page_size == -1:
                # 获取全部数据
                all_rules = []
                current_page = 1
                request_page_size = 50  # 每次请求50条记录，减少API调用次数
                
                while True:
                    request = swas__open20200601_models.ListFirewallRulesRequest(
                        region_id=region_id,
                        instance_id=instance_id,
                        page_size=request_page_size,
                        page_number=current_page
                    )
                    runtime = util_models.RuntimeOptions()
                    response = client.list_firewall_rules_with_options(request, runtime)
                    
                    response_data = self._convert_response_to_dict(response.body)
                    current_rules = response_data.get('firewall_rules', [])
                    
                    if not current_rules:
                        break
                        
                    all_rules.extend(current_rules)
                    
                    # 如果当前页记录数少于request_page_size，说明已经是最后一页
                    if len(current_rules) < request_page_size:
                        break
                        
                    current_page += 1
                
                # 构造返回结果
                result_data = response_data.copy()
                result_data['firewall_rules'] = all_rules
                result_data['total_count'] = len(all_rules)
                
                return {'success': True, 'data': result_data, 'message': f'获取防火墙规则列表成功，共{len(all_rules)}条记录'}
            else:
                # 分页获取数据
                request = swas__open20200601_models.ListFirewallRulesRequest(
                    region_id=region_id,
                    instance_id=instance_id,
                    page_size=page_size,
                    page_number=page_number
                )
                runtime = util_models.RuntimeOptions()
                response = client.list_firewall_rules_with_options(request, runtime)
                
                response_data = self._convert_response_to_dict(response.body)
                rules_count = len(response_data.get('firewall_rules', []))
                
                return {'success': True, 'data': response_data, 'message': f'获取防火墙规则列表成功，第{page_number}页，共{rules_count}条记录'}
                
        except Exception as e:
            jingrow.log_error("获取防火墙规则列表失败", f"获取实例 {instance_id} 防火墙规则列表时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '获取防火墙规则列表失败'}

    def delete_firewall_rules(self, instance_id, rule_ids, region_id='cn-shanghai'):
        """批量删除实例的防火墙规则"""
        client = self._get_client(region_id)
        try:
            request = swas__open20200601_models.DeleteFirewallRulesRequest(
                region_id=region_id,
                instance_id=instance_id,
                rule_ids=rule_ids
            )
            runtime = util_models.RuntimeOptions()
            response = client.delete_firewall_rules_with_options(request, runtime)
            return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '批量删除防火墙规则成功'}
        except Exception as e:
            jingrow.log_error("批量删除防火墙规则失败", f"删除实例 {instance_id} 防火墙规则时发生错误: {str(e)}")
            return {'success': False, 'error': str(e), 'message': '批量删除防火墙规则失败'}


# 全局管理器实例
_aliyun_manager = None

def _get_manager():
    """获取阿里云管理器实例"""
    global _aliyun_manager
    if _aliyun_manager is None:
        _aliyun_manager = AliyunLightServerManager.get_instance()
    return _aliyun_manager


# API函数 - 使用@jingrow.whitelist()装饰器
@jingrow.whitelist()
def create_aliyun_instance(plan_id, image_id, period=1, region_id='cn-shanghai'):
    """创建轻量应用服务器实例"""
    manager = _get_manager()
    return manager.create_instance(plan_id, image_id, period, region_id)

@jingrow.whitelist()
def start_aliyun_instance(instance_id, region_id='cn-shanghai'):
    """启动实例"""
    manager = _get_manager()
    return manager.start_instance(instance_id, region_id)

@jingrow.whitelist()
def stop_aliyun_instance(instance_id, region_id='cn-shanghai'):
    """停止实例"""
    manager = _get_manager()
    return manager.stop_instance(instance_id, region_id)

@jingrow.whitelist()
def reboot_aliyun_instance(instance_id, region_id='cn-shanghai'):
    """重启实例并更新状态"""
    try:
        # 1. 查找对应的Jsite Server记录
        server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        if not server:
            return {"success": False, "message": "找不到对应的服务器记录"}
        
        # 2. 立即更新状态为"重启中"
        server.status = "Starting"
        server.save(ignore_permissions=True)
        jingrow.db.commit()
        
        # 3. 调用阿里云API重启实例
        manager = _get_manager()
        result = manager.reboot_instance(instance_id, region_id)
        
        # 4. 启动后台任务监控重启状态（延迟10秒开始）
        time.sleep(10)
        jingrow.enqueue(
            "jcloud.api.aliyun_server_light.monitor_server_status",
            instance_id=instance_id,
            region_id=region_id,
            timeout=600
        )
        
        return {
            "success": True, 
            "message": "重启命令已发送，正在监控重启状态...",
            "server_name": server.name
        }
        
    except Exception as e:
        jingrow.log_error("重启实例失败", f"重启实例 {instance_id} 时发生错误: {str(e)}")
        return {"success": False, "error": str(e), "message": "重启实例失败"}

@jingrow.whitelist()
def force_reboot_aliyun_instance(instance_id, region_id='cn-shanghai'):
    """强制重启实例并更新状态"""
    try:
        # 1. 查找对应的Jsite Server记录
        server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        if not server:
            return {"success": False, "message": "找不到对应的服务器记录"}

        # 2. 立即更新状态为"启动中"（与普通重启保持一致）
        server.status = "Starting"
        server.save(ignore_permissions=True)
        jingrow.db.commit()

        # 3. 调用阿里云API强制重启实例
        manager = _get_manager()
        result = manager.force_reboot_instances([instance_id], region_id)

        if not result or not result.get('success'):
            return result

        # 4. 启动后台任务监控重启状态（延迟10秒开始）
        time.sleep(10)
        jingrow.enqueue(
            "jcloud.api.aliyun_server_light.monitor_server_status",
            instance_id=instance_id,
            region_id=region_id,
            timeout=600
        )

        return {
            "success": True,
            "message": "强制重启命令已发送，正在监控重启状态...",
            "server_name": server.name
        }

    except Exception as e:
        jingrow.log_error("强制重启实例失败", f"强制重启实例 {instance_id} 时发生错误: {str(e)}")
        return {"success": False, "error": str(e), "message": "强制重启实例失败"}


def monitor_server_status(instance_id, region_id):
    """通用的服务器状态监控 - 监控服务器状态直到Running"""
    try:
        # 通过instance_id查找服务器记录
        server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        if not server:
            jingrow.log_error("找不到服务器记录", f"无法找到实例ID为 {instance_id} 的服务器记录")
            return
        
        manager = _get_manager()
        max_retries = 60  # 最多查询60次（10分钟）
        # 阿里云轻量应用服务器可能的状态值
        waiting_states = ['Starting', 'Stopping', 'Resetting', 'Stopped', 'Pending', 'Upgrading']
        
        for retry in range(max_retries):
            # 查询实例状态
            instance_info = manager.get_instance_details([instance_id], region_id)
            
            if not instance_info or not instance_info.get('success'):
                jingrow.log_error("获取实例状态失败", f"无法获取实例 {instance_id} 的状态信息")
                time.sleep(10)
                continue
            
            # 解析实例状态
            instances = instance_info.get('data', {}).get('instances', [])
            if not instances:
                jingrow.log_error("获取实例状态失败", f"实例 {instance_id} 的状态信息为空")
                time.sleep(10)
                continue
                
            instance = instances[0]  # 取第一个实例
            status = instance.get('status', '')
              
            # 更新服务器状态
            if status == 'Running':
                server.status = 'Running'
                server.save(ignore_permissions=True)
                jingrow.db.commit()
                return
            elif status in waiting_states:
                # 继续等待
                time.sleep(10)
            else:
                server.status = status
                server.save(ignore_permissions=True)
                jingrow.db.commit()
                return
        
    except Exception as e:
        jingrow.log_error("监控状态失败", f"监控实例 {instance_id} 状态时发生错误: {str(e)}")

@jingrow.whitelist()
def upgrade_aliyun_instance(instance_id, plan_id, region_id='cn-shanghai'):
    """升级实例配置并更新状态"""
    try:
        # 1. 查找对应的Jsite Server记录
        server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        if not server:
            return {"success": False, "message": "找不到对应的服务器记录"}
        
        # 2. 立即更新状态为"升级中"
        server.status = "Upgrading"
        server.save(ignore_permissions=True)
        jingrow.db.commit()
        
        # 3. 调用阿里云API升级实例
        manager = _get_manager()
        result = manager.upgrade_instance(instance_id, plan_id, region_id)
        
        if not result or not result.get('success'):
            # 如果升级失败，恢复状态
            server.status = "Running"
            server.save(ignore_permissions=True)
            jingrow.db.commit()
            return result
        
        # 4. 启动后台任务监控升级状态（延迟10秒开始）
        time.sleep(10)
        jingrow.enqueue(
            "jcloud.api.aliyun_server_light.monitor_server_status",
            instance_id=instance_id,
            region_id=region_id,
            timeout=600
        )
        
        return {
            "success": True, 
            "message": "升级命令已发送，正在监控升级状态...",
            "server_name": server.name
        }
        
    except Exception as e:
        jingrow.log_error("升级实例失败", f"升级实例 {instance_id} 时发生错误: {str(e)}")
        return {"success": False, "error": str(e), "message": "升级实例失败"}

@jingrow.whitelist()
def renew_aliyun_instance(instance_id, period=1, region_id='cn-shanghai'):
    """续费实例"""
    manager = _get_manager()
    return manager.renew_instance(instance_id, period, region_id)

@jingrow.whitelist()
def reset_aliyun_instance_system(instance_id, image_id=None, password=None, region_id='cn-shanghai'):
    """重置系统并更新状态"""
    try:
        # 1. 查找对应的Jsite Server记录
        server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        if not server:
            return {"success": False, "message": "找不到对应的服务器记录"}
        
        # 2. 立即更新状态为"重置中"
        server.status = "Resetting"
        server.save(ignore_permissions=True)
        jingrow.db.commit()
        
        # 3. 调用阿里云API重置系统
        manager = _get_manager()
        result = manager.reset_system(instance_id, image_id, password, region_id)
        
        # 4. 启动后台任务监控重置状态（延迟10秒开始）
        time.sleep(10)
        jingrow.enqueue(
            "jcloud.api.aliyun_server_light.monitor_server_status",
            instance_id=instance_id,
            region_id=region_id,
            timeout=600
        )
        
        return {
            "success": True, 
            "message": "重置命令已发送，正在监控重置状态...",
            "server_name": server.name
        }
        
    except Exception as e:
        jingrow.log_error("重置系统失败", f"重置实例 {instance_id} 系统时发生错误: {str(e)}")
        return {"success": False, "error": str(e), "message": "重置系统失败"}

@jingrow.whitelist()
def update_aliyun_instance_password(instance_id, password, region_id='cn-shanghai'):
    """更新实例密码"""
    manager = _get_manager()
    return manager.update_instance_password(instance_id, password, region_id)

@jingrow.whitelist()
def reset_aliyun_instance_password(instance_id, password, region_id='cn-shanghai'):
    """重置实例密码并更新Jsite Server记录"""
    try:
        # 1. 查找对应的Jsite Server记录
        server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        if not server:
            return {"success": False, "message": "找不到对应的服务器记录"}
        
        # 2. 调用阿里云API更新密码
        manager = _get_manager()
        result = manager.update_instance_password(instance_id, password, region_id)
        
        if not result or not result.get('success'):
            error_msg = f"阿里云密码更新失败: {result.get('message', '未知错误')}"
            jingrow.log_error("重置密码失败", error_msg)
            return {"success": False, "message": error_msg}
        
        # 3. 更新Jsite Server记录中的password字段
        server.password = password
        server.save(ignore_permissions=True)
        jingrow.db.commit()
        
        # 4. 自动重启实例
        reboot_aliyun_instance(instance_id, region_id)
        
        return {
            "success": True,
            "message": "密码重置成功",
            "server_name": server.name,
            "instance_id": instance_id
        }
        
    except Exception as e:
        jingrow.log_error("重置密码失败", f"重置实例 {instance_id} 密码时发生错误: {str(e)}")
        return {"success": False, "error": str(e), "message": "密码重置失败"}


@jingrow.whitelist()
def list_aliyun_instances(page_number=1, page_size=20, region_id='cn-shanghai'):
    """获取实例列表"""
    manager = _get_manager()
    return manager.list_instances(page_number, page_size, region_id)

@jingrow.whitelist()
def delete_aliyun_instance(instance_id, region_id='cn-shanghai'):
    """删除实例"""
    manager = _get_manager()
    return manager.delete_instance(instance_id, region_id)

@jingrow.whitelist()
def get_aliyun_plans(region_id='cn-shanghai'):
    """获取可用套餐列表"""
    manager = _get_manager()
    result = manager.get_plans(region_id)
    
    # 过滤指定类型的套餐
    if result.get('success') and result.get('data') and 'plans' in result['data']:
        allowed_types = ['NORMAL', 'MULTI_IP', 'INTERNATIONAL', 'CAPACITY']
        filtered_plans = [
            plan for plan in result['data']['plans'] 
            if plan.get('plan_type') in allowed_types
        ]
        
        # 在origin_price上统一增加20%作为利润
        for plan in filtered_plans:
            if 'origin_price' in plan and plan['origin_price'] is not None:
                original_price = float(plan['origin_price'])
                plan['origin_price'] = int(original_price / (1 - 0.2))  # 确保20%利润率且价格为整数
        
        result['data']['plans'] = filtered_plans
    
    return result

@jingrow.whitelist()
def get_aliyun_images(image_type='system', region_id='cn-shanghai'):
    """获取可用镜像列表"""
    manager = _get_manager()
    result = manager.get_images(image_type, region_id)
    
    # 如果获取成功且有镜像数据，过滤并排序
    if result.get('success') and result.get('data') and 'images' in result['data']:
        images = result['data']['images']
        # 过滤掉以 "alibaba" 开头的镜像（不区分大小写）
        filtered_images = [
            image for image in images 
            if not image.get('image_name', '').lower().startswith('alibaba')
        ]
        # 按镜像名称（image_name）进行字母排序
        sorted_images = sorted(filtered_images, key=lambda x: x.get('image_name', '').lower())
        result['data']['images'] = sorted_images
    
    return result

@jingrow.whitelist()
def get_aliyun_regions():
    """通过阿里云SDK实时获取可用地域列表"""
    manager = _get_manager()
    return manager.get_regions()

@jingrow.whitelist()
def create_aliyun_instance_key_pair(instance_id, key_pair_name, region_id='cn-shanghai'):
    """为实例创建密钥对"""
    manager = _get_manager()
    return manager.create_instance_key_pair(instance_id, key_pair_name, region_id)



@jingrow.whitelist()
def delete_aliyun_instance_key_pair(instance_id):
    """解绑并删除实例的密钥对"""
    try:
        # 1. 查找对应的Jsite Server记录获取key_pair_name和region_id
        server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        if not server:
            return {"success": False, "message": "找不到对应的服务器记录"}
        
        key_pair_name = server.key_pair_name
        region_id = server.region
        
        if not key_pair_name:
            return {"success": True, "message": "实例没有关联的密钥对"}
        
        manager = _get_manager()
        
        # 2. 解绑实例的密钥对
        unbind_result = manager.delete_instance_key_pair(instance_id, region_id)
        if not unbind_result or not unbind_result.get('success'):
            return {"success": False, "message": f"解绑密钥对失败: {unbind_result.get('message', '未知错误')}"}
        
        # 3. 删除密钥对
        delete_result = manager.delete_key_pairs([key_pair_name], region_id)
        if not delete_result or not delete_result.get('success'):
            return {"success": False, "message": f"删除密钥对失败: {delete_result.get('message', '未知错误')}"}
        
        # 4. 清除服务器记录中的密钥对信息
        server.key_pair_name = None
        server.private_key = None
        server.save(ignore_permissions=True)
        jingrow.db.commit()
        
        return {"success": True, "message": "密钥对解绑并删除成功"}
        
    except Exception as e:
        jingrow.log_error("删除实例密钥对失败", f"删除实例 {instance_id} 密钥对时发生错误: {str(e)}")
        return {"success": False, "message": str(e)}


@jingrow.whitelist()
def get_aliyun_instance_key_pair(instance_id, region_id='cn-shanghai'):
    """获取实例的密钥对详细信息"""
    manager = _get_manager()
    return manager.get_instance_key_pair(instance_id, region_id)

@jingrow.whitelist()
def get_aliyun_instance_details(instance_ids, region_id='cn-shanghai'):
    """获取实例详细信息（支持批量查询）"""
    manager = _get_manager()
    return manager.get_instance_details(instance_ids, region_id)

@jingrow.whitelist()
def get_aliyun_instance_upgrade_plans(instance_id):
    """获取指定实例可升级的套餐列表"""
    try:
        # 获取当前实例信息
        server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        if not server:
            return {"success": False, "message": "找不到服务器记录"}
        
        # 从实例记录中获取region_id
        region_id = server.region
        if not region_id:
            return {"success": False, "message": "服务器记录缺少region信息"}
        
        # 从get_plans获取所有套餐
        manager = _get_manager()
        result = manager.get_plans(region_id)
        
        if not result or not result.get('success'):
            return result
        
        # 过滤套餐：只返回PlanType值一致的套餐，且价格大于等于当前套餐价格
        if result.get('data') and 'plans' in result['data']:
            # 先统一调整所有套餐价格
            for plan in result['data']['plans']:
                if 'origin_price' in plan and plan['origin_price'] is not None:
                    original_price = float(plan['origin_price'])
                    plan['origin_price'] = int(original_price / (1 - 0.2))  # 确保20%利润率且价格为整数
            
            # 获取当前套餐价格
            current_plan_price = 0
            if server.planid:
                for plan in result['data']['plans']:
                    if plan.get('plan_id') == server.planid:
                        current_plan_price = plan['origin_price']
                        break
            
            # 过滤套餐
            filtered_plans = []
            for plan in result['data']['plans']:
                # 检查plan_type是否与服务器的PlanType一致
                if plan.get('plan_type') == server.plan_type:
                    # 检查support_platform是否包含当前实例的os_type
                    support_platform_str = plan.get('support_platform', '')
                    try:
                        support_platform_list = json.loads(support_platform_str) if support_platform_str else []
                        if server.os_type and server.os_type in support_platform_list:
                            # 只显示价格大于等于当前套餐价格的套餐
                            if plan['origin_price'] > current_plan_price:
                                filtered_plans.append(plan)
                    except:
                        continue
            
            result['data']['plans'] = filtered_plans
        
        return result
        
    except Exception as e:
        jingrow.log_error("获取可升级套餐列表失败", f"获取实例 {instance_id} 可升级套餐时发生错误: {str(e)}")
        return {"success": False, "error": str(e), "message": "获取可升级套餐列表失败"}


# 服务器订单和创建相关

@jingrow.whitelist()
def create_server_order(**kwargs):
    """创建服务器订单"""
    try:
        plan_id = kwargs.get('plan_id')
        image_id = kwargs.get('image_id')
        period = kwargs.get('period', 1)
        region_id = kwargs.get('region_id', 'cn-shanghai')
        plan_type = kwargs.get('plan_type', '')
        
        if not plan_id or not image_id:
            jingrow.throw("缺少必要参数")
            
        team = get_current_team(True)
        
        # 获取套餐价格
        plans_response = get_aliyun_plans(region_id)
        selected_plan = None
        if plans_response and plans_response.get('success'):
            plans = plans_response['data'].get('plans', [])
            selected_plan = next((p for p in plans if p.get('plan_id') == plan_id), None)
        
        if not selected_plan:
            jingrow.throw("套餐不存在")
        
        # 计算价格
        monthly_price = float(selected_plan.get('origin_price', 0))
        total_amount = monthly_price * period
        
        # 生成订单号
        order_id = datetime.now().strftime('%Y%m%d%H%M%S%f')[:-3] + ''.join(random.choices('0123456789', k=6))
        
        # 构建业务参数
        biz_params = {
            "plan_id": plan_id,
            "image_id": image_id,
            "period": period,
            "region_id": region_id,
            "plan_type": plan_type,
            "monthly_price": monthly_price,
            "total_amount": total_amount,
            "plan_info": {
                "core": selected_plan.get('core'),
                "memory": selected_plan.get('memory'),
                "disk_size": selected_plan.get('disk_size'),
                "bandwidth": selected_plan.get('bandwidth')
            }
        }
        
        # 创建订单记录
        order = jingrow.get_pg({
            "pagetype": "Order",
            "order_id": order_id,
            "order_type": "新建服务器",
            "team": team.name,
            "status": "待支付",
            "total_amount": total_amount,
            "title": f"{region_id}",
            "description": f"{selected_plan.get('core')}核/{selected_plan.get('memory')}GB/{selected_plan.get('disk_size')}GB, {period}个月",
            "biz_params": json.dumps(biz_params, ensure_ascii=False)
        })
        order.insert(ignore_permissions=True)
        
        jingrow.db.commit()
        
        return {"success": True, "order": order.as_dict()}
        
    except Exception as e:
        jingrow.log_error("创建服务器订单失败", str(e))
        return {"success": False, "message": str(e)}

@jingrow.whitelist()
def create_server_renew_order(**kwargs):
    """创建服务器续费订单"""
    try:
        server = kwargs.get('server')
        renewal_months = kwargs.get('renewal_months', 1)
        
        if not server:
            jingrow.throw("缺少服务器信息")
            
        # 验证输入
        server_pg = jingrow.get_pg("Jsite Server", server)
        if not server_pg:
            jingrow.throw("服务器不存在")
            
        team = server_pg.team
        
        # 验证当前用户权限
        current_team = get_current_team(True)
        if current_team.name != team:
            jingrow.throw("您没有权限为此服务器创建续费订单")
        
        # 计算续费金额
        renewal_months = int(renewal_months)
        plan_price = server_pg.plan_price or 0
        total_amount = plan_price * renewal_months
        
        # 生成唯一订单号
        order_id = datetime.now().strftime('%Y%m%d%H%M%S%f')[:-3] + ''.join(random.choices('0123456789', k=6))
        
        # 构建业务参数
        biz_params = {
            "server": server,
            "renewal_months": renewal_months,
            "plan_price": plan_price,
            "total_amount": total_amount,
            "instance_id": server_pg.instance_id,
            "region_id": server_pg.region,
            "plan_id": server_pg.planid
        }
        
        # 创建订单记录
        order = jingrow.get_pg({
            "pagetype": "Order",
            "order_id": order_id,
            "order_type": "服务器续费",
            "team": team,
            "status": "待支付",
            "total_amount": total_amount,
            "title": server_pg.instance_id,
            "description": str(renewal_months),  # 存储续费月数
            "biz_params": json.dumps(biz_params, ensure_ascii=False)
        })
        
        order.insert(ignore_permissions=True)
        jingrow.db.commit()
        
        return {
            "success": True,
            "order": order.as_dict()
        }
    except Exception as e:
        jingrow.log_error("续费订单错误", f"创建续费订单失败: {str(e)}")
        return {
            "success": False,
            "message": f"创建续费订单失败: {str(e)}"
        }

@jingrow.whitelist()
def create_server_upgrade_order(**kwargs):
    """创建服务器升级订单"""
    try:
        server = kwargs.get('server')
        new_plan_id = kwargs.get('new_plan_id')
        
        if not server or not new_plan_id:
            jingrow.throw("缺少必要参数")
            
        # 验证输入
        server_pg = jingrow.get_pg("Jsite Server", server)
        if not server_pg:
            jingrow.throw("服务器不存在")
            
        team = server_pg.team
        
        # 验证当前用户权限
        current_team = get_current_team(True)
        if current_team.name != team:
            jingrow.throw("您没有权限为此服务器创建升级订单")
        
        # 获取套餐列表
        plans_response = get_aliyun_plans(server_pg.region)
        if not plans_response or not plans_response.get('success'):
            jingrow.throw("获取套餐列表失败")
        
        plans = plans_response['data'].get('plans', [])
        
        # 获取当前套餐价格
        current_plan_price = 0
        if server_pg.planid:
            for plan in plans:
                if plan.get('plan_id') == server_pg.planid:
                    current_plan_price = float(plan.get('origin_price', 0))
                    break
        
        # 获取新套餐价格
        new_plan = None
        for plan in plans:
            if plan.get('plan_id') == new_plan_id:
                new_plan = plan
                break
        
        if not new_plan:
            jingrow.throw("新套餐不存在")
        
        new_plan_price = float(new_plan.get('origin_price', 0))
        
        # 计算剩余天数
        if server_pg.end_date:
            try:
                # 确保end_date是datetime.date对象
                if isinstance(server_pg.end_date, str):
                    end_date = jingrow.utils.getdate(server_pg.end_date)
                else:
                    end_date = server_pg.end_date
                current_date = jingrow.utils.nowdate()
                remaining_days = (end_date - current_date).days
                if remaining_days <= 0:
                    remaining_days = 1  # 至少1天
            except Exception as e:
                jingrow.log_error("计算剩余天数失败", f"计算实例 {server_pg.instance_id} 剩余天数时发生错误: {str(e)}")
                remaining_days = 30  # 出错时使用默认值
        else:
            remaining_days = 30  # 默认30天
        
        # 计算升级费用：按天计费，全额补差价
        daily_price_diff = (new_plan_price - current_plan_price) / 30
        upgrade_amount = daily_price_diff * remaining_days
        
        # 确保升级费用不为负数
        if upgrade_amount < 0:
            upgrade_amount = 0
        
        # 生成唯一订单号
        order_id = datetime.now().strftime('%Y%m%d%H%M%S%f')[:-3] + ''.join(random.choices('0123456789', k=6))
        
        # 构建业务参数
        biz_params = {
            "server": server,
            "new_plan_id": new_plan_id,
            "current_plan_price": current_plan_price,
            "new_plan_price": new_plan_price,
            "remaining_days": remaining_days,
            "upgrade_amount": upgrade_amount,
            "instance_id": server_pg.instance_id,
            "region_id": server_pg.region,
            "current_plan_id": server_pg.planid,
            "new_plan_info": {
                "core": new_plan.get('core'),
                "memory": new_plan.get('memory'),
                "disk_size": new_plan.get('disk_size'),
                "bandwidth": new_plan.get('bandwidth')
            }
        }
        
        # 创建订单记录
        order = jingrow.get_pg({
            "pagetype": "Order",
            "order_id": order_id,
            "order_type": "服务器升级",
            "team": team,
            "status": "待支付",
            "total_amount": upgrade_amount,
            "title": server_pg.instance_id,
            "description": new_plan_id,  # 存储新套餐ID
            "biz_params": json.dumps(biz_params, ensure_ascii=False)
        })
        
        order.insert(ignore_permissions=True)
        jingrow.db.commit()
        
        return {
            "success": True,
            "order": order.as_dict(),
            "upgrade_info": {
                "current_plan_price": current_plan_price,
                "new_plan_price": new_plan_price,
                "remaining_days": remaining_days,
                "daily_price_diff": daily_price_diff,
                "upgrade_amount": upgrade_amount
            }
        }
    except Exception as e:
        jingrow.log_error("升级订单错误", f"创建升级订单失败: {str(e)}")
        return {
            "success": False,
            "message": f"创建升级订单失败: {str(e)}"
        }

def renew_server(order_name):
    """支付成功后异步续费服务器"""
    try:
        order = jingrow.get_pg("Order", order_name)
        if not order:
            raise Exception("订单不存在")
        
        # 从biz_params中读取业务参数
        biz_params = json.loads(order.biz_params) if order.biz_params else {}
        server_name = biz_params.get("server")
        renewal_months = biz_params.get("renewal_months", 1)
        instance_id = biz_params.get("instance_id")
        region_id = biz_params.get("region_id", "cn-shanghai")
        
        if not server_name or not instance_id:
            raise Exception("订单中缺少必要的服务器信息")
        
        # 查找服务器记录
        server = jingrow.get_pg("Jsite Server", server_name)
        if not server:
            raise Exception("找不到对应的服务器记录")
        
        # 调用阿里云API续费
        manager = _get_manager()
        result = manager.renew_instance(instance_id, renewal_months, region_id)
        
        if not result or not result.get('success'):
            raise Exception(f"阿里云续费失败: {result.get('message', '未知错误')}")
        
        # 更新服务器到期时间
        server.end_date = jingrow.utils.add_months(server.end_date or jingrow.utils.nowdate(), renewal_months)
        server.save(ignore_permissions=True)
        
        # 更新订单状态
        order.status = "交易成功"
        order.save(ignore_permissions=True)
        
        jingrow.db.commit()
        
        return True
        
    except Exception as e:
        jingrow.log_error("服务器续费失败", f"订单 {order_name}: {str(e)}")
        raise e

def upgrade_server(order_name):
    """支付成功后异步升级服务器"""
    try:
        order = jingrow.get_pg("Order", order_name)
        if not order:
            raise Exception("订单不存在")
        
        # 从biz_params中读取业务参数
        biz_params = json.loads(order.biz_params) if order.biz_params else {}
        server_name = biz_params.get("server")
        new_plan_id = biz_params.get("new_plan_id")
        instance_id = biz_params.get("instance_id")
        region_id = biz_params.get("region_id", "cn-shanghai")
        
        if not server_name or not new_plan_id or not instance_id:
            raise Exception("订单中缺少必要的服务器升级信息")
        
        # 查找服务器记录
        server = jingrow.get_pg("Jsite Server", server_name)
        if not server:
            raise Exception("找不到对应的服务器记录")
        
        # 调用阿里云API升级实例
        result = upgrade_aliyun_instance(instance_id, new_plan_id, region_id)
        
        # 打印result到后台日志
        jingrow.log_error("阿里云升级实例结果", f"订单 {order_name} 的升级结果: {result}")
        
        if not result or not result.get('success'):
            raise Exception(f"阿里云升级失败: {result.get('message', '未知错误')}")
        
        # 更新服务器记录中的套餐信息
        new_plan_info = biz_params.get("new_plan_info", {})
        if new_plan_info:
            server.planid = new_plan_id
            server.cpu = new_plan_info.get("core")
            server.memory = new_plan_info.get("memory")
            server.disk_size = new_plan_info.get("disk_size")
            server.bandwidth = new_plan_info.get("bandwidth")
            server.plan_price = biz_params.get("new_plan_price", 0)
            server.save(ignore_permissions=True)
        
        # 更新订单状态
        order.status = "交易成功"
        order.save(ignore_permissions=True)
        
        jingrow.db.commit()
        
        # 延迟60秒执行update_server_record来更新服务器详细信息
        time.sleep(60)
        jingrow.enqueue(
            "jcloud.api.aliyun_server_light.update_server_record",
            instance_ids=json.dumps([instance_id]),
            timeout=120
        )
        
        return True
        
    except Exception as e:
        jingrow.log_error("服务器升级失败", f"订单 {order_name}: {str(e)}")
        raise e

def create_aliyun_server(order_name):
    """异步创建服务器"""
    try:
        order = jingrow.get_pg("Order", order_name)
        if not order:
            raise Exception("订单不存在")
        
        # 从biz_params中读取业务参数
        biz_params = json.loads(order.biz_params) if order.biz_params else {}
        plan_id = biz_params.get("plan_id")
        image_id = biz_params.get("image_id")
        period = biz_params.get("period", 1)
        region_id = biz_params.get("region_id", "cn-shanghai")
        plan_type = biz_params.get("plan_type", "")
        monthly_price = biz_params.get("monthly_price", 0)
        plan_info = biz_params.get("plan_info", {})
        
        if not plan_id or not image_id:
            raise Exception("订单中缺少必要的服务器配置信息")
        
        # 调用阿里云API创建实例
        result = create_aliyun_instance(plan_id, image_id, period, region_id)
        
        # 打印result到后台日志
        jingrow.log_error("阿里云创建实例结果", f"订单 {order_name} 的创建结果: {result}")
        
        if not result or not result.get('success'):
            raise Exception(f"阿里云创建失败: {result.get('message', '未知错误')}")
        
        # 阿里云API返回的是instance_ids数组，取第一个实例ID
        instance_id = result['data']['instance_ids'][0]
        
        # 创建本地服务器记录
        server = jingrow.get_pg({
            "pagetype": "Jsite Server",
            "team": order.team,
            "order_id": order.order_id,
            "status": "Pending",
            "instance_id": instance_id,
            "region": region_id,
            "image_id": image_id,
            "end_date": jingrow.utils.add_months(jingrow.utils.nowdate(), period),
            "title": f"{region_id} - {plan_info.get('core', '')}核/{plan_info.get('memory', '')}GB",
            "planid": plan_id,
            "plan_type": plan_type,
            "period": period,
            "plan_price": monthly_price,
            "cpu": plan_info.get('core'),
            "memory": plan_info.get('memory'),
            "disk_size": plan_info.get('disk_size'),
            "bandwidth": plan_info.get('bandwidth')
        })
        server.insert(ignore_permissions=True)
               
        # 更新订单状态
        order.status = "交易成功"
        order.save(ignore_permissions=True)
        
        jingrow.db.commit()
        
        # 延迟60秒执行update_server_record来更新服务器详细信息
        time.sleep(30)
        jingrow.enqueue(
            "jcloud.api.aliyun_server_light.update_server_record",
            instance_ids=json.dumps([instance_id]),
            timeout=120
        )
        
        return True
        
    except Exception as e:
        jingrow.log_error("服务器创建失败", f"订单 {order_name}: {str(e)}")
        raise e

@jingrow.whitelist()
def create_server_key_pair(instance_id):
    """为实例创建密钥对并保存私钥"""
    try:
        # 查找对应的服务器记录获取region_id
        server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        if not server:
            jingrow.log_error("找不到对应的服务器记录")
        
        region_id = server.region
        uuid_suffix = str(uuid.uuid4())[:4]
        key_pair_name = f"{region_id}-{instance_id[:8]}-{uuid_suffix}"
        
        # 直接调用管理器方法创建密钥对
        manager = _get_manager()
        key_pair_result = manager.create_instance_key_pair(instance_id, key_pair_name, region_id)
                
        if not key_pair_result or not key_pair_result.get('success'):
            error_msg = key_pair_result.get('message', '未知错误') if key_pair_result else '返回结果为空'
            jingrow.log_error(f"密钥对创建失败: {error_msg}")
            return {"success": False, "message": f"密钥对创建失败: {error_msg}"}
        
        # 获取私钥 - 直接访问data字段
        key_pair_data = key_pair_result.get('data', {})
        private_key = key_pair_data.get('private_key')
        
        if private_key:
            # 保存私钥到服务器记录
            server.key_pair_name = key_pair_name
            server.private_key = private_key
            server.save(ignore_permissions=True)
            jingrow.db.commit()
            
            return {
                "success": True,
                "message": "密钥对创建成功",
                "key_pair_name": key_pair_name,
                "private_key": private_key
            }
        else:
            jingrow.log_error("密钥对创建成功但未获取到私钥", f"完整的key_pair_result: {key_pair_result}")
            return {"success": False, "message": "密钥对创建成功但未获取到私钥"}
            
    except Exception as e:
        jingrow.log_error("创建密钥对失败", f"实例 {instance_id}: {str(e)}")
        return {"success": False, "message": str(e)}

@jingrow.whitelist()
def update_server_record(instance_ids):
    """根据阿里云实例信息更新Jsite Server记录"""
    try:
        # 解析instance_ids（JSON字符串格式）
        if isinstance(instance_ids, str):
            instance_ids = json.loads(instance_ids)
        
        # 获取第一个实例ID
        instance_id = instance_ids[0]
        
        # 查找对应的Jsite Server记录获取region_id
        server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        if not server:
            jingrow.log_error("更新服务器信息失败", f"找不到实例ID为 {instance_id} 的Jsite Server记录")
            return {"success": False, "message": f"找不到实例ID为 {instance_id} 的Jsite Server记录"}
        
        region_id = server.region
        
        # 获取阿里云实例详细信息
        instance_details = get_aliyun_instance_details(instance_ids, region_id)
        
        if not instance_details or not instance_details.get('success'):
            error_msg = f"获取阿里云实例信息失败: {instance_details.get('message', '未知错误')}"
            jingrow.log_error("更新服务器信息失败", error_msg)
            return {"success": False, "message": error_msg}
        
        # 解析实例信息
        instances = instance_details.get('data', {}).get('instances', [])
        if not instances:
            jingrow.log_error("更新服务器信息失败", "未找到实例信息")
            return {"success": False, "message": "未找到实例信息"}
        
        instance_info = instances[0]  # 取第一个实例
        
        # 获取公网IP（必需，实例状态为Running且最多重试30次）
        if not instance_info.get('public_ip_address') or instance_info.get('status') != 'Running':
            for retry in range(30):
                time.sleep(10)
                retry_details = get_aliyun_instance_details(instance_ids, region_id)
                if retry_details and retry_details.get('success'):
                    retry_instances = retry_details.get('data', {}).get('instances', [])
                    if retry_instances:
                        current_status = retry_instances[0].get('status', '')
                        current_public_ip = retry_instances[0].get('public_ip_address')
                        if current_status == 'Running' and current_public_ip:
                            # 条件满足后，重新获取完整的实例信息
                            instance_info = retry_instances[0]
                            break
            else:
                jingrow.log_error(f"获取实例信息失败-{instance_id}", f"实例 {instance_id} 在30次重试后仍未变为Running状态或获取到公网IP")
                return {"success": False, "message": f"实例 {instance_id} 在30次重试后仍未变为Running状态或获取到公网IP"}
        
        server.public_ip = instance_info.get('public_ip_address')
        
        server.private_ip = instance_info.get('inner_ip_address') or instance_info.get('network_attributes', [{}])[0].get('private_ip_address')
        
        # 更新end_date（从expired_time转换）
        expired_time = instance_info.get('expired_time')
        if expired_time:
            try:
                expired_datetime = datetime.fromisoformat(expired_time.replace('Z', '+00:00'))
                server.end_date = expired_datetime.strftime('%Y-%m-%d %H:%M:%S')
            except Exception as e:
                jingrow.log_error("时间格式转换失败", f"转换expired_time {expired_time} 时发生错误: {str(e)}")
        
        # 更新其他相关信息
        server.status = instance_info.get('status', '')
        
        # 更新系统信息
        image_info = instance_info.get('image', {})
        if image_info:
            image_name = image_info.get('image_name', '')
            image_version = image_info.get('image_version', '')
            os_type = image_info.get('os_type', '')

            server.system = f"{image_name} {image_version}".strip()
            server.os_type = os_type
        
        # 更新资源规格信息
        resource_spec = instance_info.get('resource_spec', {})
        if resource_spec:
            server.cpu = resource_spec.get('cpu')
            server.memory = resource_spec.get('memory')
            server.disk_size = resource_spec.get('disk_size')
            server.bandwidth = resource_spec.get('bandwidth')
        
        # 更新套餐信息
        plan_id = instance_info.get('plan_id')
        if plan_id:
            # 更新planid
            server.planid = plan_id
            
            # 直接从实例信息获取plan_type
            plan_type = instance_info.get('plan_type')
            if plan_type:
                server.plan_type = plan_type
            
            # 获取套餐信息来计算价格
            plans_result = get_aliyun_plans(region_id)
            if plans_result and plans_result.get('success') and plans_result.get('data', {}).get('plans'):
                for plan in plans_result['data']['plans']:
                    if plan.get('plan_id') == plan_id:
                        # 使用调整后的价格（已经包含20%利润）
                        if 'origin_price' in plan and plan['origin_price'] is not None:
                            server.plan_price = float(plan['origin_price'])
                        break

        # 保存更新
        server.save(ignore_permissions=True)
        jingrow.db.commit()
        
        # 同步防火墙规则（在保存服务器信息之后）
        sync_firewall_rules(instance_id)
        
        return {
            "success": True,
            "message": "服务器信息更新成功",
            "updated_fields": {
                "public_ip": instance_info.get('public_ip_address'),
                "private_ip": server.private_ip,
                "end_date": server.end_date,
                "status": instance_info.get('status'),
                "system": server.system,
                "os_type": server.os_type,
                "plan_price": server.plan_price,
                "planid": server.planid
            }
        }
        
    except Exception as e:
        jingrow.log_error("更新服务器信息失败", f"更新服务器信息时发生错误: {str(e)}")
        return {"success": False, "message": str(e)}

@jingrow.whitelist()
def reset_server_key_pair(instance_id):
    """重置服务器密钥对：先删除旧的，再创建新的"""
    try:
        # 第一步：删除旧的密钥对（如果存在）
        delete_aliyun_instance_key_pair(instance_id)
        
        # 第二步：创建新的密钥对
        result = create_server_key_pair(instance_id)
        
        return result
            
    except Exception as e:
        jingrow.log_error("重置密钥对失败", f"重置实例 {instance_id} 密钥对时发生错误: {str(e)}")
        return {"success": False, "message": str(e)}

@jingrow.whitelist()
def get_server_plan_price(instance_id):
    """根据实例ID获取当前套餐的实时价格"""
    try:
        # 获取服务器记录
        server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        if not server:
            return {"success": False, "message": "找不到服务器记录"}
        
        if not server.planid:
            return {"success": False, "message": "服务器记录缺少套餐信息"}
        
        # 获取套餐列表（使用get_aliyun_plans确保价格调整一致）
        plans_result = get_aliyun_plans(server.region)
        
        if not plans_result or not plans_result.get('success'):
            return {"success": False, "message": "获取套餐列表失败"}
        
        # 查找当前套餐
        plans = plans_result.get('data', {}).get('plans', [])
        current_plan = None
        for plan in plans:
            if plan.get('plan_id') == server.planid:
                current_plan = plan
                break
        
        if not current_plan:
            return {"success": False, "message": "找不到对应的套餐信息"}
        
        # 使用已经调整过的价格
        current_plan_price = float(current_plan.get('origin_price', 0))
        
        return {
            "success": True,
            "plan_price": current_plan_price,
            "plan_info": {
                "plan_id": current_plan.get('plan_id'),
                "cpu": current_plan.get('core'),
                "memory": current_plan.get('memory'),
                "disk_size": current_plan.get('disk_size'),
                "bandwidth": current_plan.get('bandwidth')
            }
        }
        
    except Exception as e:
        jingrow.log_error("获取套餐价格失败", f"获取实例 {instance_id} 套餐价格时发生错误: {str(e)}")
        return {"success": False, "error": str(e), "message": "获取套餐价格失败"}

@jingrow.whitelist()
def get_password(pagetype, name, fieldname):

	return jingrow.get_pg(pagetype, name).get_password(fieldname)

@jingrow.whitelist()
def get_jsite_server(instance_id=None, name=None):
    """获取Jsite Server记录"""
    try:
        if not instance_id and not name:
            return {"success": False, "message": "请提供 instance_id 或 name 参数"}
        
        server = None
        if instance_id:
            server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        elif name:
            server = jingrow.get_pg("Jsite Server", name)
        
        if not server:
            return {"success": False, "message": "找不到对应的服务器记录"}
        
        # 返回服务器信息（排除敏感字段）
        server_data = server.as_dict()
        
        # 移除敏感字段
        sensitive_fields = ['password', 'private_key']
        for field in sensitive_fields:
            if field in server_data:
                del server_data[field]
        
        return {
            "success": True,
            "data": server_data,
            "message": "获取服务器记录成功"
        }
        
    except Exception as e:
        jingrow.log_error("获取Jsite Server记录失败", f"获取服务器记录时发生错误: {str(e)}")
        return {"success": False, "message": f"获取服务器记录失败: {str(e)}"}

@jingrow.whitelist()
def create_aliyun_firewall_rule(instance_id, rule_protocol, port, remark=None, region_id='cn-shanghai'):
    """创建阿里云轻量应用服务器防火墙规则"""
    try:      
        # 调用管理器创建防火墙规则
        manager = _get_manager()
        result = manager.create_firewall_rule(instance_id, rule_protocol, port, remark, region_id)
        
        # 如果创建成功，同步防火墙规则到本地记录
        if result and result.get('success'):
            sync_firewall_rules(instance_id)
        
        return result
        
    except Exception as e:
        jingrow.log_error("创建防火墙规则失败", f"为实例 {instance_id} 创建防火墙规则时发生错误: {str(e)}")
        return {"success": False, "error": str(e), "message": "创建防火墙规则失败"}

@jingrow.whitelist()
def get_aliyun_firewall_rules(instance_id, region_id='cn-shanghai', page_size=10, page_number=1):
    """获取阿里云轻量应用服务器防火墙规则列表
    Args:
        instance_id: 实例ID
        region_id: 地域ID，默认cn-shanghai
        page_size: 每页记录数，默认10，如果设置为-1则获取全部数据
        page_number: 页码，默认1
    """
    try:        
        # 调用管理器获取防火墙规则列表
        manager = _get_manager()
        result = manager.list_firewall_rules(instance_id, region_id, page_size, page_number)
        
        return result
        
    except Exception as e:
        jingrow.log_error("获取防火墙规则列表失败", f"获取实例 {instance_id} 防火墙规则列表时发生错误: {str(e)}")
        return {"success": False, "error": str(e), "message": "获取防火墙规则列表失败"}

@jingrow.whitelist()
def delete_aliyun_firewall_rules(instance_id, rule_ids, region_id='cn-shanghai'):
    """批量删除阿里云轻量应用服务器防火墙规则"""
    try:        
        # 调用管理器批量删除防火墙规则
        manager = _get_manager()
        result = manager.delete_firewall_rules(instance_id, rule_ids, region_id)
        
        # 如果删除成功，同步防火墙规则到本地记录
        if result and result.get('success'):
            sync_firewall_rules(instance_id)
        
        return result
        
    except Exception as e:
        jingrow.log_error("批量删除防火墙规则失败", f"删除实例 {instance_id} 防火墙规则时发生错误: {str(e)}")
        return {"success": False, "error": str(e), "message": "批量删除防火墙规则失败"}

@jingrow.whitelist()
def sync_firewall_rules(instance_id):
    """同步阿里云防火墙规则到本地Jsite Server记录"""
    try:
        # 查找对应的Jsite Server记录
        server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        if not server:
            return {"success": False, "message": "找不到对应的服务器记录"}
        
        region_id = server.region
        if not region_id:
            return {"success": False, "message": "服务器记录缺少region信息"}
        
        # 获取阿里云防火墙规则（获取全部数据）
        firewall_result = get_aliyun_firewall_rules(instance_id, region_id, page_size=-1)
        if not firewall_result or not firewall_result.get('success'):
            error_msg = f"获取阿里云防火墙规则失败: {firewall_result.get('message', '未知错误')}"
            jingrow.log_error("同步防火墙规则失败", error_msg)
            return {"success": False, "message": error_msg}
        
        firewall_rules_data = firewall_result.get('data', {}).get('firewall_rules', [])
        
        # 转换防火墙规则格式
        converted_rules = []
        for rule in firewall_rules_data:
            converted_rule = {
                "rule_id": rule.get('rule_id', ''),
                "rule_protocol": rule.get('rule_protocol', ''),
                "port": rule.get('port', ''),
                "source_cidr_ip": rule.get('source_cidr_ip', '0.0.0.0/0'),
                "remark": rule.get('remark', '')
            }
            converted_rules.append(converted_rule)
        
        # 清空现有的防火墙规则并添加新的
        server.firewall_rules = []
        for rule_data in converted_rules:
            server.append('firewall_rules', rule_data)
        
        # 保存更新
        server.save(ignore_permissions=True)
        jingrow.db.commit()
        
        return {
            "success": True,
            "message": f"防火墙规则同步成功，共同步 {len(converted_rules)} 条规则",
            "rules_count": len(converted_rules),
            "server_name": server.name
        }
        
    except Exception as e:
        jingrow.log_error("同步防火墙规则失败", f"同步实例 {instance_id} 防火墙规则时发生错误: {str(e)}")
        return {"success": False, "error": str(e), "message": "同步防火墙规则失败"}

@jingrow.whitelist()
def get_jingrow_firewall_rules(**data):
    """获取防火墙规则（从本地数据库获取，支持分页）"""
    try:
        instance_id = data.get('instance_id')
        limit = data.get('limit', 10)
        pageno = data.get('pageno', 1)
        
        if not instance_id:
            return {"success": False, "message": "缺少实例ID参数"}
        
        # 查找对应的Jsite Server记录
        server_records = jingrow.get_all(
            "Jsite Server",
            {"instance_id": instance_id},
            ["name"]
        )
        
        if not server_records:
            return {"success": False, "message": "未找到指定的服务器记录"}
        
        server_record = server_records[0]
        
        # 获取该服务器的所有防火墙规则
        firewall_rules = jingrow.get_all(
            "Firewall Rules",
            {"parent": server_record.name},
            ["name", "rule_id", "rule_protocol", "port", "source_cidr_ip", "remark", "idx"],
            order_by="idx desc"
        )
        
        # 转换为API格式的数据结构
        all_items = []
        for rule in firewall_rules:
            item = {
                "rule_id": rule.rule_id or rule.name,
                "rule_protocol": rule.rule_protocol or "",
                "port": rule.port or "",
                "source_cidr_ip": rule.source_cidr_ip or "0.0.0.0/0",
                "remark": rule.remark or ""
            }
            all_items.append(item)
        
        # 数据已经按idx降序排列（最新添加的在前面），无需再次排序
        sorted_items = all_items
        
        # 计算分页
        total = len(sorted_items)
        pagecount = (total + limit - 1) // limit
        start_index = (pageno - 1) * limit
        end_index = start_index + limit
        
        # 返回当前页的记录
        current_page_items = sorted_items[start_index:end_index]
        
        # 返回格式化的防火墙规则信息
        return {
            "success": True,
            "data": {
                "pageno": pageno,
                "limit": limit,
                "total": total,
                "pagecount": pagecount,
                "firewall_rules": current_page_items
            }
        }
        
    except Exception as e:
        return {"success": False, "message": f"防火墙规则查询失败: {str(e)}"}

@jingrow.whitelist()
def execute_jsite_task(instance_id, mode='deploy', command_content=None, **kwargs):

    try:        
        # 获取服务器信息并验证
        server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id})
        if not server:
            return {"success": False, "message": "找不到对应的服务器记录"}
      
        region_id = server.region
        # 验证command_content参数
        if not command_content:
            return {"success": False, "message": "缺少command_content参数"}
        
        # 如果mode为deploy，开通3000/4000端口
        if mode == 'deploy':
            create_aliyun_firewall_rule(instance_id, 'TCP', '3000/4000', 'Jsite', region_id)
        
        # 执行命令，不传入参数字典
        manager = _get_manager()
        result = manager.run_command(instance_id, command_content, parameters=None, command_name=mode, region_id=region_id, timeout=3600)
        
        return result
        
    except Exception as e:
        jingrow.log_error("执行Jsite任务失败", f"实例 {instance_id}, 模式 {mode}, 错误: {str(e)}")
        return {"success": False, "message": f"执行Jsite任务失败: {str(e)}"}
