# -*- coding: utf-8 -*-

from pathlib import Path
from threading import Lock
import io
import os 
import re
import json
from cachetools import TTLCache
from hashlib import md5

from core.respone_format import *
from make_docx_demo.check_test_table.baidu_ocr import access_token
from tools.new_mysql import MySQLUploader
from tools.loglog import logger
from tools.thread_pool_manager import pool_executor

from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
import oss2
import nls
from oss2.credentials import EnvironmentVariableCredentialsProvider

Path("data/speech_data").mkdir(parents=True, exist_ok=True)


class TestTts:
    def __init__(self, token):
       
        self.appkey = "EwztMPbSeu5hTrss"
        self.token = token
        self.url = "wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1"

    def start(self, text, local_file_path):
        self.__text = text
        self.__f = open(local_file_path, "wb")
        self.__test_run()
       
       

    def test_on_metainfo(self, message, *args):
        print("on_metainfo message=>{}".format(message))

    def test_on_error(self, message, *args):
        print("on_error args=>{}".format(args))

    def test_on_close(self, *args):
        try:
            self.__f.close()
        except Exception as e:
            print("close file failed since:", e)

    def test_on_data(self, data, *args):
        try:
            self.__f.write(data)
        except Exception as e:
            print("write data failed:", e)

    def test_on_completed(self, message, *args):
        print("on_completed:args=>{} message=>{}".format(args, message))

    def __test_run(self):
        tts = nls.NlsSpeechSynthesizer(url=self.url,
                                       token=self.token,
                                       appkey=self.appkey,
                                      
                                       on_data=self.test_on_data,
                                      
                                       on_error=self.test_on_error,
                                       on_close=self.test_on_close,
                                       )
        tts.start(self.__text, voice="Eva", aformat="mp3", speech_rate=-400)


class GetAudio:
    def __init__(self):
        self.m = MySQLUploader()
        self.auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
        self.bucket_name = 'public-qingti-data'
        self.bucket = oss2.Bucket(self.auth, 'oss-cn-hangzhou.aliyuncs.com', self.bucket_name)

        self.token_cache = TTLCache(maxsize=10, ttl=28800) 
        self.token = None
        self.lock = Lock()
       
        self.re_compile = re.compile("[~.!?;*\"%]")

   
    def upload_file_to_oss(self, word_or_hash_name, oss_file_name, local_file_path):
        for _ in range(2):
            try:
                r = self.bucket.put_object_from_file(oss_file_name, local_file_path)
            except Exception as e:
                logger.error(f"上传文件错误{type(e).__name__} {e}")
                continue
            s = r.resp.status
            if s == 200:
                print(f"音频上传oss成功 {word_or_hash_name}")
                os.remove(local_file_path) 
                return True
        else:
            logger.critical(f"2次上传oss错误,音频:{word_or_hash_name}")

   
    def insert_mysql(self, word_or_hash_name,oss_file_name,original_text):
        s = "insert into tts (word_or_hash_name,audio,long_tts_text) values (%s,%s,%s)"
        self.m.execute_(s, (word_or_hash_name,oss_file_name,original_text))

   
    def query_mysql(self, word):
        s = "select audio from tts where word_or_hash_name=%s"
        r = self.m.query_data(s, (word,))
        if not r:
            return False
        return r[0][0]

    @staticmethod
    def __create_token():
       
        client = AcsClient(
            os.getenv('OSS_ACCESS_KEY_ID'),
            os.getenv('OSS_ACCESS_KEY_SECRET'),
            "cn-shanghai"
        )
       
        request = CommonRequest()
        request.set_method('POST')
        request.set_domain('nls-meta.cn-shanghai.aliyuncs.com')
        request.set_version('2019-02-28')
        request.set_action_name('CreateToken')

        try:
            response = client.do_action_with_exception(request)

            jss = json.loads(response)
            if 'Token' in jss and 'Id' in jss['Token']:
                token = jss['Token']['Id']
               
               
               
                logger.info(f"生成token成功。{token}")
                return token

        except Exception as e:
            logger.error(f"token生成错误：{type(e).__name__} {e}")

   
    def get_audio(self, word, local_file_path):
        self.lock.acquire()
        try:
            if "token" not in self.token_cache:
                self.token = self.__create_token()
                self.token_cache["token"] = self.token
        except Exception as e:
            logger.error(f"{type(e).__name__} {e}")
        finally:
            self.lock.release()

        t = TestTts(self.token)
        t.start(word, local_file_path)

   
    def submit_task(self, word_or_phrase:str,resp_type:int):
        f = pool_executor.submit(self.run_task, word_or_phrase,resp_type)
        return f

   
    def __preprocess_data(self,text: str) -> tuple:
        """
        预处理数据。超过50个字符的所有名字都用哈希值。
        :param text: 预处理文本内容
        :return:
        """
        text = self.re_compile.sub(" ",text.strip()) 
        if len(text) > 30 or " " in text: 
            hash_str = md5(text.encode()).hexdigest()
            return text, hash_str
        return text,text

   
    def __resp_convert(self,oss_file_name,resp_type):
        """
        :param oss_file_name: OSS全路径；"baseData/audio/{word_or_hash_name}.mp3"
        :param resp_type: 回复格式设计：0返回oss路径，1 二进制文件，2 url三种；
        :return:
        """
        if resp_type == 0:
            logger.success(f"返回成功:oss路径{oss_file_name}")
            return oss_file_name
        elif resp_type == 1:
            try:
               
                obj = self.bucket.get_object(oss_file_name)
               
                content = io.BytesIO(obj.read())
                logger.success(f"返回成功:二进制数据{oss_file_name}")
                return content
            except Exception as e:
                raise resp_500(message=f"错误:转换二进制文件 {e}")
        elif resp_type == 2:
           

            mp3_file_url = f"https://{self.bucket_name}.oss-cn-hangzhou.aliyuncs.com/{oss_file_name}"
            logger.success(f"返回成功:https的url {mp3_file_url}")
            return mp3_file_url


   
    def run_task(self, word_or_phrase,resp_type):
        """
        :param word_or_phrase: 单词或短语文本，去生成tts的文本
        :param resp_type: 回复设计：0返回oss路径，1 二进制文件，2 url三种；
        :return:
        """
       
        original_text,word_or_hash_name = self.__preprocess_data(word_or_phrase)
        oss_file_name = f"baseData/audio/{word_or_hash_name}.mp3"
        local_file_path = f"data/speech_data/{word_or_hash_name}.mp3"

       
        query_word_mp3_path = self.query_mysql(word_or_hash_name)
        if query_word_mp3_path:
            resp_convertt = self.__resp_convert(oss_file_name=query_word_mp3_path,resp_type=resp_type)
            return resp_convertt

       
        self.get_audio(original_text, local_file_path)

       
        upload_result = self.upload_file_to_oss(word_or_hash_name, oss_file_name, local_file_path)
        if upload_result:
            self.insert_mysql(word_or_hash_name,oss_file_name,original_text)
            resp_convertt = self.__resp_convert(oss_file_name=oss_file_name, resp_type=resp_type)
            return resp_convertt

       
        return False


