package com.xunao.effectdemo.yzs;

import android.Manifest;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;

import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonWriter;
import com.unisound.edu.oraleval.sdk.sep15.IOralEvalSDK;
import com.unisound.edu.oraleval.sdk.sep15.OralEvalSDKFactory;
import com.unisound.edu.oraleval.sdk.sep15.SDKError;
import com.unisound.edu.oraleval.sdk.sep15.utils.OralEvalEnum;
import com.xunao.effectdemo.R;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;

public class YZSDemoActivity extends Activity
    implements View.OnClickListener, IOralEvalSDK.ICallback {
  private static final String TAG = "oraleval-demo";
  public static final String CONFIG = "config";
  static final boolean USE_OFFLINE_SDK_IF_FAIL_TO_SERVER = false;

  private ConfigBean configBean = new ConfigBean();
  private FileOutputStream audioFileOut;
  private FileOutputStream opusFileOut;
  private File files;
  private final String audioName = "testAudio.mp3";  //音频文件名
  private final String opusName = "testOpus";  //opus文件名

  private EditText etOralEvalText;
  private EditText et_url;
  private EditText etAppKey;
  private TextView tvResult;
  private Button btStart;
  private Button play_b;
  private CheckBox cbDefaultConfig;
  private ProgressBar progressBar;
  IOralEvalSDK _oe;
  ProgressDialog _pd;

  //读写权限
  private static String[] PERMISSIONS_STORAGE = {
      Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
      Manifest.permission.RECORD_AUDIO
  };

  //请求状态码
  private static int REQUEST_PERMISSION_CODE = 1;

  private void getCfg(OralEvalSDKFactory.StartConfig cfg) {
    if (!cbDefaultConfig.isChecked()) {
      //常用配置
      if (!TextUtils.isEmpty(configBean.getOralText())) {
        cfg.setOralText(configBean.getOralText());
      }
      if (configBean.isCN()) {
        cfg.setOralEvalMode(OralEvalEnum.OnlineCH);
      } else {
        cfg.setOralEvalMode(OralEvalEnum.OnlineUS);
      }
      cfg.setVadEnable(configBean.isVadEnable());
      cfg.setVadAfterMs(configBean.getVadAfterMs());
      cfg.setVadBeforeMs(configBean.getVadBeforeMs());
      //不常用配置
      cfg.setScoreAdjuest(configBean.get_scoreAdjuest());
      cfg.setServiceType(configBean.getServiceType());
      cfg.setMp3Audio(configBean.isMp3Audio());
      cfg.setUid(configBean.getUid());
      //不建议修改或者很少使用配置
      cfg.setOnline_ip(configBean.getOnline_ip());
      cfg.setSecret(configBean.getSecret());
      cfg.setSocket_timeout(configBean.getSocket_timeout());
      cfg.setAsyncRecognize(configBean.isSetAsyncRecognize());
      cfg.setBufferLog(configBean.isBufferLog());
    }
    if (USE_OFFLINE_SDK_IF_FAIL_TO_SERVER) {
      cfg.set_useOfflineWhenFailedToConnectToServer(true);
    }
    cfg.setReTry(false);
    cfg.setAppKey(etAppKey.getText().toString());
  }

  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.demo_activity);
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
      if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
          != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_PERMISSION_CODE);
      }
    }

    files = new File(Environment.getExternalStorageDirectory() + "/yunzhisheng/");
    if (!files.exists()) {
      files.mkdirs();
    }
    initOfflineSDK();

    etOralEvalText = (EditText) findViewById(R.id.etOralEvalText);
    et_url = (EditText) findViewById(R.id.et_url);
    etAppKey = (EditText) findViewById(R.id.etAppKey);
    tvResult = (TextView) findViewById(R.id.tvResult);
    btStart = (Button) findViewById(R.id.btStart);
    btStart.setOnClickListener(this);
    play_b = (Button) findViewById(R.id.play_b);
    play_b.setOnClickListener(this);
    progressBar = (ProgressBar) findViewById(R.id.progressBar);
    cbDefaultConfig = (CheckBox) findViewById(R.id.cbDefaultConfig);
    cbDefaultConfig.setChecked(true);
    findViewById(R.id.cancel_b).setOnClickListener(this);
    findViewById(R.id.retry_b).setOnClickListener(this);
    findViewById(R.id.btConfig).setOnClickListener(this);
    findViewById(R.id.btSelect).setOnClickListener(this);
    progressBar.setMax(100);
  }

  private void initOfflineSDK() {
    if (USE_OFFLINE_SDK_IF_FAIL_TO_SERVER) {
      File filesdir = this.getFilesDir();
      if (!filesdir.exists()) {
        filesdir.mkdirs();
      }
      Log.i(TAG, "start init offline sdk");
      IOralEvalSDK.OfflineSDKError err =
          OralEvalSDKFactory.initOfflineSDK(YZSDemoActivity.this, filesdir.getAbsolutePath());
      Log.i(TAG, "end init offline sdk");
      if (err != IOralEvalSDK.OfflineSDKError.NOERROR) {
        showToast("init sdk failed:" + err);
      }
    }
  }

  @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
      @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_PERMISSION_CODE) {
      for (int i = 0; i < permissions.length; i++) {
        Log.i(TAG, "申请的权限为：" + permissions[i] + ",申请结果：" + grantResults[i]);
      }
    }
    files = new File(Environment.getExternalStorageDirectory() + "/yunzhisheng/");
    if (!files.exists()) {
      files.mkdirs();
    }
    initOfflineSDK();
  }

  private void showToast(String txt) {
    if (!TextUtils.isEmpty(txt)) {
      Toast.makeText(YZSDemoActivity.this, txt, Toast.LENGTH_LONG).show();
    }
  }

  @Override public void onDestroy() {
    super.onDestroy();
    if (USE_OFFLINE_SDK_IF_FAIL_TO_SERVER) {
      OralEvalSDKFactory.cleanupOfflineSDK(this);
    }
    if (_oe != null) {
      _oe.cancel();
    }
  }

  @Override public void onClick(View view) {
    switch (view.getId()) {
      case R.id.btSelect:
        fileOralEval();
        break;
      case R.id.btStart:
        start();
        break;
      case R.id.retry_b:
        retry(opusName);
        break;
      case R.id.cancel_b:
        btStart.setText(R.string.start);
        showToast("取消评测");
        if (_oe != null) {
          _oe.cancel();
        }
        break;
      case R.id.play_b:
        showToast("开始播放");
        play();
        break;
      case R.id.btConfig:
        cbDefaultConfig.setChecked(false);
        Intent intent = new Intent(this, YZSConfigActivity.class);
        intent.putExtra(CONFIG, configBean);
        startActivityForResult(intent, 1000);
        break;
      default:
        break;
    }
  }

  private void chooseAudio() {
    Intent intent = new Intent();
    intent.setType("audio/wav");
    intent.setAction(Intent.ACTION_GET_CONTENT);
    startActivityForResult(intent, 1);
  }

  @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (data != null) {
      if (data.getSerializableExtra(CONFIG) != null) {
        configBean = (ConfigBean) data.getSerializableExtra(CONFIG);
      }
    }
  }

  private void start() {
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
      if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
          != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_PERMISSION_CODE);
        showToast("请打开录音和存储权限");
        return;
      }
    }
    if (_oe == null) {
      String txt = etOralEvalText.getText().toString();
      if (TextUtils.isEmpty(txt)) {
        showToast("Empty Text!");
        return;
      }
      OralEvalSDKFactory.StartConfig cfg = new OralEvalSDKFactory.StartConfig(txt);
      if (cfg == null) {
        return;
      }
      getCfg(cfg);
      _oe = OralEvalSDKFactory.start(this, cfg, this);
      btStart.setText(R.string.bt_stop);
      if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        File audioFile = new File(files, audioName);
        if (!audioFile.exists()) {
          try {
            audioFile.createNewFile();
          } catch (IOException e) {
            e.printStackTrace();
          }
        }
        File opusFile = new File(files, opusName);
        if (!opusFile.exists()) {
          try {
            opusFile.createNewFile();
          } catch (IOException e) {
            e.printStackTrace();
          }
        }
        ;
        updateFile("title.txt", txt);
      } else {
        showToast("没有SD卡");
      }
    } else {
      _oe.stop();
      Log.e("============", "stop");
      btStart.setText(R.string.start);
    }
  }

  private void play() {
    try {
      final MediaPlayer mp = MediaPlayer.create(this, Uri.fromFile(new File(files, audioName)));
      mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override public void onPrepared(MediaPlayer mediaPlayer) {
          Log.d(TAG, "mp3 duration:" + mp.getDuration() + "ms");
        }
      });
      mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override public void onCompletion(MediaPlayer mediaPlayer) {
          Log.d(TAG, "final pos:" + mp.getCurrentPosition());
          mp.release();
          play_b.setEnabled(true);
          play_b.setBackgroundColor(Color.parseColor("#d6d7d7"));
        }
      });
      mp.setOnErrorListener(new MediaPlayer.OnErrorListener() {
        @Override public boolean onError(MediaPlayer mp, int what, int extra) {
          mp.release();
          play_b.setEnabled(true);
          play_b.setBackgroundColor(Color.parseColor("#d6d7d7"));
          return false;
        }
      });
      mp.start();
      play_b.setEnabled(false);
      play_b.setBackgroundColor(Color.parseColor("#33d6d7d7"));
    } catch (Exception ee) {
      Log.e(TAG, "playing failed.", ee);
    }
  }

  private void fileOralEval() {
    File file = new File(files, "test.wav");
    if (_oe != null) {
      _oe.cancel();
      btStart.setText(R.string.start);
      showToast("上次评测正在进行中，现在已经取消");
      return;
    }
    String txt = etOralEvalText.getText().toString();
    if (TextUtils.isEmpty(txt)) {
      showToast("Empty Text!");
      return;
    }
    OralEvalSDKFactory.StartConfig cfg = null;
    try {
      cfg = new OralEvalSDKFactory.StartConfig(txt, file.getAbsolutePath());
    } catch (IOException e) {
      e.printStackTrace();
      showToast("Opening " + file.getAbsolutePath() + " failed");
      return;
    }
    showToast("正在进行文件评测");
    if (cfg == null) {
      return;
    }
    getCfg(cfg);
    _oe = OralEvalSDKFactory.start(this, cfg, this);
  }

  private void retry(String file_name) {
    if (_oe != null) {
      _oe.cancel();
      btStart.setText(R.string.start);
      showToast("上次评测正在进行中，现在已经取消");
      return;
    }
    String txt = etOralEvalText.getText().toString();
    if (TextUtils.isEmpty(txt)) {
      showToast("Empty Text!");
      return;
    }
    File file = new File(files, file_name);
    Log.e("file size =", file.length() + "");
    OralEvalSDKFactory.StartConfig cfg = null;
    if (file.exists()) {
      try {
        cfg = new OralEvalSDKFactory.StartConfig(txt, file.getAbsolutePath());
      } catch (IOException e) {
        e.printStackTrace();
        showToast("Opening " + file.getAbsolutePath() + " failed");
        return;
      }
      showToast("正在重试");
    } else {
      showToast("没有可使用音频");
    }

    if (cfg == null) {
      return;
    }
    getCfg(cfg);
    cfg.setReTry(true);
    _oe = OralEvalSDKFactory.start(this, cfg, this);
  }

  /*
   文件缓存
   */
  public void updateFile(String fileName, String data) {
    File titleFile = new File(files, fileName);
    if (!titleFile.exists()) {
      try {
        titleFile.createNewFile();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    OutputStream os = null;
    try {
      os = new FileOutputStream(titleFile);
      os.write(data.getBytes());
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (os != null) {
        try {
          os.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }

  long audioLength = 0;

  @Override public void onStart(IOralEvalSDK iOralEvalSDK, int audioId) {
    Log.i(TAG, "onStart(), audioId=" + audioId);
    this.runOnUiThread(new Runnable() {
      @Override public void run() {
        btStart.setEnabled(true);
        btStart.setBackgroundColor(Color.parseColor("#d6d7d7"));
      }
    });
    audioLength = 0;
  }

  @Override public void onCancel() {
    Log.i(TAG, "onCancel()");
    this.runOnUiThread(new Runnable() {
      @Override public void run() {
        _oe = null;
        if (audioFileOut != null) {
          try {
            audioFileOut.close();
          } catch (IOException e) {
            e.printStackTrace();
          }
          audioFileOut = null;
        }

        if (opusFileOut != null) {
          try {
            opusFileOut.close();
          } catch (IOException e) {
            e.printStackTrace();
          }
          opusFileOut = null;
        }
        btStart.setText(R.string.start);
      }
    });
  }

  @Override public void onError(IOralEvalSDK iOralEvalSDK, SDKError error,
      IOralEvalSDK.OfflineSDKError ofError) {
    Log.i(TAG, "onError");
    final SDKError err = error;
    final IOralEvalSDK.OfflineSDKError ofe = ofError;
    final String sdkLog = iOralEvalSDK.getLog();
    this.runOnUiThread(new Runnable() {
      @Override public void run() {
        _oe = null;
        updateFile("log.txt", sdkLog);
        btStart.setText(R.string.start);
        tvResult.setText("Error:" + err + "\n. offline error:" + ofe);
        btStart.setEnabled(true);
        btStart.setBackgroundColor(Color.parseColor("#d6d7d7"));
        if (_pd != null) {
          _pd.dismiss();
          _pd = null;
        }
        if (audioFileOut != null) {
          try {
            audioFileOut.close();
          } catch (IOException e) {
            e.printStackTrace();
          }
          audioFileOut = null;
        }

        if (opusFileOut != null) {
          try {
            opusFileOut.close();
          } catch (IOException e) {
            e.printStackTrace();
          }
          opusFileOut = null;
        }
      }
    });
  }

  @Override public void onStop(IOralEvalSDK iOralEvalSDK, String s, boolean offline, String str,
      IOralEvalSDK.EndReason stoptype) {
    Log.i(TAG, "onStop(), offline=" + offline + ", stoptype:" + stoptype);
    Log.i(TAG, "result:" + s);
    Log.i(TAG, "url:" + str);

    final String sdkLog = iOralEvalSDK.getLog();

    final String rst = s;
    final String url = str;
    if (audioFileOut != null) {
      try {
        audioFileOut.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
      audioFileOut = null;
    }

    if (opusFileOut != null) {
      try {
        opusFileOut.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
      opusFileOut = null;
    }

    this.runOnUiThread(new Runnable() {
      @Override public void run() {
        _oe = null;
        btStart.setText(R.string.start);
        tvResult.setText(formatResult(rst));
        updateFile("result.txt", rst);
        updateFile("log.txt", sdkLog);
        btStart.setEnabled(true);
        btStart.setBackgroundColor(Color.parseColor("#d6d7d7"));
        et_url.setText(url);
        File audioFile = new File(files, audioName);
        if (audioFile.exists()) {
          long size = audioFile.length();
          if (size < 20000) {
            showToast("说话时间过短");
          }
        }
        showToast("length:" + audioLength + "-----fileLength:" + audioFile.length());
        if (_pd != null) {
          _pd.dismiss();
          _pd = null;
        }
      }
    });
  }

  private String formatResult(String str) {
    JsonParser parser = new JsonParser();
    Gson gson = new Gson();
    JsonElement jo = null;
    try {
      jo = parser.parse(str);
    } catch (JsonParseException jpe) {
      return str;
    }
    StringWriter swr = new StringWriter();
    JsonWriter jwr = new JsonWriter(swr);
    jwr.setIndent("  ");
    gson.toJson(jo, jwr);
    try {
      jwr.flush();
      swr.flush();
    } catch (Exception e) {
    }
    return swr.getBuffer().toString();
  }

  @Override public void onVolume(IOralEvalSDK who, final int value) {
    this.runOnUiThread(new Runnable() {
      @Override public void run() {
        progressBar.setProgress(value);
      }
    });
  }

  @Override public void onStartOralEval() {
    Log.e("StartOralEval", "StartOralEval");
  }

  @Override public void onAudioData(IOralEvalSDK iOralEvalSDK, byte[] bytes, int offset, int len) {
    audioLength += bytes.length;
    try {
      if (audioFileOut == null) {
        audioFileOut = new FileOutputStream(new File(files, audioName));
      }
      audioFileOut.write(bytes, offset, len);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  @Override public void onOpusData(IOralEvalSDK iOralEvalSDK, byte[] bytes, int offset, int len) {
    try {
      if (opusFileOut == null) {
        opusFileOut = new FileOutputStream(new File(files, opusName));
      }
      opusFileOut.write(bytes, offset, len);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  @Override public void onAsyncResult(IOralEvalSDK who, String url) {
    Log.i(TAG, "onAsyncResult url:" + url);
  }
}
