package com.wmdigit.wmposdemo.ui;

import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.hardware.camera2.CameraCharacteristics;
import android.os.Bundle;
import android.os.RemoteException;
import android.text.TextUtils;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.TextureView;
import android.view.View;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.listener.OnItemClickListener;
import com.elvishew.xlog.XLog;
import com.wmdigit.wmpos.WmAceKG;
import com.wmdigit.wmpos.ai.support.AiSupportActivity;
import com.wmdigit.wmpos.bean.DetectResult;
import com.wmdigit.wmpos.bean.ImageBean;
import com.wmdigit.wmpos.bean.ImageProductBean;
import com.wmdigit.wmpos.bean.ProductMatch;
import com.wmdigit.wmpos.bean.ScaleBitmap;
import com.wmdigit.wmpos.bean.ScaleSetting;
import com.wmdigit.wmpos.http.OnCheckSnCodeVerificationListener;
import com.wmdigit.wmpos.http.OnProductMatchListener;
import com.wmdigit.wmpos.http.OnQueryPosRegisterInfoListener;
import com.wmdigit.wmpos.http.OnUnBindPosListener;
import com.wmdigit.wmpos.listener.OnBitmapSaveListener;
import com.wmdigit.wmpos.listener.OnDataExportListener;
import com.wmdigit.wmpos.listener.OnPreLearningListener;
import com.wmdigit.wmpos.utils.StopWatch;
import com.wmdigit.wmposdemo.R;
import com.wmdigit.wmposdemo.adapter.ButtonAdapter;
import com.wmdigit.wmposdemo.model.AiSupport;
import com.wmdigit.wmposdemo.model.bean.ApiButton;
import com.wmdigit.wmposdemo.databinding.ActivityWeighingBinding;
import com.wmdigit.wmposdemo.model.bean.ApiLevel;
import com.wmdigit.wmposdemo.model.data.Constant;
import com.wmdigit.wmposdemo.utils.ScreenUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

public class WeighingActivity extends AiSupportActivity implements OnItemClickListener, AiSupport {

