"""
_on_open
{'action': 'started', 'data': '', 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'}
{'action': 'result', 'data': {'sub': 'iat', 'auth_id': '473c6d01e01d5105499d83b7d293c4bd', 'text': {'bg': 0, 'ed': 0, 'ls': False, 'pgs': 'apd', 'sn': 1, 'ws': [{'bg': 0, 'cw': [{'sc': 0, 'w': '今天'}]}, {'bg': 0, 'cw': [{'sc': 0, 'w': '天气'}]}]}, 'result_id': 1, 'is_last': False, 'is_finish': False, 'json_args': {'language': 'zh-cn', 'accent': 'mandarin'}}, 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'}
{'code': '0', 'sub': 'iat', 'is_last': False, 'is_finish': False, 'pgs': 'apd', 'service': 'raw', 'rawText': '今天天气'}
{'action': 'result', 'data': {'sub': 'iat', 'auth_id': '473c6d01e01d5105499d83b7d293c4bd', 'text': {'bg': 0, 'ed': 0, 'ls': False, 'pgs': 'rpl', 'rg': [1, 1], 'sn': 2, 'ws': [{'bg': 0, 'cw': [{'sc': 0, 'w': '今天'}]}, {'bg': 0, 'cw': [{'sc': 0, 'w': '天气'}]}, {'bg': 0, 'cw': [{'sc': 0, 'w': '怎么样'}]}]}, 'result_id': 2, 'is_last': False, 'is_finish': False, 'json_args': {'language': 'zh-cn', 'accent': 'mandarin'}}, 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'}
{'code': '0', 'sub': 'iat', 'is_last': False, 'is_finish': False, 'pgs': 'rpl', 'service': 'raw', 'rawText': '今天天气怎么样'}
{'action': 'result', 'data': {'sub': 'iat', 'auth_id': '473c6d01e01d5105499d83b7d293c4bd', 'text': {'bg': 0, 'ed': 0, 'ls': False, 'pgs': 'rpl', 'rg': [1, 2], 'sn': 3, 'ws': [{'bg': 0, 'cw': [{'sc': 0, 'w': '今天'}]}, {'bg': 0, 'cw': [{'sc': 0, 'w': '天气'}]}, {'bg': 0, 'cw': [{'sc': 0, 'w': '怎么样'}]}]}, 'result_id': 3, 'is_last': False, 'is_finish': False, 'json_args': {'language': 'zh-cn', 'accent': 'mandarin'}}, 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'}
{'code': '0', 'sub': 'iat', 'is_last': False, 'is_finish': False, 'pgs': 'rpl', 'service': 'raw', 'rawText': '今天天气怎么样'}
{'action': 'result', 'data': {'sub': 'iat', 'auth_id': '473c6d01e01d5105499d83b7d293c4bd', 'text': {'bg': 0, 'ed': 0, 'ls': False, 'pgs': 'apd', 'sn': 4, 'ws': [{'bg': 0, 'cw': [{'sc': 0, 'w': ''}]}]}, 'result_id': 4, 'is_last': False, 'is_finish': False, 'json_args': {'language': 'zh-cn', 'accent': 'mandarin'}}, 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'}
{'code': '0', 'sub': 'iat', 'is_last': False, 'is_finish': False, 'pgs': 'apd', 'service': 'raw', 'rawText': ''}
{'action': 'result', 'data': {'sub': 'iat', 'auth_id': '473c6d01e01d5105499d83b7d293c4bd', 'text': {'bg': 0, 'ed': 0, 'ls': True, 'pgs': 'rpl', 'rg': [4, 4], 'sn': 5, 'ws': [{'bg': 0, 'cw': [{'sc': 0, 'w': '？'}]}]}, 'result_id': 5, 'is_last': True, 'is_finish': False, 'json_args': {'language': 'zh-cn', 'accent': 'mandarin'}}, 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'}
{'code': '0', 'sub': 'iat', 'is_last': True, 'is_finish': False, 'pgs': 'rpl', 'service': 'raw', 'rawText': '？'}
{'action': 'result', 'data': {'sub': 'nlp', 'auth_id': '473c6d01e01d5105499d83b7d293c4bd', 'intent': {'answer': {'text': '我昨天忘记看天气预报了', 'type': 'T'}, 'category': 'IFLYTEK.weather', 'data': {'error': {'code': 0, 'message': ''}, 'result': []}, 'dialog_stat': 'DataValid', 'rc': 3, 'save_history': True, 'semantic': [{'intent': 'QUERY', 'slots': [{'name': 'datetime', 'normValue': '{"datetime":"2023-11-28","suggestDatetime":"2023-11-28"}', 'value': '今天'}, {'name': 'location.city', 'normValue': 'CURRENT_CITY', 'value': 'CURRENT_CITY'}, {'name': 'location.poi', 'normValue': 'CURRENT_POI', 'value': 'CURRENT_POI'}, {'name': 'location.type', 'normValue': 'LOC_POI', 'value': 'LOC_POI'}, {'name': 'queryType', 'value': '内容'}, {'name': 'subfocus', 'value': '天气状态'}]}], 'service': 'weather', 'shouldEndSession': 'true', 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'state': {'fg::weather::default::default': {'state': 'default'}}, 'text': '今天天气怎么样？', 'uuid': 'awa027d6d87@dx000118c0e4f8a15800', 'version': '173.0'}, 'result_id': 1, 'is_last': True, 'is_finish': True}, 'sid': 'awa027d6d87@dx000118c0e4f8a15800', 'code': '0', 'desc': 'success'}
{'code': '0', 'sub': 'nlp', 'is_last': True, 'is_finish': True, 'service': 'weather', 'rawText': '今天天气怎么样？'}
_on_error
1
_on_error
1
_on_close
"""
from PyQt5.QtCore import QObject, QUrl, pyqtSignal
from PyQt5.QtWebSockets import QWebSocket, QWebSocketProtocol
import base64
import hashlib
import json
import time
import uuid
from util import my_util, constants

