import time
import json
import requests
import re
import httpx
import hashlib
import uuid

class Translation():
    def __init__(self, app_key, app_secret):
        """
        Translate Function
        """
        import sys
        from importlib import reload
        reload(sys)

        self.YOUDAO_URL = 'https://openapi.youdao.com/api'
        self.APP_KEY = app_key
        self.APP_SECRET = app_secret

    def encrypt(self, signStr):
        hash_algorithm = hashlib.sha256()
        hash_algorithm.update(signStr.encode('utf-8'))
        return hash_algorithm.hexdigest()

    def truncate(self, q):
        if q is None:
            return None
        size = len(q)
        return q if size <= 20 else q[0:10] + str(size) + q[size - 10:size]

    def do_request(self, data):
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        return requests.post(self.YOUDAO_URL, data=data, headers=headers)

    async def do_request_async(self, data):
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        async with httpx.AsyncClient(headers=headers) as client:
            result = await client.post(self.YOUDAO_URL, data=data)
        return result

    def trans(self, from_language, content, useby='p'):
        """
        from_language : ja = japan; en = english;
        if useby = 'p' => filter bracket content
        """
        import uuid

        if useby == 'p':
            pattern = '\(.*?\)|（.*?）|\[.*?\]'
            content = re.sub(pattern, '', content, 0)

        if content.endswith('\\') or content.endswith("'"):
            content = content[:-1]

        data = {}
        data['from'] = from_language
        data['to'] = 'zh-CHS'
        data['signType'] = 'v3'
        curtime = str(int(time.time()))
        data['curtime'] = curtime
        salt = str(uuid.uuid1())
        signStr = self.APP_KEY + self.truncate(content) + salt + curtime + self.APP_SECRET
        sign = self.encrypt(signStr)
        data['appKey'] = self.APP_KEY
        data['q'] = content
        data['salt'] = salt
        data['sign'] = sign
        #data['vocabId'] = "您的用户词表ID"

        response = self.do_request(data)
        #contentType = response.headers['Content-Type']
        result = json.loads(response.content.decode())

        if result['errorCode'] == '0':
            return result['translation'][0]
        else:
            errorcode = result['errorCode']
            print(f'Translation wrong Error Code : {errorcode} \n Retring...')

            response = self.do_request(data)
            result = json.loads(response.content.decode())

            if result['errorCode'] == '0':
                return result['translation'][0]
            else:
                errorcode = result['errorCode']
                return f'Translation wrong Error Code : {errorcode}'

    async def trans_async(self, from_language, content, useby='p'):
        """
        from_language : ja = japan; en = english;
        if useby = 'p' => filter bracket content
        """
        if useby == 'p':
            pattern = '\(.*?\)|（.*?）|\[.*?\]'
            content = re.sub(pattern, '', content, 0)

        if content.endswith('\\') or content.endswith("'"):
            content = content[:-1]

        data = {}
        data['from'] = from_language
        data['to'] = 'zh-CHS'
        data['signType'] = 'v3'
        curtime = str(int(time.time()))
        data['curtime'] = curtime
        salt = str(uuid.uuid1())
        signStr = self.APP_KEY + self.truncate(content) + salt + curtime + self.APP_SECRET
        sign = self.encrypt(signStr)
        data['appKey'] = self.APP_KEY
        data['q'] = content
        data['salt'] = salt
        data['sign'] = sign
        #data['vocabId'] = "您的用户词表ID"

        response = await self.do_request_async(data)
        #contentType = response.headers['Content-Type']
        result = json.loads(response.content.decode())

        if result['errorCode'] == '0':
            return result['translation'][0]
        else:
            errorcode = result['errorCode']
            print(f'Translation wrong Error Code : {errorcode} \n Retring...')

            response = await self.do_request_async(data)
            result = json.loads(response.content.decode())

            if result['errorCode'] == '0':
                return result['translation'][0]
            else:
                errorcode = result['errorCode']
                return f'Translation wrong Error Code : {errorcode}'

