package com.sonic.cow.client.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import com.sonic.cow.client.AsrV2Client;
import com.sonic.cow.client.config.AsrConfig;
import com.sonic.cow.domain.input.VoiceAsrInput;
import com.sonic.cow.domain.output.AsrOutput;
import com.sonic.cow.enums.ToastResultCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Slf4j
@Service
public class AsrV2ClientImpl implements AsrV2Client {

    @Autowired
    private AsrConfig asrConfig;

    /**
     * 提交地址
     */
    private static final String submitUrl = "https://voice.ap-southeast-1.bytepluses.com/api/v3/auc/bigmodel/submit";
    /**
     * 查询地址
     */
    private static final String queryUrl = "https://voice.ap-southeast-1.bytepluses.com/api/v3/auc/bigmodel/query";
    /**
     * 资源ID
     */
    private static final String resourceId = "volc.bigasr.auc";
    /**
     * 状态码
     */
    private static final String X_API_STATUS_CODE = "X-Api-Status-Code";


    @Override
    public AsrOutput asr(String userId, VoiceAsrInput input) throws UnirestException, InterruptedException {
        //TODO 判断url的格式是否有效（host是否有效），判断是否是用户自己的

        String taskId = UUID.randomUUID().toString();
        //STEP1: 创建语音识别任务
        String xttLogId = submitTask(userId, taskId, input.getUrl());
        //没有创建成功，直接抛出异常
        ToastResultCode.SOUND_ASR_ERROR.check(StringUtils.isEmpty(xttLogId));
        int count = 0;
        //STEP2 获取结果
        while (true) {
            //记录处理次数，处理次数达到35次，也就是10s都没有结果返回的话那么久不再继续处理了
            if(count > 35) {
                break;
            }
            HttpResponse<String> queryResponse = queryTask(taskId, xttLogId);
            String code = queryResponse.getHeaders().getFirst(X_API_STATUS_CODE);
            if ("20000000".equals(code)) {
                JSONObject jsonObject = JSONObject.parseObject(queryResponse.getBody());
                log.info("=======> asr jsonObject:{}", JSONObject.toJSONString(jsonObject));
                JSONObject result = jsonObject.getJSONObject("result");
                JSONArray utterances = result.getJSONArray("utterances");
                JSONObject firstUtterance = utterances.getJSONObject(0);
                String text = firstUtterance.getString("text");
                return AsrOutput.builder()
                        .content(text)
                        .duration(jsonObject.getJSONObject("audio_info").getInteger("duration"))
                        .build();
            } else if (!"20000001".equals(code) && !"20000002".equals(code)) {
                //不为队列中或处理中的状态抛出异常
                ToastResultCode.SOUND_ASR_ERROR.check(true);
            }
            //休眠0.3秒后再次请求获取结果
            Thread.sleep(300);
            //计数器增加
            count++;
        }
        return null;
    }

    /**
     * 创建任务
     * @param taskId
     * @param fileUrl
     * @return
     * @throws UnirestException
     */
    private String submitTask(String userId, String taskId, String fileUrl) throws UnirestException {
        JSONObject requestBody = new JSONObject();
        JSONObject user = new JSONObject();
        user.put("uid", "fake_uid");
        requestBody.put("user", user);
        JSONObject audio = new JSONObject();
        audio.put("url", fileUrl);
        requestBody.put("audio", audio);
        JSONObject request = new JSONObject();
        request.put("model_name", "bigmodel");
        request.put("enable_channel_split", true);
        request.put("enable_ddc", true);
        request.put("enable_speaker_info", true);
        request.put("enable_punc", true);
        request.put("enable_itn", true);
        JSONObject corpus = new JSONObject();
        corpus.put("correct_table_name", "");
        corpus.put("context", "");
        request.put("corpus", corpus);
        requestBody.put("request", request);

        log.info("===> Submit task request body: {}", requestBody);

        HttpResponse<String> response = Unirest.post(submitUrl)
                .header("X-Api-App-Key", asrConfig.getAsrAppId())
                .header("X-Api-Access-Key", asrConfig.getAsrAccessToken())
                .header("X-Api-Resource-Id", resourceId)
                .header("X-Api-Request-Id", taskId)
                .header("X-Api-Sequence", "-1")
                .body(requestBody.toString())
                .asString();

        String statusCode = response.getHeaders().getFirst(X_API_STATUS_CODE);
        String logId = response.getHeaders().getFirst("X-Tt-Logid");
        log.info("===> Submit task success statusCode: {}, logId : {}", statusCode, logId);
        if ("20000000".equals(statusCode)) {
            return logId;
        } else {
            log.info("===> Submit task failed and the response headers are: {}", response.getHeaders());
        }
        return null;
    }

    /**
     * 查询任务
     * @param taskId
     * @param xTtLogid
     * @return
     * @throws UnirestException
     */
    private HttpResponse<String> queryTask(String taskId, String xTtLogid) throws UnirestException {
        HttpResponse<String> response = Unirest.post(queryUrl)
                .header("X-Api-App-Key", asrConfig.getAsrAppId())
                .header("X-Api-Access-Key", asrConfig.getAsrAccessToken())
                .header("X-Api-Resource-Id", resourceId)
                .header("X-Api-Request-Id", taskId)
                .header("X-Tt-Logid", xTtLogid)
                .body("{}")
                .asString();

        //查询结果代码说明：
//        20000000 Success
//        20000001 Processing
//        20000002 Task in queue
//        20000003 Mute audio (There is no need to query again when this error code is returned. Just submit again directly.)
//        45000001 Invalid request parameters (The request parameters are missing required fields / the field values are invalid / repeated requests.)
//        45000002 Empty audio
//        45000151 Incorrect audio format
//        550xxxx Service internal processing error
//        55000031 Server busy (The service is overloaded and cannot process the current request.)
        if (response.getHeaders().containsKey("X-Api-Status-Code")) {
            log.info("===> Query task response header X-Api-Status-Code: {}", response.getHeaders().getFirst("X-Api-Status-Code"));
        } else {
            log.info("===> Query task failed and the response headers are: {}", response.getHeaders());
        }
        return response;
    }

}
