/*
 * Copyright (C) 2020, KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
#include "reader.h"
#include "global/kaglobal.h"

#include <QBuffer>
#include <QUrl>
#include <QMutexLocker>

#include <ukui-log4qt.h>

#define READ_FILE_PATH "/.read"

//朗读回调函数，用于接收SDK返回的音频数据
static void synthesisResultCallback(SpeechSynthesisResult *result, void *user_data)
{
    Reader *reader = static_cast<Reader*>(user_data);
    if (reader == nullptr) {
        KyInfo() << "Invalid callback user data pointer.";
        return;
    }
    if (reader->m_soundFlag){
        return;
    }
    SpeechResultReason reason = speech_synthesis_result_get_reason(result);
    int errorCode = speech_synthesis_result_get_error_code(result);
    const char *errorMsg = speech_synthesis_result_get_error_message(result);


    if(errorCode !=0 && errorCode != -1)
    {
        KyInfo() << "当前错误码为" << errorCode;
//        QString errorMsg = getReaderErrorMsg((SpeechResult)errorCode);
        QString errorStr = Globals::getErrorMsg(static_cast<SpeechErrorCode>(errorCode));
        Q_EMIT reader->reply(errorStr,true,0,errorCode);
        Q_EMIT reader->sigReadEnd(reader->m_index);
        Q_EMIT reader->sigResetPreIndex();
        return;
    }

    if(reason == SPEECH_SYNTHESIS_COMPLETED){
        //由QAudioOutput改为QMediaPlayer方案，需要将pcm格式文件，转换成MP3格式
        QString oldName = reader->m_file->fileName();
        QFileInfo fileInfo(oldName);
        QString baseName = fileInfo.baseName();  // 获取文件名（不包括扩展名）
        QString newName = fileInfo.absolutePath() + "/" + baseName + ".mp3";  // 新的文件路径
        QProcess process;
        process.start("ffmpeg", QStringList() << "-f" << "s16le" << "-ar" << "16000" << "-ac" << "1" << "-i" << oldName << newName);
        process.waitForFinished();
        reader->m_file->close();
        KyInfo() << "oldName : " << oldName;
        KyInfo() << "newName : " << newName;
        reader->m_file->setFileName(newName);
        if (reader->isNeedRead)
            reader->startReading();
    }
     return;
}

Reader::Reader(QObject *parent) : QObject(parent)
{
    m_file = new QFile(this);

    m_player = new QMediaPlayer(this);

    initConnect();
}

Reader::~Reader()
{
    if(m_file->isOpen())
        m_file->close();
}

void Reader::startReading()
{
    KyInfo() << "reader startReading";

    if (!m_file->exists()) {
        KyInfo() << "文件不存在:" << m_file->fileName();
        return;
    }

    m_player->setMedia(QUrl::fromLocalFile(m_file->fileName()));
    m_player->play();
    isNeedRead = true;
}

void Reader::pauseReading()
{
    if(isNeedRead)
        isNeedRead = false;

    //判断文件是否在打开，打开说明合成未结束，无法直接播放，直接返回。
    if (m_file->isOpen())
        return;
    if(m_player->state() == QMediaPlayer::State::PlayingState)
    {
        m_player->pause();
    }
}

void Reader::continueReading(int index)
{
    isNeedRead = true;

    //判断文件是否在打开，打开说明合成未结束，无法直接播放，直接返回。等待合成结束后，触发播放
    if (m_file->isOpen())
        return;

    if (m_player->state() == QMediaPlayer::PausedState) {
                m_player->play();
                KyInfo() << "Resumed";
    } else {
       startReading();
   }
}

//向SDK发送文字数据
bool Reader::sendText(const QString &msg, int index)
{
    if (msg.length() == 0) {
        // KyInfo() << "文本为空";
        Q_EMIT sigReadEnd(index);
        Q_EMIT sigResetPreIndex();
        return false;
    }
    if(!initSession()){
        KyInfo() << "初始化session失败，文字发送失败，已经返回";
        Q_EMIT sigReadEnd(index);
        Q_EMIT sigResetPreIndex();

        return false;
     }
    m_soundFlag = false;

    if(m_player->state() == QMediaPlayer::State::PlayingState){
        m_player->stop();
    }

    if (m_file->isOpen()) {
         m_file->close();
    }

    // 清空其他音频文件
    QString dataDirPath = Globals::defaultPath + READ_FILE_PATH;
    QDir readPathDir(dataDirPath);
    QStringList filters;
    filters << "*.pcm";
    filters << "*.mp3";
    QFileInfoList fileList = readPathDir.entryInfoList(filters, QDir::Files);
    foreach(const QFileInfo &fileInfo, fileList) {
        QFile::remove(fileInfo.absoluteFilePath());
    }

    // 打开新文件进行写入
    QString fileName = generateUniqueFileName();
    QByteArray byteArray = fileName.toUtf8();
    const char* cString = byteArray.constData();
    m_file->setFileName(fileName);

    //记录播放语音的index值，音频播放结束时使用
    m_index = index;

    auto *synthesizerConfig = audio_config_create_audio_output_from_pcm_file_name(cString);
    audio_config_set_input_audio_rate(synthesizerConfig, 16000);
    speech_synthesizer_set_audio_config(session, synthesizerConfig);

    QByteArray array = msg.toUtf8();
    const char* text = array.data();

    speech_synthesizer_synthesize_text_async(session, text, (uint32_t)(array.length()));


    m_file->open(QIODevice::WriteOnly);
    isNeedRead = true;
    return true;
}


bool Reader::initSession()
{
    if(this->session != nullptr)
        return true;
    QString error;

    KyInfo() << "*** start initSession speech_synthesizer_create_session()";

    SpeechSynthesizerSession *session = speech_synthesizer_create_session();
    if(session == nullptr){
        KyInfo() << "error : speech_synthesizer_create_session failed!";
        //TODO： 错误处理
        return false;
    }
    KyInfo() << "*** end initSession speech_synthesizer_create_session()";

    KyInfo() << "*** start initSession speech_synthesizer_init_session()";

    int ret =  speech_synthesizer_init_session(session);
    if(ret){
        KyInfo() << "reader init session error:" << ret;
        error = Globals::getErrorMsg(static_cast<SpeechErrorCode>(ret));
        Q_EMIT reply(error, true, 0, ret);
        return false;
    }
    KyInfo() << "*** end initSession speech_synthesizer_init_session()";


    if(session)
        this->session = session;
    else
         return false;

    speech_synthesizer_result_set_callback(session, synthesisResultCallback, this);

    return true;
}

void Reader::closeSession()
{
    if(this->session != nullptr){
        SpeechSynthesizerSession ** sSession = &session;
        speech_synthesizer_destroy_session(sSession);
    }
    this->session = nullptr;
}

void Reader::initConnect()
{
    connect(m_player, &QMediaPlayer::mediaStatusChanged, this, &Reader::onPlayerStateChanged);
}

void Reader::onPlayerStateChanged(QMediaPlayer::MediaStatus status) {
    if (status == QMediaPlayer::MediaStatus::EndOfMedia) {
        Q_EMIT sigReadEnd(m_index);
//        m_player->stop();
    }
}


QString Reader::generateUniqueFileName()
{
    QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
    return Globals::defaultPath + READ_FILE_PATH + "/audio_" + timestamp + ".pcm";
}