class Translation_AI():
    """ 
    大模型翻译类 - 使用有道大模型 API
    """
    def __init__(self, app_key, app_secret):
        """
        翻译类 - 使用有道大模型 API

        :param app_key: 应用ID (可选，若不传则使用默认硬编码值)
        :param app_secret: 应用密钥 (可选，若不传则使用默认硬编码值)
        """
        # 保留你原有的硬编码密钥（也可通过参数覆盖）
        self.APP_KEY = app_key
        self.APP_SECRET = app_secret
        self.API_URL = "https://openapi.youdao.com/proxy/http/llm-trans"

    def _generate_sign(self, text, salt, curtime):
        """生成签名（与大模型API要求一致）"""
        # 根据规则生成 input
        if len(text) <= 20:
            input_text = text
        else:
            input_text = text[:10] + str(len(text)) + text[-10:]

        sign_str = self.APP_KEY + input_text + salt + curtime + self.APP_SECRET
        return hashlib.sha256(sign_str.encode("utf-8")).hexdigest()

    def _preprocess_content(self, content, useby='p'):
        """
        预处理文本：过滤括号、处理结尾字符
        保持你原有的逻辑
        """
        if useby == 'p':
            pattern = '\(.*?\)|（.*?）|\[.*?\]'
            content = re.sub(pattern, '', content, 0)

        if content.endswith('\\') or content.endswith("'"):
            content = content[:-1]
        return content

    def _get_full_translation(self, text, from_lang, to_lang='zh-CHS', prompt=None):
        """
        调用大模型 API 获取完整翻译（非流式返回最终结果）
        内部使用流式请求并收集最后一个全量翻译
        """
        salt = str(uuid.uuid4())
        curtime = str(int(time.time()))
        sign = self._generate_sign(text, salt, curtime)

        data = {
            "appKey": self.APP_KEY,
            "salt": salt,
            "signType": "v3",
            "sign": sign,
            "curtime": curtime,
            "i": text,               # 注意：大模型API参数名为 i，不是 q
            "from": from_lang,
            "to": to_lang,
            "streamType": "full",    # 全量返回，每次事件都包含完整译文
        }
        if prompt:
            data["prompt"] = prompt

        response = requests.post(
            self.API_URL,
            data=data,
            headers={"Content-Type": "application/x-www-form-urlencoded"},
            stream=True
        )

        if response.status_code != 200:
            raise Exception(f"大模型API请求失败，状态码: {response.status_code}")

        full_translation = None
        for line in response.iter_lines(decode_unicode=True):
            if not line:
                continue
            # 大模型API返回 SSE 格式：event:xxx 或 data:xxx
            if line.startswith("data:"):
                json_str = line[5:].lstrip()  # 移除 'data:' 前缀
                try:
                    result = json.loads(json_str)
                    if result.get("successful", False):
                        data_field = result.get("data", {})
                        # streamType='full' 时，transFull 字段包含当前完整翻译
                        trans_full = data_field.get("transFull")
                        if trans_full:
                            full_translation = trans_full
                    else:
                        # 出错时，可以抛出或记录
                        error_code = result.get("code")
                        error_msg = result.get("message")
                        raise Exception(f"翻译错误 [{error_code}]: {error_msg}")
                except json.JSONDecodeError:
                    continue

        if full_translation is None:
            raise Exception("未能从大模型API获取有效翻译结果")
        return full_translation

    async def _get_full_translation_async(self, text, from_lang, to_lang='zh-CHS', prompt=None):
        """异步版本：使用 httpx 流式请求获取完整翻译"""
        salt = str(uuid.uuid4())
        curtime = str(int(time.time()))
        sign = self._generate_sign(text, salt, curtime)

        data = {
            "appKey": self.APP_KEY,
            "salt": salt,
            "signType": "v3",
            "sign": sign,
            "curtime": curtime,
            "i": text,
            "from": from_lang,
            "to": to_lang,
            "streamType": "full",
        }
        if prompt:
            data["prompt"] = prompt

        async with httpx.AsyncClient() as client:
            async with client.stream(
                "POST",
                self.API_URL,
                data=data,
                headers={"Content-Type": "application/x-www-form-urlencoded"}
            ) as response:
                if response.status_code != 200:
                    raise Exception(f"大模型API请求失败，状态码: {response.status_code}")

                full_translation = None
                async for line in response.aiter_lines():
                    if not line:
                        continue
                    if line.startswith("data:"):
                        json_str = line[5:].lstrip()
                        try:
                            result = json.loads(json_str)
                            if result.get("successful", False):
                                trans_full = result.get("data", {}).get("transFull")
                                if trans_full:
                                    full_translation = trans_full
                            else:
                                error_code = result.get("code")
                                error_msg = result.get("message")
                                raise Exception(f"翻译错误 [{error_code}]: {error_msg}")
                        except json.JSONDecodeError:
                            continue

                if full_translation is None:
                    raise Exception("未能从大模型API获取有效翻译结果")
                return full_translation

    # ------------------ 对外公开方法 ------------------
    def trans(self, from_language, content, useby='p', prompt=None):
        """
        同步翻译方法

        :param from_language: 源语言 (例如 'ja', 'en', 'auto')
        :param content: 待翻译文本
        :param useby: 若为 'p' 则过滤括号内容
        :param prompt: 可选，自定义提示词
        :return: 翻译后的字符串
        """
        # 预处理
        content = self._preprocess_content(content, useby)

        # 调用大模型API获取翻译
        try:
            result = self._get_full_translation(content, from_language, prompt=prompt)
            return result
        except Exception as e:
            # 保留你原有的重试逻辑（一次重试）
            print(f'Translation wrong Error: {e} \n Retrying...')
            try:
                result = self._get_full_translation(content, from_language, prompt=prompt)
                return result
            except Exception as e2:
                return f'Translation wrong Error: {e2}'

    async def trans_async(self, from_language, content, useby='p', prompt=None):
        """
        异步翻译方法

        :param from_language: 源语言 (例如 'ja', 'en', 'auto')
        :param content: 待翻译文本
        :param useby: 若为 'p' 则过滤括号内容
        :param prompt: 可选，自定义提示词
        :return: 翻译后的字符串
        """
        content = self._preprocess_content(content, useby)

        try:
            result = await self._get_full_translation_async(content, from_language, prompt=prompt)
            return result
        except Exception as e:
            print(f'Translation wrong Error: {e} \n Retrying...')
            try:
                result = await self._get_full_translation_async(content, from_language, prompt=prompt)
                return result
            except Exception as e2:
                return f'Translation wrong Error: {e2}'

