/*
 * Copyright (c) 2020. Lemon Healthcare
 *
 *
 */

package com.lemonhc.mplus.stt;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.drawable.AnimationDrawable;
import android.os.Build;
import android.os.Handler;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.lemonhc.mplus.MPlusConstants;
import com.lemonhc.mplus.mcare_plus.R;
import com.lemonhc.mplus.mcare_plus.activity.MainActivity;
import com.lemonhc.mplus.naver_csr.ChatBotEventHandler;
import com.lemonhc.mplus.naver_csr.ChatBotEventListener;
import com.lemonhc.mplus.naver_csr.ChatBotProc;
import com.lemonhc.mplus.naver_csr.ChatBotView;
import com.lemonhc.mplus.naver_csr.ChatBotViewModel;
import com.lemonhc.mplus.naver_csr.SpeechRecognizerWrapper;
import com.naver.speech.clientapi.SpeechConfig;
import com.naver.speech.clientapi.SpeechRecognitionException;
import com.naver.speech.clientapi.SpeechRecognitionListener;
import com.naver.speech.clientapi.SpeechRecognitionResult;
import com.naver.speech.clientapi.SpeechRecognizer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import butterknife.BindView;
import butterknife.ButterKnife;
import lombok.NonNull;

public class NaverRecognizer extends SpeechRecognizerWrapper implements SpeechRecognitionListener, ChatBotEventListener {

    @NonNull
    Context context;

    private MainActivity activity;
    private SpeechRecognizer mRecognizer;
    private ChatBotView chatBotView;
    private ChatBotViewModel chatBotViewModel;
    private AnimationDrawable spinnerAnim;
    private static final Logger LOGGER = LoggerFactory.getLogger(NaverRecognizer.class);

    public NaverRecognizer(Context context){
        this.context = context;
        this.activity = (MainActivity) this.context;
        this.chatBotView = activity.getChatBotView();
        this.chatBotViewModel = activity.getChatBotView().chatBotViewModel;

        // 챗봇이벤트 리스너 사용등록
        ChatBotEventHandler.addListener(this);

        try {
            this.permissionCheck();
            this.mRecognizer = new SpeechRecognizer(this.context, MPlusConstants.NAVER_STT_CLIENT_ID);
            this.mRecognizer.setSpeechRecognitionListener(this);
        } catch (SpeechRecognitionException e) {
            e.printStackTrace();
            Log.e("NaverRecognizer", "NaverRecognizer(Context context) SpeechRecognitionException" + e.toString());
        }

        this.startAnimation();

    }

