from io import BytesIO
from typing import Any, Coroutine

from fastapi import Request, Response, status
from fastapi.responses import JSONResponse

from ..asr.rapid_paraformer.utils import read_yaml
from ..asr.rapid_paraformer import RapidParaformer

from funasr import AutoModel
from funasr.utils.postprocess_utils import rich_transcription_postprocess
from .blackbox import Blackbox
from injector import singleton, inject

from pathlib import Path
from ..configuration import PathConf

import tempfile

import json
import os
import opencc
import base64

from ..configuration import SenseVoiceConf

from ..log.logging_time import logging_time
import logging
logger = logging.getLogger(__name__)

converter = opencc.OpenCC('s2t.json')

def is_base64(value) -> bool:
    try:
        base64.b64decode(base64.b64decode(value)) == value.encode()
        return True
    except Exception:
        return False
        
@singleton
class ASR(Blackbox):
    mode: str
    url: str
    speed: int
    device: str
    language: str
    speaker: str

    @logging_time(logger=logger)
    def model_init(self, sensevoice_config: SenseVoiceConf, path: PathConf) -> None:

        config = read_yaml(".env.yaml")
        self.paraformer = RapidParaformer(config)
        sense_model_path = Path(path.sensevoice_model_path)

        model_dir = str(sense_model_path)

        self.speed = sensevoice_config.speed
        self.device = sensevoice_config.device
        self.language = sensevoice_config.language
        self.speaker = sensevoice_config.speaker
        self.device = sensevoice_config.device
        self.url = ''
        self.mode = sensevoice_config.mode
        self.asr = None
        self.speaker_ids = None
        # os.environ['CUDA_VISIBLE_DEVICES'] = str(sensevoice_config.device)
        if self.mode == 'local':
            self.asr = AutoModel(
            model=model_dir,
            trust_remote_code=True,
            remote_code= "../SenseVoice/model.py",
            vad_model="fsmn-vad",
            vad_kwargs={"max_single_segment_time": 30000},
            device=self.device,
        )   
            
        else:
            self.url = sensevoice_config.url
        logging.info('#### Initializing SenseVoiceASR Service in cuda:' + sensevoice_config.device + ' mode...')

    @inject
    def __init__(self, sensevoice_config: SenseVoiceConf, settings: dict, path: PathConf) -> None:
        self.model_init(sensevoice_config, path)
 
    def __call__(self, *args, **kwargs):
        return self.processing(*args, **kwargs)
    
    async def processing(self,  *args, settings: dict):

        print("\nChat Settings: ", settings)
        if settings is None:
            settings = {}
        user_model_name = settings.get("asr_model_name")
        print(f"asr_model_name: {user_model_name}")
        data = args[0]

        if 'sensevoice' in user_model_name:
            with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as temp_audio_file:
                temp_audio_file.write(data)
                temp_audio_path = temp_audio_file.name
            res = self.asr.generate(
                input=temp_audio_path,
                cache={},
                language="auto",  # "zh", "en", "yue", "ja", "ko", "nospeech"
                use_itn=True,
                batch_size_s=60,
                merge_vad=True,  #
                merge_length_s=15,
            )        
            # results = self.paraformer([BytesIO(data)])
            results = rich_transcription_postprocess(res[0]["text"])
            os.remove(temp_audio_path)
            if len(results) == 0:
                return None
            results = converter.convert(results)
            return results
        
        elif 'funasr' in user_model_name:
            results = converter.convert(results)
            return results
        
        else:
            results = self.paraformer([BytesIO(data)])
            if len(results) == 0:
                return None
            results = converter.convert(results[0])
            return results      

    def valid(self, data: any) -> bool:
        if isinstance(data, bytes):
            return True
        return False
    
    async def fast_api_handler(self, request: Request) -> Response:

        try:
            content_type = request.headers['content-type']
            if content_type == 'application/json':
                data = await request.json()
                setting: dict = (await request.json()).get("settings")
            else:
                data = await request.form()
                setting: dict = (await request.form()).get("settings")
        except Exception as e:
            return JSONResponse(content={"error": "json parse error"}, status_code=status.HTTP_400_BAD_REQUEST)
              
        data = data.get("audio")
        print(f'type: {type(data)}')
        print('='*90)
        print(data)
        print('='*90)
        
        if isinstance(setting, str):
            try:
                setting = json.loads(setting)  #str covert to dict
            except json.JSONDecodeError:
                return JSONResponse(content={"error": "Invalid settings format"}, status_code=status.HTTP_400_BAD_REQUEST)
        
        if data is None:
            # self.logger.warn("asr bag request","type", "fast_api_handler", "api", "asr")
            return JSONResponse(content={"error": "data is required"}, status_code=status.HTTP_400_BAD_REQUEST)

        # 如果数据是Base64编码的字符串，需要先解码为字节数据
        if isinstance(data, str):
            try:
                d = base64.b64decode(data)  # Base64解码为字节数据
            except base64.binascii.Error:
                return JSONResponse(content={"error": "Invalid base64 encoding"}, status_code=status.HTTP_400_BAD_REQUEST)
        else:
            d = await data.read()
        try:
            txt = await self.processing(d, settings=setting)
        except ValueError as e:
            return JSONResponse(content={"error": str(e)}, status_code=status.HTTP_400_BAD_REQUEST)
        return JSONResponse(content={"text": txt}, status_code=status.HTTP_200_OK)