ORIGIN = "http://wsapi.xfyun.cn"
BASE_URL = "ws://wsapi.xfyun.cn/v1/aiui"
# BASE_URL = "wss://wsapi.xfyun.cn/v1/aiui"

# 结束标识
END_TAG = "--end--"


def get_auth_id():
    mac = uuid.UUID(int=uuid.getnode()).hex[-12:]
    return hashlib.md5(":".join([mac[e:e + 2] for e in range(0, 11, 2)]).encode("utf-8")).hexdigest()


class AiuiManager(QObject):
    trigger = pyqtSignal(dict)

    _app_id = "ab154863"
    _api_key = "5a584b63730d3450d64cdd65f17f56d0"

    def __init__(self):
        super(AiuiManager, self).__init__()
        self._last_status = 0
        self._last_raw_text = ""
        self._last_pgs = None
        self._param = {"result_level": "complete", "auth_id": get_auth_id(), "data_type": "audio",
                       "aue": "raw", "scene": "main", "sample_rate": "16000", "cloud_vad_eos": "60000"}
        self.ws = None

    def regist_engine(self, aue="raw"):
        self.update_params({"aue": aue})

    def update_params(self, params):
        if params:
            self._param.update(params)

    def start_speech(self):
        print("start_speech 1")
        # try:
        #     self.ws.close()
        # except:
        #     pass
        self.ws = QWebSocket(origin=ORIGIN, version=QWebSocketProtocol.VersionLatest)
        # 信号连接
        self.ws.connected.connect(self._on_open)
        self.ws.error.connect(self._on_error)
        self.ws.disconnected.connect(self._on_close)
        self.ws.textMessageReceived.connect(self._on_message)
        self._create_url()
        self.ws.open(QUrl(f"{self.ws_url}"))
        print("start_speech 2")

    def _callback(self, data: dict):
        self.trigger.emit(data)

    def _create_url(self):
        _param_b64 = base64.b64encode(json.dumps(self._param).encode('utf-8'))
        _cur_time = str(int(time.time()))
        _tmp = self._api_key + _cur_time + _param_b64.decode()
        _md5 = hashlib.md5()
        _md5.update(_tmp.encode(encoding='utf-8'))
        check_sum = _md5.hexdigest()
        self.ws_url = BASE_URL + "?appid=" + self._app_id + "&checksum=" + check_sum + "&curtime=" + _cur_time + "&param=" + _param_b64.decode()

    # 连接建立时
    def _on_open(self):
        print('_on_open')
        pass

    # 连接异常时
    def _on_error(self, error_code):
        print('_on_error')
        print(error_code)
        # self.ws.close()
        # self._callback(my_util.gen_q_data(constants.AITEST_AIUI_ERROR, self.ws.errorString()))
        pass

    # 接收到文本消息时
    def _on_message(self, message):
        data = json.loads(str(message))
        print(data)
        _action = data["action"]
        self._sid = data["sid"]
        if _action == "started":  # 正常连接
            d = f"连接已建立,sid:{self._sid}"
            self._callback(my_util.gen_q_data(constants.AITEST_AIUI_LOG, d))
            self._callback(my_util.gen_q_data(constants.AITEST_AIUI_START, True))
        elif _action == "result":
            _data = my_util.parse_aiui_v2_result(data)
            print(_data)
            # text = self.parse_aiui_engine_stream_result(_data)
            # if text:
            #     self._callback(my_util.gen_q_data(constants.AITEST_AIUI_RESULT, text))
            if _data.get("is_finish"):
                self._callback(
                    my_util.gen_q_data(constants.AITEST_AIUI_NLP, json.dumps(data["data"], ensure_ascii=False)))
                self._callback(my_util.gen_q_data(constants.AITEST_AIUI_RESULT, _data["rawText"]))
        else:
            self._callback(my_util.gen_q_data(constants.AITEST_AIUI_ERROR, data))

    # 连接断开时
    def _on_close(self):
        print('_on_close')
        d = f"连接已断开！,sid:{self._sid}"
        self._callback(my_util.gen_q_data(constants.AITEST_AIUI_LOG, d))

    def audio_write(self, buf: bytes):
        if self.ws:
            self.ws.sendBinaryMessage(buf)

    def stop_speech(self):
        if self.ws:
            d = f"sid:{self._sid},发送结束标识！！！"
            self._callback(my_util.gen_q_data(constants.AITEST_AIUI_LOG, d))
            self.ws.sendBinaryMessage(bytes(END_TAG.encode("utf-8")))

    def parse_aiui_engine_stream_result(self, data: dict):
        sub = data.get("sub")
        if sub != "iat":
            return ""
        raw_text = data.get("rawText")
        is_last = data.get("is_last")
        last_text = data.get("last_text")
        pgs = data.get("pgs")
        status = 0
        if pgs == "apd":
            if my_util.symbol_in_word(raw_text):
                status = 1
                if not self._last_status:  # 短句
                    text = self._last_raw_text + raw_text
                else:
                    text = raw_text
            elif self._last_pgs == "rpl" and not self._last_status:
                status = 1
                text = self._last_raw_text
            else:
                status = 0
                text = raw_text
        else:
            if my_util.symbol_in_word(raw_text):
                status = 1
                text = raw_text
            else:
                status = 0
                text = raw_text
        self._last_status = status
        self._last_pgs = pgs
        self._last_raw_text = text
        if status == 1:
            _text = text
        else:
            _text = ""
        return _text