    public void startAnimation(){


        new Thread(new Runnable() {
            @Override
            public void run() {
                // runOnUiThread를 추가하고 그 안에 UI작업을 한다.
                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        chatBotView.getAnimation().post(new Runnable() {
                            @Override
                            public void run() {
                                spinnerAnim = (AnimationDrawable) chatBotView.getAnimation().getDrawable();
                                if (!spinnerAnim.isRunning()) {
                                    spinnerAnim.setVisible(true,true);
                                    spinnerAnim.setOneShot(false);
                                    spinnerAnim.start();
                                }

//                                progressAnimation =    (AnimationDrawable)imageView.getDrawable();
//                                progressAnimation.setCallback(imageView);
//                                progressAnimation.setVisible(true, true);
                            }
                        });
                    }
                });
            }
        }).start();

    }


    @Override
    public void initSpeechRecognizer() {
        this.mRecognizer.initialize();
    }

    @Override
    public void recognize() {

        // 마이크 권한체크
        if (!this.checkMicPermission()){
            Toast.makeText(this.context, "마이크 사용권한이 없습니다.", Toast.LENGTH_SHORT).show();
            return;
        }

        try {
            mRecognizer.recognize(new SpeechConfig(SpeechConfig.LanguageType.KOREAN, SpeechConfig.EndPointDetectType.AUTO));
        } catch (SpeechRecognitionException e) {
            e.printStackTrace();
            Log.e("NaverRecognizer", "recognize() SpeechRecognitionException" + e.toString());
        }
    }

    @Override
    public void requestChatbot(String questionString) {

        ChatBotProc chatBotProc = new ChatBotProc();
        chatBotProc.requestChatbot(questionString, "test");

    }

    @TargetApi(Build.VERSION_CODES.M)
    private void permissionCheck() {
        /*
         * 사용자 단말기의 권한이 허용되어 있는지 확인한다.
         * Android는 C언어 기반으로 만들어졌기 때문에 Boolean 타입보다 Int 타입을 사용한다.
         */
        int tmp = this.context.checkSelfPermission(Manifest.permission.RECORD_AUDIO);
        /*
         * 패키지는 안드로이드 어플리케이션의 아이디이다.
         * 현재 어플리케이션이 CALL_PHONE에 대해 거부되어있는지 확인한다.
         */

        MainActivity activity = (MainActivity) this.context;
        if (tmp == PackageManager.PERMISSION_DENIED) {
            /*
             * 사용자가 RECORD_AUDIO 권한을 거부한 적이 있는지 확인한다.
             * 거부한적이 있으면 True를 리턴하고
             * 거부한적이 없으면 False를 리턴한다.
             */
            if (!activity.shouldShowRequestPermissionRationale(Manifest.permission.RECORD_AUDIO)) {
                // 최초 권한 요청
                activity.requestPermissions(new String[] {Manifest.permission.RECORD_AUDIO}, 1000);
            }
        }

        if (!activity.shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            // 최초 권한 요청
            activity.requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1000);
        }
    }

    boolean checkMicPermission() {
        int permissionCheck = ContextCompat.checkSelfPermission(this.context, Manifest.permission.RECORD_AUDIO);
        return permissionCheck == PackageManager.PERMISSION_GRANTED;
    }

    public void showTextComponents(Boolean title, Boolean voice, Boolean description){
        // Thread를 생성한다.
        new Thread(new Runnable() {
            @Override
            public void run() {
                // runOnUiThread를 추가하고 그 안에 UI작업을 한다.
                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        int titleVisible = (title) ? View.VISIBLE : View.INVISIBLE;
                        chatBotView.getTitle().setVisibility(titleVisible);

                        int voiceVisible = (voice) ? View.VISIBLE : View.INVISIBLE;
                        chatBotView.getVoice().setVisibility(voiceVisible);

                        int descriptionVisible = (description) ? View.VISIBLE : View.INVISIBLE;
                        chatBotView.getDescription().setVisibility(descriptionVisible);
                    }
                });
            }
        }).start();
    }
    public void showIconComponents(Boolean mic, Boolean animation, Boolean refresh){
        // Thread를 생성한다.
        new Thread(new Runnable() {
            @Override
            public void run() {
                // runOnUiThread를 추가하고 그 안에 UI작업을 한다.
                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        int micVisible = (mic) ? View.VISIBLE : View.INVISIBLE;
                        chatBotView.getMic().setVisibility(micVisible);

                        int animationVisible = (animation) ? View.VISIBLE : View.INVISIBLE;
//                        startAnimation(animation);
                        chatBotView.getAnimation().setVisibility(animationVisible);

                        int refreshVisible = (refresh) ? View.VISIBLE : View.INVISIBLE;
                        chatBotView.getRefresh().setVisibility(refreshVisible);
                    }
                });
            }
        }).start();
    }

    @Override
    public void onInactive() {
        Log.e("NaverRecognizer", "onInactive() ");
    }

    @Override
    public void onReady() {
        Log.e("NaverRecognizer", "onReady() ");

        // Thread를 생성한다.
        new Thread(new Runnable() {
            @Override
            public void run() {
                // runOnUiThread를 추가하고 그 안에 UI작업을 한다.
               activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        chatBotViewModel.setTitle("찾고 싶은 메뉴를 말씀하세요.");
                        chatBotView.getTitle().setText(chatBotViewModel.getTitle().getValue());
                        chatBotView.getVoice().setTextColor(Color.BLACK);
                        showTextComponents(true,true,false);
                        showIconComponents(false,true,false);
                    }
                });
            }
        }).start();

    }

    @Override
    public void onRecord(short[] speech) {
        Log.e("NaverRecognizer", "onRecord() speech" );
    }

    @Override
    public void onPartialResult(String partialResult) {
        Log.e("NaverRecognizer", "onPartialResult() partialResult: " + partialResult);
        // Thread를 생성한다.
        new Thread(new Runnable() {
            @Override
            public void run() {
                // runOnUiThread를 추가하고 그 안에 UI작업을 한다.
                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (partialResult.length() > 0){
                            chatBotViewModel.setVoiceMessage(String.format("\"%s\"", partialResult));
                            chatBotView.getVoice().setText(chatBotViewModel.getVoiceMessage().getValue());
                            showTextComponents(false,true,false);
                            showIconComponents(false,true,false);
                        }
                    }
                });
            }
        }).start();
    }

    @Override
    public void onEndPointDetected() {
        Log.e("NaverRecognizer", "onEndPointDetected()" );
        // Thread를 생성한다.
        new Thread(new Runnable() {
            @Override
            public void run() {
                // runOnUiThread를 추가하고 그 안에 UI작업을 한다.
                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        chatBotViewModel.setTitle("찾고 싶은 메뉴를 말씀하세요.");
                        showTextComponents(true,true,false);
                        chatBotView.getTitle().setText(chatBotViewModel.getTitle().getValue());
                        showIconComponents(false,false,true);

                    }
                });
            }
        }).start();

    }

    @Override
    public void onResult(SpeechRecognitionResult finalResult) {

        Log.d("NaverSTT", "onResult() " + finalResult.getResults().get(0));

        // 이곳의 결과값을 가지고, 챗봇을 수행한다.
        // TODO 실패일 경우 거르는 로직 필요
        this.requestChatbot(finalResult.getResults().get(0));
    }

    @Override
    public void onError(int errorCode) {
        Log.e("NaverRecognizer", "onError() errorCode" + errorCode);
        if (this.mRecognizer.isRunning()){
            this.mRecognizer.stop();
        }
    }

    @Override
    public void onEndPointDetectTypeSelected(SpeechConfig.EndPointDetectType epdType) {
        Log.e("NaverRecognizer", "onEndPointDetectTypeSelected() epdType" + epdType.toString());
        if (this.mRecognizer.isRunning()){
            this.mRecognizer.stop();
        }
    }

    @Override
    public void onEvent(String result) {
        // 챗봇 결과 이벤트가 이쪽으로 들어온다.
        Log.d("onEvent",String.format("챗봇인식결과: %s", result));
        LOGGER.debug("챗봇인식결과: %s", result);

        if (!result.equals("fail")){

            // Thread를 생성한다.
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // runOnUiThread를 추가하고 그 안에 UI작업을 한다.
                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            chatBotViewModel.setTitle("아래의 메뉴로 이동합니다.");
                            chatBotView.getVoice().setTextColor(Color.RED);
                            chatBotViewModel.setVoiceMessage(String.format("\"%s\"", result));
                            chatBotView.getTitle().setText(chatBotViewModel.getTitle().getValue());
                            chatBotView.getVoice().setText(chatBotViewModel.getVoiceMessage().getValue());
                            showTextComponents(true,true,false);
                            showIconComponents(false,false,true);
                        }
                    });
                }
            }).start();
            this.activity.voidceMenuCall(result);
        } else {
            // Thread를 생성한다.
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // runOnUiThread를 추가하고 그 안에 UI작업을 한다.
                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            chatBotViewModel.setTitle("원하시는 메뉴를 찾지 못했습니다.");
                            chatBotView.getVoice().setTextColor(Color.RED);
                            chatBotView.getTitle().setText(chatBotViewModel.getTitle().getValue());

                            showTextComponents(true,true,true);
                            showIconComponents(false,false,true);
                        }
                    });
                }
            }).start();
        }
    }
}