if __name__ == '__main__':
   
   

    import os

    os.chdir('..')
   
   
   
   

    g = GetAudio()
    article="""i'm Bob ,The Marches were a happy family. Poverty, hard work, and even the fact that Father March was away with the Union armies could not down the spirits of Meg, Jo, Amy, and Marmee, as the March girls called their mother. The March sisters tried to be good but had their share of faults. Pretty Meg was often displeased with the schoolchildren she taught; boyish Jo was easy to become angry; golden-haired schoolgirl Amy liked to show up; but Beth, who kept the house, was loving and gentle always. The happy days passed and darkness came when a telegram arrived for Mrs. March. "Your husband is very ill," it said, "come at once." The girl tried to be brave when their mother left for the front. They waited and prayed. Little Beth got scarlet fever when she was taking care of the sick neighbor. She became very ill but began to recover by the time Marmee was back. When Father came home from the front and at that joyful Christmas dinner they were once more all together. Three years later, the March girls had grown into young womanhood. Meg became Mrs. Brooke, and after a few family troubles got used to her new state happily. Jo had found pleasure in her literary efforts. Amy had grown into a young lady with a talent for design and an even greater one for society. But Beth had never fully regained her health, and her family watched her with love and anxiety. Amy was asked to go and stay in Europe with a relative of the Marches. Jo went to New York and became successful in her writing and had the satisfaction of seeing her work published there. But at home the bitterest blow was yet to fall. Beth had known for some time that she couldn't live much longer to be with the family and in the spring time she died. News came from Europe that Amy and Laurie, the grandson of a wealthy neighbor, had planned to be married soon. Now Jo became ever more successful in her writing and got married to Professor Bhaer and soon afterwards founded a school for boys. And so the little women had grown up and lived happily with their children, enjoying the harvest of love and goodness that they had devoted all their lives to."""
    g.get_audio(article, "1.mp3")