    private String sessionId;
    private DetectResult detectResult;
    private int MAX = 99999;
    private int MIN = 10000;
    private Random random;
    private int randNumber;
    // 测试用定时器
    private int count = 0;
    private Timer timer = null;
    private ActivityWeighingBinding weighingBinding;
    private TextureView textureView;
    // 计数器
    private Timer mTimer;
    private int mCount = 0;
    //是否击中
    boolean isHit = false;
    private ButtonAdapter adapter;
    private List<ApiButton> buttonList;
    private List<String> resultList;
    private Context context;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // 注意写在super.onCreate之前
        setModelInitListener(new OnModelInitListener() {
            @Override
            public void onComplete() {
                XLog.i("初始化学习模型成功");
            }
        });
        super.onCreate(savedInstanceState);
        initView();
        initData();
        initListener();
    }

    private void initView() {
        weighingBinding = ActivityWeighingBinding.inflate(getLayoutInflater());
        setContentView(weighingBinding.getRoot());
        weighingBinding.tvInfo.setMovementMethod(ScrollingMovementMethod.getInstance());
    }

    private void initListener() {
        adapter.setOnItemClickListener(this);
        weighingBinding.btnGetRandom.setOnClickListener(v -> {
            // randNumber 将被赋值为一个 MIN 和 MAX 范围内的随机数
            randNumber = random.nextInt(MAX - MIN + 1) + MIN;
            System.out.println("生成随机商品id=" + randNumber);
            weighingBinding.edtPlu.setText(randNumber + "");
        });
        // 压力测试开始
        weighingBinding.btnPressureTestStart.setOnClickListener(v -> {
            if (mTimer != null) {
                mTimer.cancel();
                mTimer = null;
            }
            mTimer = new Timer();
            mTimer.schedule(new TimerTask() {
                @Override
                public void run() {
                    mCount++;
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            weighingBinding.tvInfo.setText("正在压测，当前轮数：" + mCount + "");
                            detectResult = autoDetect();
                            //创建随机数
                            randNumber = random.nextInt(MAX - MIN + 1) + MIN;
                            weighingBinding.edtPlu.setText(randNumber + "");
                            isHit = detectResult.getProductIds().contains(randNumber + "") && (detectResult.getProductIds().size() == 1);
                            setFeedBack(detectResult.getSessionId(), randNumber + "", "苹果", isHit);
                            weighingBinding.tvInfo.append("反馈完成, 命中结果" + (isHit == false ? "未命中" : "命中"));

                        }
                    });
                }
            }, 1500, 1500);
        });
        //压力测试停止
        weighingBinding.btnPressureTestStop.setOnClickListener(v -> {
            if (mTimer != null) {
                mTimer.cancel();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        weighingBinding.tvInfo.setText("压力测试停止");
                    }
                });
            }
        });
    }

    public void initData() {
        context = this;
        random = new Random(1);
        buttonList = Constant.API_BUTTONS;
        adapter = new ButtonAdapter(R.layout.item_button, Constant.API_BUTTONS);
        weighingBinding.rvButtons.setAdapter(adapter);
        GridLayoutManager gridLayoutManager = new GridLayoutManager(this, ScreenUtils.isScreenLandscape(this) ? 5 : 3);
        weighingBinding.rvButtons.setLayoutManager(gridLayoutManager);
    }

    @Override
    public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
        ApiButton apiButton = buttonList.get(position);
        if (apiButton.getLevel() == ApiLevel.LEVEL_ABANDON) {
            weighingBinding.tvInfo.setText("该接口已不再使用");
            return;
        } else {
            weighingBinding.tvInfo.setText("调用" + apiButton.getMethodName() + "接口\n");
            switch (apiButton.getMethodNo()) {
                case "3.2":
                    //初始化pos
                    initPosPage();
                    break;
                case "3.3":
                    setCameraId();
                    break;
                case "3.4":
                    //获取全景照
                    getCameraFrame();
                    break;
                case "3.5":
                    //标定秤盘并保存坐标信息
                    saveScaleSetting();
                    break;
                case "3.6":
                    //判断秤盘是否已标定
                    getScaleSettingI();
                    break;
                case "3.8":
                    //解绑POS
                    unBindPos();
                    break;
                case "3.9":
                    //清除训练数据
                    clearTrainedDataI();
                    break;
                case "3.10":
                    //商品识别
                    autoDetectI();
                    break;
                case "3.11":
                    setFeedBackI();
                    break;
                case "3.12":
                    //不再推荐
                    setNoRecommendI();
                    break;
                case "3.14":
                    //获取本地图片地址
                    getLocalImagePathI();
                    break;
                case "3.15":
                    //根据sessionId获取学习数据
                    getSelfLearnI();
                    break;
                case "3.16":
                    // 本地图片异步学习接口
                    imageLearnI();
                    break;
                case "3.17":
                    // 图片同步学习接口
                    imageLearnSyncI();
                    break;
                case "3.18":
                    // 图片学习任务取消
                    imageLearnCancelI();
                    break;
                case "3.19":
                    //导出学习数据
                    exportDataI();
                    break;
                case "3.20":
                    //导入学习数据
                    importDataI();
                    break;
                case "3.21":
                    //启动局域网服务
                    startServerI();
                    break;
                case "3.22":
                    //停止局域网服务
                    stopServerI();
                    break;
                case "3.25":
                    //查询已经学习的商品数据
                    queryLearnedProductsI();
                    break;
                case "3.26":
                    //查询POS注册信息
                    queryPosByMacI();
                    break;
                case "3.27":
                    //学习本地特征数据
                    learnLocalVectorDataI();
                    break;
                case "3.28":
                    //纠错
                    correctI();
                    break;

                case "3.29":
                    // 自动配图
                    autoMatchProduct();
                    break;

                case "3.30":
                    // 校验SN合法性
                    checkSnCodeVerification();
                    break;

                case "3.31":
                    // 加载预学习数据
                    preLearningData();
                    break;
            }
        }
    }

    @Override
    public void initPosPage() {
        Intent intent = new Intent(this, RegisterActivity.class);
        startActivity(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public void onResume() {
        super.onResume();
        WmAceKG.startServer();
    }

    @Override
    public void onPause() {
        super.onPause();
        WmAceKG.stopServer();
    }

    @Override
    public void setCameraId() {
        //设置摄像头id
        WmAceKG.setCameraId(0);
    }

    @Override
    public void getCameraFrame() {
        ScaleBitmap scaleBitmap = getScaleBitmap(true);
        if (scaleBitmap.getCrop() != null) {
            weighingBinding.ivScrop.setImageBitmap(scaleBitmap.getCrop());
        } else if (scaleBitmap.getRaw() != null) {
            weighingBinding.ivScrop.setImageBitmap(scaleBitmap.getRaw());
        }
    }

    @Override
    public void saveScaleSetting() {
        ScaleSetting setting = new ScaleSetting();
        // 该数据为测试用数据
        setting.setLeft(100);
        setting.setTop(100);
        setting.setWidth(400);
        setting.setHeight(300);
        int code = WmAceKG.saveScaleSetting(setting);
        weighingBinding.tvInfo.setText("相机裁剪结果:" + code);
    }

    @Override
    public void getScaleSettingI() {
        boolean scaleSetting = WmAceKG.getScaleSetting();
        weighingBinding.tvInfo.setText("秤盘标定结果:" + scaleSetting);
    }

    @Override
    public void unBindPos() {
        WmAceKG.unBindPos(Constant.TENANT, Constant.SN_CODE, new OnUnBindPosListener() {
            @Override
            public void unBindFail(int code, String message) {
                weighingBinding.tvInfo.setText("解绑失败:" + code + "," + message);
            }

            @Override
            public void unBindSuccess() {
                weighingBinding.tvInfo.setText("解绑成功");
            }
        });
    }

    @Override
    public void clearTrainedDataI() {
        WmAceKG.clearTrainedData();
    }

    @Override
    public void autoDetectI() {
        try {
            DetectResult detectResult = autoDetect(new OnBitmapSaveListener() {
                @Override
                public void onComplete(Bitmap bitmap, String path) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            weighingBinding.ivScrop.setImageBitmap(bitmap);
//                            String text = weighingBinding.tvInfo.getText().toString();
                            weighingBinding.tvInfo.append(path);
                        }
                    });
                }
            });
            if (detectResult == null) {
                return;
            }
            if (detectResult.getErrorCode() == 2000) {
                openCamera();
            }
            if (detectResult.getErrorCode() != 0) {
                weighingBinding.tvInfo.setText("识别错误,错误码:" + detectResult.getErrorCode());
                if (detectResult.getErrorCode() == 2007) {
                    weighingBinding.tvInfo.setText("正在初始化数据,请稍等");
                }
                return;
            }
            sessionId = detectResult.getSessionId();
            StringBuilder builder = new StringBuilder();
            builder.append("sessionId:");
            builder.append(sessionId + "\n");
