package com.voice.platform.asr_demo;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.text.Html;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioGroup;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;

import com.google.android.material.snackbar.Snackbar;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.platform.asr_sdk.Asr;
import com.platform.asr_sdk.AsrAuth;
import com.platform.asr_sdk.BaseAsr;
import com.platform.asr_sdk.Errors;
import com.platform.asr_sdk.HttpUtils;
import com.platform.asr_sdk.LogUtils;
import com.platform.asr_sdk.Recognizer;
import com.platform.asr_sdk.Recorder;
import com.platform.asr_sdk.Transcriber;


import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

public class AsrUi {
    private EditText editAppId;
    private EditText editAppSecret;
    private EditText editOnCode;
    private EditText editOffCode;
    private final MainActivity activity;
    private ActivityResultLauncher<Intent> wavLauncher;

    private ActivityResultLauncher<String> txtLauncher;
    public static final int TYPE_WAV = 1;
    public static final int TYPE_HOTWORDS = 2;
    private int fileType;
    private String startTime;
    private long startTime1;
    private  AlertDialog asrProgressDialog;
    private  String format;
    private String audioFilePath = "";
    private ArrayAdapter<Hotwords> spinnerHotwordsAdapter;
    private ArrayList<Hotwords> spinnerHotwordsData;
    private ActivityResultLauncher<String> fileLauncher;
    public AsrUi(MainActivity activity) {
        this.activity = activity;
    }
    private TextView txtResult;
    private TextView textIs;
    private String total = "";
    private ScrollView scroll;
    private Recorder recorder;
    private RadioGroup rgOnline;
    private Spinner spinnerLang;
    private boolean initSuccess;
    private Asr.Type type = Asr.Type.TRANSCRIBER;

    private Transcriber transcriber;
    private Recognizer recognizer;
    private Asr asr;

