import time
import urllib.request
import urllib.error
import json
import ssl
from functools import wraps

from .config import ADAM_API_HOST, ADAM_API_TOKEN, ADAM_TASK_ID


def retry_on_exception(max_retries=3, delay=5):
    """
    重试装饰器，在发生异常时最多重试指定次数

    Args:
        max_retries: 最大重试次数
        delay: 重试间隔时间（秒）
    """
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            last_exception = None
            for attempt in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    last_exception = e
                    if attempt < max_retries - 1:
                        time.sleep(delay)
                        continue
                    raise last_exception
            return None
        return wrapper
    return decorator


def _make_http_request(url, data, return_json=True):
    """
    通用的 HTTP POST 请求函数

    Args:
        url: 请求的 URL
        data: 请求数据（字典格式）
        return_json: 是否将响应解析为 JSON，False 则返回文本

    Returns:
        响应数据（JSON 或文本）
    """
    if not ADAM_API_TOKEN:
        raise ValueError("ADAM_API_TOKEN environment variable is not set")

    headers = {
        "Authorization": f"Bearer {ADAM_API_TOKEN}",
        "Content-Type": "application/json"
    }

    try:
        # 将请求数据转换为JSON字符串并编码
        json_data = json.dumps(data).encode('utf-8')

        # 创建请求对象
        req = urllib.request.Request(url, data=json_data, headers=headers, method='POST')

        context = ssl._create_unverified_context()

        # 发送请求
        with urllib.request.urlopen(req, context=context) as response:
            # 检查响应状态码
            if response.status >= 400:
                raise Exception(f"HTTP错误: {response.status}")

            # 读取响应
            response_data = response.read().decode('utf-8')

            # 根据需要返回 JSON 或文本
            if return_json:
                return json.loads(response_data)
            else:
                return response_data

    except urllib.error.HTTPError as e:
        raise Exception(f"HTTP请求失败 - HTTP错误 {e.code}: {e.reason}")
    except urllib.error.URLError as e:
        raise Exception(f"HTTP请求失败 - 网络错误: {str(e)}")
    except json.JSONDecodeError as e:
        if return_json:
            raise Exception(f"HTTP请求失败 - JSON解析错误: {str(e)}")
        else:
            raise Exception(f"HTTP请求失败 - 响应解码错误: {str(e)}")
    except Exception as e:
        raise Exception(f"HTTP请求失败: {str(e)}")


def messageSend(message):
    """
    发送消息给用户
    """
    if not ADAM_API_HOST:
        raise ValueError("ADAM_API_HOST environment variable is not set")
    if not ADAM_TASK_ID:
        raise ValueError("ADAM_TASK_ID environment variable is not set")

    url = f"{ADAM_API_HOST}/api/task/create_message"

    request_data = {
        "task_id": ADAM_TASK_ID,
        "message": message,
        "role": "tool"
    }

    try:
        return _make_http_request(url, request_data, return_json=True)
    except Exception as e:
        raise Exception(f"发送消息失败: {str(e)}")


class DynamicObject:
    """
    动态对象类，用于处理 JSON 响应

    这个类可以动态地将字典转换为对象属性，支持嵌套的字典结构
    同时保持原始数据的访问能力
    """
    def __init__(self, data):
        self._raw_data = data
        if isinstance(data, dict):
            for key, value in data.items():
                if isinstance(value, (dict, list)):
                    setattr(self, key, self._convert_value(value))
                else:
                    setattr(self, key, value)

    def _convert_value(self, value):
        """递归转换嵌套的数据结构"""
        if isinstance(value, dict):
            return DynamicObject(value)
        elif isinstance(value, list):
            return [self._convert_value(item) for item in value]
        return value

    def __getattr__(self, name):
        """处理未定义的属性访问"""
        return self._raw_data.get(name)

    def __getitem__(self, key):
        """支持字典式访问"""
        return self._raw_data.get(key)

    def __str__(self):
        """返回可读的字符串表示"""
        return f"DynamicObject({self._raw_data})"

    def __repr__(self):
        return self.__str__()

    def to_dict(self):
        """将对象转换回字典"""
        return self._raw_data


@retry_on_exception(max_retries=3)
def completionCreate(request_params):
    """
    创建 openai 的代理函数

    Returns:
        DynamicObject: 一个动态对象，可以像访问属性一样访问 API 响应的所有字段
    """
    if not ADAM_API_HOST:
        raise ValueError("ADAM_API_HOST environment variable is not set")

    url = f"{ADAM_API_HOST}/api/chat/completions"

    try:
        response = _make_http_request(url, request_params, return_json=True)
        return DynamicObject(response)
    except Exception as e:
        raise Exception(f"调用聊天补全接口失败: {str(e)}")