//            resultList.clear();
            resultList = detectResult.getProductIds();
            if (detectResult.getProductIds() != null) {
                List<String> productIds = detectResult.getProductIds();
                if (productIds.size() > 0) {
                    for (String productId : productIds) {
                        if (!TextUtils.isEmpty(productId)) {
                            builder.append("商品id:" + productId + "\n");
                        }
                    }
                } else {
                    builder.append("商品识别为空,可以调用setFeedback绑定plu号");
                }
            }
            weighingBinding.tvInfo.setText(builder);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setFeedBackI() {
        String plu = weighingBinding.edtPlu.getText().toString();
        if (TextUtils.isEmpty(plu)) {
            Toast.makeText(this, "请输入plu号", Toast.LENGTH_LONG).show();
            return;
        }
        if (TextUtils.isEmpty(sessionId)) {
            return;
        }
        if (resultList != null) {
            boolean isHit = resultList.contains(plu) && (resultList.size() == 1);
            setFeedBack(sessionId, plu, "测试用商品", isHit);
            weighingBinding.tvInfo.append("反馈完成, 命中结果" + isHit);
        }
    }

    @Override
    public void setNoRecommendI() {
        String plu = weighingBinding.edtPlu.getText().toString();
        if (TextUtils.isEmpty(plu)) {
            Toast.makeText(this, "请输入plu号", Toast.LENGTH_LONG).show();
            return;
        }
        setNoRecommend(plu);
    }

    @Override
    public void getLocalImagePathI() {
        String localImagePath = WmAceKG.getLocalImagePath(sessionId);
        weighingBinding.tvInfo.append(localImagePath);
    }

    @Override
    public void getSelfLearnI() {
        String selfLearn = WmAceKG.getSelfLearn(sessionId);
        weighingBinding.tvInfo.append("学习数据:"+selfLearn);
    }

    @Override
    public void imageLearnI() {
        List<ImageBean> list = getLocalTestImage();
        WmAceKG.imageLearn( list, true);
    }

    @Override
    public void imageLearnSyncI() {
        List<ImageBean> list = getLocalTestImage();
        new Thread(new Runnable() {
            @Override
            public void run() {
                WmAceKG.imageLearnSync( list, true);
            }
        }).start();

    }

    @Override
    public void imageLearnCancelI() {
        WmAceKG.imageLearnCancel();
    }

    @Override
    public void exportDataI() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                StopWatch stopWatch = new StopWatch("exportDb");
                stopWatch.start("exportDb");
                int code = WmAceKG.exportData(new OnDataExportListener() {
                    @Override
                    public void onComplete(String path) {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                weighingBinding.tvInfo.append(path);
                            }
                        });
                    }
                });
                stopWatch.stop();
                XLog.i(stopWatch.prettyPrint());
                if (code == 0) {
                    XLog.i("导出成功");
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            weighingBinding.tvInfo.append("导出成功,耗时:" + stopWatch.getTotalTimeSeconds()+"秒");
                        }
                    });
                } else {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            weighingBinding.tvInfo.setText("导出失败");
                        }
                    });
                    XLog.i("导出失败，错误码为：" + code);
                }
            }
        }).start();
    }

    @Override
    public void importDataI() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                StopWatch stopWatch = new StopWatch("importDb");
                stopWatch.start("importDb");
                int code = WmAceKG.importData(true);
                stopWatch.stop();
                XLog.i(stopWatch.prettyPrint());
                if (code == 0) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            weighingBinding.tvInfo.setText("导入成功,耗时:" + stopWatch.getTotalTimeSeconds()+"秒");
                        }
                    });
                    XLog.i("导入成功");
                } else {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            weighingBinding.tvInfo.setText("导入失败");
                        }
                    });
                }
            }
        }).start();
    }

    @Override
    public void startServerI() {
        WmAceKG.startServer();
    }

    @Override
    public void stopServerI() {
        WmAceKG.stopServer();
    }

    @Override
    public void queryLearnedProductsI() {
        List<String> productIds = WmAceKG.queryLearnedProducts();
        weighingBinding.tvInfo.setText("已学习的商品:" + productIds);
    }

    @Override
    public void queryPosByMacI() {
        WmAceKG.queryPosByMac(new OnQueryPosRegisterInfoListener() {
            @Override
            public void onSuccess(String posId, String snCode, String tenant) {
                weighingBinding.tvInfo.setText("pos号:" + posId + "\nsncode:" + snCode + "\ntenant:" + tenant);
            }

            @Override
            public void onFailure(int code, String message) {
                weighingBinding.tvInfo.setText("绑定失败");
            }
        });
    }

    int ret = 1;
    @Override
    public void learnLocalVectorDataI() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                ret = WmAceKG.learnLocalVectorData();
            }
        }).start();
        if (ret == 0) {
            weighingBinding.tvInfo.append("学习成功");
        } else if (ret == -1) {
            weighingBinding.tvInfo.append("学习失败,未找到txt文件");
        }
    }

    @Override
    public void correctI() {
        String plu = weighingBinding.edtPlu.getText().toString();
        if (TextUtils.isEmpty(plu)) {
            Toast.makeText(this, "请输入plu号", Toast.LENGTH_LONG).show();
            return;
        }
        correct(sessionId, plu);
    }

    @Override
    public void autoMatchProduct() {
        // 从本地文件读取测试用商品资料,注意一次传入数量控制在2000以内
        List<ProductMatch> list = new ArrayList<>();
        AssetManager assetManager = context.getAssets();
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(assetManager.open("list_product.txt")));
            String line;
            while ((line = reader.readLine()) != null){
                String[] array = line.split("\t");
                if (array.length >= 2){
                    ProductMatch productMatch = new ProductMatch();
                    productMatch.setProductNumber(array[0]);
                    productMatch.setProductName(array[1]);
                    list.add(productMatch);
                }
            }
            reader.close();
        } catch (IOException e) {
            XLog.e(e.toString());
        }
        // 调用自动配图接口
        WmAceKG.thumbnailsAutoMatch(list, new OnProductMatchListener() {
            @Override
            public void onSuccess(List<ProductMatch> productBeans) {
                weighingBinding.tvInfo.setText("");
                weighingBinding.tvInfo.append("自动配图成功");
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for (ProductMatch temp : productBeans){
                            XLog.i(temp.getProductName() + "=====>" + temp.getMatchProductUrl());
                        }
                    }
                }).start();
            }

            @Override
            public void onFailure(int code, String message) {
                weighingBinding.tvInfo.setText("");
                weighingBinding.tvInfo.append("自动配图失败:" + code + message);
            }
        });
    }

    @Override
    public void checkSnCodeVerification() {
        // 检验SN合法性
        // todo snCode请替换成设备真实SN
        String snCode = "77C4AD47-04B3-47B7-B9DF-A55D91F9E0BA";
        weighingBinding.tvInfo.setText("正在校验SN合法性:" + snCode + "\n");
        // 第二个参数为接口网络请求的超时时间
        WmAceKG.checkSnCodeVerification(snCode, 1L, new OnCheckSnCodeVerificationListener() {
            @Override
            public void onSuccess(int code, String description) {
                weighingBinding.tvInfo.append("校验SN合法性结果:" + code);
                weighingBinding.tvInfo.append(description);
            }

            @Override
            public void onFailure(int code, String message) {
                weighingBinding.tvInfo.append("校验SN合法性失败:" + code + "," + message);
            }
        });
    }

    /**
     * 加载预学习数据
     */
    @Override
    public void preLearningData() {
        // 加载测试用商品
        List<ProductMatch> productMatches = new ArrayList<>();
        AssetManager am = context.getAssets();
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(am.open("list_product.txt")));
            String line;
            while ((line = reader.readLine()) != null){
                String[] array = line.split("\t");
                if (array.length >= 2){
                    ProductMatch productMatch = new ProductMatch();
                    productMatch.setProductNumber(array[0]);
                    productMatch.setProductName(array[1]);
                    productMatches.add(productMatch);
                }
            }
            reader.close();
        } catch (IOException e) {
            XLog.e(e.toString());
        }
        WmAceKG.preLearning(productMatches, new OnPreLearningListener() {
            @Override
            public void onSuccess(int successNum) {
                weighingBinding.tvInfo.append("预学习成功，学习的商品数量:" + successNum);
            }

            @Override
            public void onFailure(int code, String message, int successNum) {
                weighingBinding.tvInfo.append(String.format("预学习失败, 错误码:%s, 错误信息:%s, 学习数量:%s", code, message, successNum));
            }
        });
    }

    /**
     * 获取本地测试用图片
     * @return
     */
    public List<ImageBean> getLocalTestImage(){
        List<ImageBean> list = new ArrayList<>();
        String rootPath = getExternalFilesDir("TestImage").getPath()+"/";
        File directory = new File(rootPath);
        if (directory.exists()){
            // code仅为测试使用，实际应替换为真实的商品编号
            int code = 0;
            for (String path : Objects.requireNonNull(directory.list())){
                System.out.println("path:" + rootPath + path);
                list.add(new ImageBean(rootPath + path, code + ""));
                code ++;
            }
        }

        return list;
    }

}