    private boolean onlineAuth = true;
    private boolean onlineAsr = true;
    private boolean autoRecording = true;
    private LinearLayout line_offCode;
    private LinearLayout line_appid;
    private Spinner spinnerHotwords;
    private String langType;
    public static final String BLACK = "#000000";
    public static final String GRAY = "#909090";
    private boolean Pressure =false;
    public void init() {
//        System.out.println("UI.init");
        initLauncher();
        httpList();
        initRecognizer();
        initViews();

    }
    int i=1;
    private void initViews() {
        editAppId = activity.findViewById(R.id.editAppId);
        editAppSecret = activity.findViewById(R.id.editAppSecret);

        editOnCode = activity.findViewById(R.id.editOnCode);
        editOffCode = activity.findViewById(R.id.editOffCode);

        line_offCode = activity.findViewById(R.id.line_offCode);
        line_appid = activity.findViewById(R.id.line_appid);

        spinnerHotwords = activity.findViewById(R.id.spinnerHotwords);
        spinnerHotwordsData = new ArrayList<>();
        spinnerHotwordsAdapter = new ArrayAdapter<>(activity, android.R.layout.simple_spinner_dropdown_item, spinnerHotwordsData);
        spinnerHotwords.setAdapter(spinnerHotwordsAdapter);

        editAppId.setText(activity.getAppId());
        editAppSecret.setText(activity.getAppSecret());

        editOnCode.setText(activity.getOfflinekey());
        editOffCode.setText(activity.getOfflineAuthCode());

        TextView machineCode=activity.findViewById(R.id.text_machineCode);
        String sixDigitCode = AsrAuth.getSixDigitCode(activity);
        try {
            JSONObject jo = new JSONObject(sixDigitCode);
            machineCode.setText("Machine code:"+jo.getString("encode_machine_info"));
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }

        activity.findViewById(R.id.btnInit).setOnClickListener(v -> onClickInit());
        activity.findViewById(R.id.btnReleaseCurrent).setOnClickListener(v -> onClickReleaseCurrent());
        activity.findViewById(R.id.btnReleaseAll).setOnClickListener(v -> onClickReleaseAll());
        activity.findViewById(R.id.btnStart).setOnClickListener(v -> onClickStart());
        activity.findViewById(R.id.btnStop).setOnClickListener(v -> onClickStop());
        activity.findViewById(R.id.btnFile).setOnClickListener(v -> onClickFile());
        activity.findViewById(R.id.btnLoadHw).setOnClickListener(v -> onClickBtnLoadHw());
        activity.findViewById(R.id.btnsenEnd).setOnClickListener(v -> getAsr().sentenceEnd());
        activity.findViewById(R.id.btnspeakerStart).setOnClickListener(v -> getAsr().speakerStart("speaker00_"+i++));
        startTime1 = System.currentTimeMillis();

        activity.findViewById(R.id.btnStress).setOnClickListener(v ->
                {
                    Pressure=true;
                    format = new SimpleDateFormat("MMdd-HH:mm:ss").format(new Date());
                    asrProgressDialog = new AlertDialog.Builder(activity)
                            .setTitle("start:")
                            .setMessage("Identifying the first audio")
                            .setCancelable(false)
                            .create();
                    asrProgressDialog.show();
                    onClickStartFile();
                }
                );
        textIs = activity.findViewById(R.id.text_is);

        txtResult = activity.findViewById(R.id.txtResult);
        scroll = activity.findViewById(R.id.scroll);

        RadioGroup rgAuth = activity.findViewById(R.id.rgAuth);
        rgAuth.setOnCheckedChangeListener((group, checkedId) -> {
            if (checkedId == R.id.rbOnlineAuth) {
                line_offCode.setVisibility(View.GONE);
                onlineAuth = true;
            } else if (checkedId == R.id.rbOfflineAuth) {
                onlineAuth = false;
                line_offCode.setVisibility(View.VISIBLE);
            }
        });

        rgOnline = activity.findViewById(R.id.rgOnline);
        rgOnline.setOnCheckedChangeListener((group, checkedId) -> {
            setSpinnerAdapter();
            if (checkedId == R.id.rbOnline) {
                onlineAsr = true;
                rgAuth.setVisibility(View.GONE);
                line_offCode.setVisibility(View.GONE);
                line_appid.setVisibility(View.VISIBLE);
            } else if (checkedId == R.id.rbOffline) {
                onlineAsr = false;
                rgAuth.setVisibility(View.VISIBLE);
                line_appid.setVisibility(View.GONE);
                line_offCode.setVisibility(onlineAuth ? View.GONE : View.VISIBLE);
            }
        });


        RadioGroup rgType = activity.findViewById(R.id.rgType);
        rgType.setOnCheckedChangeListener((group, checkedId) -> {
            if (checkedId == R.id.rbRecognize) {
                onClickStop();
                type = Asr.Type.RECOGNIZER;
            } else if (checkedId == R.id.rbTranscribe) {
                onClickStop();
                type = Asr.Type.TRANSCRIBER;

            }
        });

        RadioGroup rgAuto = activity.findViewById(R.id.rgAuto);


        spinnerLang = activity.findViewById(R.id.spinnerLang);
        setSpinnerAdapter();
        spinnerLang.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
//                langType = ((Lang) parent.getAdapter().getItem(position)).langCode;
                String[] arr = adapter.getItem(position).split("\\+");
                langType = arr[0];
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });
    }

    private void initLauncher() {
        activity.registerForActivityResult(new ActivityResultContracts.RequestPermission(), success -> {
            String msg = "Recording permission acquisition" + (success ? "success" : "lose");
            tip(msg);
        }).launch(Manifest.permission.RECORD_AUDIO);

    }
    private SpinnerAdapter adapter;
    private void setSpinnerAdapter() {
//        spinnerLang.setAdapter(new ArrayAdapter<>(activity, android.R.layout.simple_spinner_dropdown_item, getLangs()));
        adapter = new SpinnerAdapter(activity, itemList);
        spinnerLang.setAdapter(adapter);
    }

    @NonNull
    private Lang[] getLangs() {
        if (rgOnline.getCheckedRadioButtonId() == R.id.rbOnline) {
            return new Lang[]{
                    new Lang("ja-JP", "日本語"),
                    new Lang("en-US", "英語"),
                    new Lang("zh-cmn-Hans-CN", "中国語"),
                    new Lang("jaen-JP", "日英混"),
                    new Lang("zhen-cmn-Hans-CN", "中英混"),
            };
        } else {
            return new Lang[]{
                    new Lang("ja-JP", "日本語"),
                    new Lang("en-US", "英語"),
                    new Lang("zh-cmn-Hans-CN", "中国語"),

            };
        }
    }


    private static class Lang {
        String langCode;
        String text;

        public Lang(String langCode, String text) {
            this.langCode = langCode;
            this.text = text;
        }

        @NonNull
        @Override
        public String toString() {
            return text;
        }
    }


    private final Model[] models = new Model[]{
            new Model("日本語", "ja-JP"),
            new Model("英語", "en-US"),
            new Model("中国語", "zh-cmn-Hans-CN"),
            new Model("日英混", "jaen-JP"),
            new Model("中英混", "zhen-cmn-Hans-CN"),
            };


    private static class Model {
        String title;
        String lang;
        String authCode;
        String modelPath;
        boolean authSuccess;
        boolean initSuccess;

        public Model(String title, String lang) {
            this.title = title;
            this.lang = lang;
            this.modelPath = lang;
        }
    }

    private String getCurrLang() {
        return models[spinnerLang.getSelectedItemPosition()].lang;
    }

    private void onClickFile() {
        fileLauncher.launch("audio/x-wav");

    }
    private void onClickInit() {
        System.out.println("MainActivity.onClickInit");
        String appId = editAppId.getText().toString();
        String appSecret = editAppSecret.getText().toString();
        String offLineCode = editOffCode.getText().toString();
        Asr.InitListener initListener = getInitListener();

        if (onlineAsr) {
            getAsr().initOnline(appId, appSecret, initListener);
        } else {
            if (onlineAuth) {
                getAsr().initOffline_OnlineAuth(appId, getCurrLang(), initListener);
            } else {
                getAsr().initOffline_OfflineAuth(appId,offLineCode, getCurrLang(), initListener);
            }
        }
        if (autoRecording) {
            System.out.println("auto init Recording...");
            getAsr().initRecorder();
        }

    }

    private void onClickReleaseCurrent() {
        String lang = getCurrLang();
        getAsr().finsh(lang);
    }

    private void onClickReleaseAll() {
        getAsr().releaseAll();
    }

    private BaseAsr getAsr() {
        if (type == Asr.Type.RECOGNIZER) {
            return recognizer;
        }
        return transcriber;
    }

    private void initRecognizer() {
        transcriber = Transcriber.getInstance(activity,((code, msg) -> {
            if ("00000".equals(code)) {
                System.out.println("Success");
            } else {
                System.out.println("code = " + code);
            }
        }));

        transcriber.setListener(getListener(Asr.Type.TRANSCRIBER));
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        recognizer = Recognizer.getInstance(activity,((code, msg) -> {
            if ("00000".equals(code)) {
                System.out.println("Success");
            } else {
                System.out.println("code = " + code);
            }
        }));

        recognizer.setListener(getListener(Asr.Type.RECOGNIZER));
        startTime = new SimpleDateFormat("yyyyMMdd-HHmmss", Locale.CHINA).format(new Date());
    }

    @NonNull
    private Asr.Listener getListener(Asr.Type type) {
        return new Asr.Listener() {
            @Override
            public void onStart(String taskId) {
                System.out.println("onStart.taskId = " + taskId);
            }

            @Override
            public void onError(String taskId, Errors.Err err) {
                LogUtils.printCallStackTrace();
                System.out.println("Listener.onError,taskId= " + taskId + ", err = " + err);
                tip("Error:"+err.toString());

            }

            @Override
            public void onResult(String msg) {
                System.out.println("Listener.onResult, type= " + type + ", result = " + msg);
                showOnlineResult(msg);
            }

            @Override
            public void onIntermediateResult(String msg) {
                showOnlineIntermediateResult(msg);
                System.out.println("Listener.onIntermediateResult, type= " + type + ", result = " + msg);
            }

            @Override
            public void onWarning(String taskId,Errors.Err err) {
                System.out.println("Listener.onWarning,taskId= " + taskId + ", err = " + err);
                tip("Warning:"+err.toString());
            }

            @Override
            public void onGetAudio(byte[] data) {
//                System.out.println("MainActivity.onGetAudio,thread:" + Thread.currentThread());
            }

            @Override
            public void onStop() {
                System.out.println("Main.onStop");
                if (Pressure){
                    onClickStartFile();
                }
            }
        };
    }

    private void showOnlineIntermediateResult(String mse) {
        JsonObject json = (JsonObject) JsonParser.parseString(mse);
        String result = json.get("result").getAsString();
//        System.out.println("result = " + result);
        activity.runOnUiThread(() -> {
            if (!result.isEmpty()){
                txtResult.setText(Html.fromHtml(color(total,BLACK)+color(result,GRAY)));
            }
            scroll.post(() -> scroll.fullScroll(View.FOCUS_DOWN));
        });
    }

    private void showOnlineResult(String mse) {
        JsonObject json = (JsonObject) JsonParser.parseString(mse);
        String result = json.get("result").getAsString();
//        System.out.println("result = " + result);

        boolean endsWithEnglish = result.matches(".*[a-zA-Z]$");

        boolean endsWithPunctuation = result.matches(".*[,.!?]$");
        if (endsWithPunctuation || endsWithEnglish) {
            // 字符串以英文标点结尾
            total += result+"  ";
        }else {
            total += result;
        }

        activity.runOnUiThread(() -> {
            txtResult.setText(total);
            txtResult.setText(Html.fromHtml(color(total,BLACK)));
            scroll.post(() -> scroll.fullScroll(View.FOCUS_DOWN));
        });
    }
    private String color(String word, String color) {
        return String.format("<font color='%s'>%s</font>", color, word);
    }

    private boolean needSpace(String text) {
        return text.endsWith(",") || text.endsWith(".") || text.endsWith("?") || text.endsWith("!");
    }

    private void onClickStart() {
        total = "";
        txtResult.setText("");


        JsonObject params = new JsonObject();
        params.addProperty("lang_type", langType);
        params.addProperty("enable_intermediate_result", true);
        params.addProperty("enable_punctuation_prediction", true);
        params.addProperty("enable_modal_particle_filter", true);
        params.addProperty("enable_inverse_text_normalization", true);
        params.addProperty("max_sentence_silence", 800);
        params.addProperty("enable_words", true);
        params.addProperty("enable_save_log", true);
//        params.addProperty("enable_words", true);
        Hotwords hw = (Hotwords) spinnerHotwords.getSelectedItem();
        if (hw != null) {
            params.addProperty("hotwords_id", hw.getId());
        }
        getAsr().start(autoRecording, onlineAsr, params);

    }

    private void onClickStartFile() {

    }
    private void onClickBtnLoadHw() {
        fileType = TYPE_HOTWORDS;
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("application/zip");
        wavLauncher.launch(intent);
    }

    private void onClickStop() {
        getAsr().stop();
        if (!autoRecording) {
            stopRecording();
        }
    }

    @NonNull
    private Asr.InitListener getInitListener() {
        return new Asr.InitListener() {
            @Override
            public void onSuccess() {
//                System.out.println("MainActivity.onClickInit.onSuccess");
                System.out.println("init success.");
                initSuccess = true;
            }

            @Override
            public void onFail(Errors.Err err) {
                System.out.println("MainActivity.onClickInit.onFail");
                System.out.println("init fail,err: " + err);
                tip(err + "");
            }
        };
    }
    private List<String> itemList = new ArrayList<>();
    private void httpList() {
        JsonObject json = new JsonObject();
        json.addProperty("product_code", "SpeechTranscriber");

        Map<String, String> map = new HashMap<>();
        map.put("Language", "jp");
//        api.voice.dolphin-ai.jp
        HttpUtils.get("https://api.voice.dolphin-ai.jp/common/v1/setting/langs?product_code=SpeechTranscriber", map, new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                e.printStackTrace();

            }
            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                String listJson = response.body().string();
                System.out.println("listJson = " + listJson);
                if (listJson.isEmpty()){
                    return;
                }
                try {
                    JSONObject jsonObject = new JSONObject(listJson);
//                    JSONObject data = jsonObject.getJSONObject("data");
                    JSONArray config_list = jsonObject.getJSONArray("data");
                    itemList = new ArrayList<>();

                    for (int i = 0; i < config_list.length(); i++) {
                        JSONObject jsonConfig_list = config_list.getJSONObject(i);
                        String item = jsonConfig_list.getString("code");
                        String item2 = jsonConfig_list.getString("name");
                        itemList.add(item+"+"+item2);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private void stopRecording() {
        if (recorder == null) {
            return;
        }
        recorder.stop();
    }

    private void tip(String msg) {
        Snackbar.make(activity.getWindow().getDecorView(), msg, Snackbar.LENGTH_SHORT).show();
    }

}
