package com.ihaoin.hooloo.device.view;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.ihaoin.hooloo.device.R;
import com.ihaoin.hooloo.device.component.NetworkHandler;
import com.ihaoin.hooloo.device.component.PushMessageReceiver;
import com.ihaoin.hooloo.device.config.AppConfig;
import com.ihaoin.hooloo.device.config.Base;
import com.ihaoin.hooloo.device.data.TrolleyGoods;
import com.ihaoin.hooloo.device.data.po.ConfirmGoods;
import com.ihaoin.hooloo.device.data.po.ConfirmOrder;
import com.ihaoin.hooloo.device.data.po.ConfirmSku;
import com.ihaoin.hooloo.device.data.vo.Goods;
import com.ihaoin.hooloo.device.data.vo.Sku;
import com.ihaoin.hooloo.device.network.HttpUtil;
import com.ihaoin.hooloo.device.util.CollectionUtils;
import com.ihaoin.hooloo.device.util.JsonUtils;
import com.ihaoin.hooloo.device.util.RandomUtils;
import com.ihaoin.hooloo.device.util.SharedPreferencesUtils;
import com.ihaoin.hooloo.device.util.Utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class ConfirmOrderDialog extends Dialog {
    private List<ConfirmGoods> goods = new ArrayList<>();
    private UIHandler uiHandler;
    private ConfirmOrderHandler confirmOrderHandler;
    private Thread expireThread;
    private Thread returnThread;
    private final Integer EXPIRE_TIMES = 60;
    private final Integer RETURN_TIMES = 5;

    private View layoutContent;
    private View layoutConfirm;
    private View layoutSucceed;
    private ImageView imgQRCode;
    private TextView txtExpire;
    private TextView txtReturn;
    private View butnClose;
    private View loading;

    public ConfirmOrderDialog(@NonNull Context context) {
        super(context);
    }

    public void setGoods(List<TrolleyGoods> trolleyGoods) {
        this.goods = translate(trolleyGoods);
    }

    public void setGoods(Goods goods, Sku sku, Integer count) {
        this.goods = translate(goods, sku, count);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(R.layout.view_confirm_order);
        initViews();
    }

    private void initViews() {
        setCancelable(false);
        setCanceledOnTouchOutside(false);

        layoutContent = findViewById(R.id.layout_content);
        layoutConfirm = findViewById(R.id.layout_confirm);
        layoutSucceed = findViewById(R.id.layout_succeed);
        imgQRCode = findViewById(R.id.img_qrcode);
        txtExpire = findViewById(R.id.txt_expire);
        txtReturn = findViewById(R.id.txt_return);
        butnClose = findViewById(R.id.butn_close);
        loading = findViewById(R.id.loading);

        butnClose.setOnClickListener(x -> dismiss());
        uiHandler = new UIHandler();

        showConfirmViews();

        setOnDismissListener(dismissListener);

        postConfirmOrder();
        Utils.setTouchDelegate(findViewById(R.id.layout_root), Arrays.asList(butnClose));
    }

    private void showConfirmViews() {
        layoutConfirm.setVisibility(View.VISIBLE);
        layoutSucceed.setVisibility(View.GONE);
    }

    private void showSucceedViews() {
        layoutConfirm.setVisibility(View.GONE);
        layoutSucceed.setVisibility(View.VISIBLE);
    }

    private void postConfirmOrder() {
        try {
            startLoading();

            confirmOrderHandler = new ConfirmOrderHandler();
            HttpUtil.postConfirmOrder(genJson(), confirmOrderHandler);
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(getContext(), R.string.error_get_qrcode, Toast.LENGTH_LONG).show();
            dismiss();
        }
    }

    private void startLoading() {
        layoutContent.setVisibility(View.INVISIBLE);
        loading.setVisibility(View.VISIBLE);

        AnimationDrawable animationDrawable = (AnimationDrawable) loading.getBackground();
        animationDrawable.start();
    }

    private void stopLoading() {
        layoutContent.setVisibility(View.VISIBLE);
        loading.setVisibility(View.INVISIBLE);

        AnimationDrawable animationDrawable = (AnimationDrawable) loading.getBackground();
        animationDrawable.stop();
    }

    private String genJson() {
        try {
            ConfirmOrder confirmOrder = new ConfirmOrder();
            confirmOrder.setMachineCode(AppConfig.MACHINE_CODE);
            confirmOrder.setScreenNo(SharedPreferencesUtils.getScreenNo(getContext()));
            confirmOrder.setSeqNo(genSeqNo());
            confirmOrder.setGoods(goods);
            String json = JsonUtils.getMapper().writeValueAsString(confirmOrder);
            Log.d("TEST", json);
            return json;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private String genSeqNo() {
        return new Date().getTime() + "-" + RandomUtils.nextInt(null);
    }

    OnDismissListener dismissListener = new OnDismissListener() {
        @Override
        public void onDismiss(DialogInterface dialog) {
            Utils.fastBroadcast(getContext(), Base.BROADCAST_ACTION_CLEAR_GOODS);
            if (expireThread != null) {
                expireThread.interrupt();
            }
            if (returnThread != null) {
                returnThread.interrupt();
            }
            if (uiHandler != null) {
                uiHandler.removeCallbacksAndMessages(null);
                uiHandler = null;
            }
            if (confirmOrderHandler != null) {
                confirmOrderHandler.removeCallbacksAndMessages(null);
                confirmOrderHandler = null;
            }
            if (qrCodeVisitedHandler != null) {
                qrCodeVisitedHandler.removeCallbacksAndMessages(null);
                qrCodeVisitedHandler = null;
            }
            unregsitQRCodeVisitedListener();
        }
    };

    /** 等待扫码倒计时 */
    private void startExpireThread() {
        regsitQRCodeVisitedListener();
        expireThread = new Thread(() -> {
            try {
                for (int i = EXPIRE_TIMES; i >= 0; i--) {
                    if (uiHandler == null) {
                        return;
                    }
                    Message msg = new Message();
                    msg.what = 0;// 二维码失效倒计时
                    msg.obj = i;
                    uiHandler.sendMessage(msg);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        expireThread.start();
    }

    /** 扫码成功倒计时 */
    private void startReturnThread() {
        returnThread = new Thread(() -> {
            try {
                for (int i = RETURN_TIMES; i >= 0; i--) {
                    if (uiHandler == null) {
                        return;
                    }
                    Message msg = new Message();
                    msg.what = 1;// 扫码成功倒计时
                    msg.obj = i;
                    uiHandler.sendMessage(msg);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        returnThread.start();
    }

    /** 刷新UI */
    class UIHandler extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case 0:
                    Integer expireTimes = (Integer) msg.obj;
                    txtExpire.setText(getContext().getString(R.string.expire_times, expireTimes.toString()));
                    if (expireTimes <= 0) {
                        dismiss();
                    }
                    break;
                case 1:
                    Integer returnTimes = (Integer) msg.obj;
                    txtReturn.setText(getContext().getString(R.string.scan_succeed, returnTimes.toString()));
                    if (returnTimes <= 0) {
                        dismiss();
                    }
                    break;
            }
        }
    }

    /** 服务器保存购物车信息回调 */
    class ConfirmOrderHandler extends NetworkHandler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            try {
                stopLoading();
                Object obj = msg.obj;
                if (msg.what == 0 || obj == null) {
                    Toast.makeText(getContext(), R.string.error_get_qrcode, Toast.LENGTH_LONG).show();
                    dismiss();
                    return;
                }

                String id = obj.toString();
                Bitmap bitmap = genQRCode(id);
                imgQRCode.setImageBitmap(bitmap);
                startExpireThread();
            } catch (Exception e) {
                Toast.makeText(getContext(), R.string.error_get_qrcode, Toast.LENGTH_LONG).show();
                dismiss();
            }
        }
    }

    private Bitmap genQRCode(String saveCode) throws WriterException {
        String url = String.format(AppConfig.WX_URL, saveCode);
        int width = Utils.dpToPx(getContext(), 800); // 图像宽度
        int height = Utils.dpToPx(getContext(), 800); // 图像高度
        Map<EncodeHintType, Object> hints = new HashMap();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵
        int[] pixels = new int[width * height];
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                if (bitMatrix.get(x, y)) {
                    pixels[y * width + x] = Color.BLACK; // 黑色色块像素设置
                } else {
                    pixels[y * width + x] = Color.WHITE; // 白色色块像素设置
                }
            }
        }

        /** 4.创建Bitmap对象,根据像素数组设置Bitmap每个像素点的颜色值,之后返回Bitmap对象 */
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
        return bitmap;
    }

    private QRCodeVisitedHandler qrCodeVisitedHandler;

    class QRCodeVisitedHandler extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            if (msg.what != 1) {
                return;
            }
            expireThread.interrupt();
            showSucceedViews();
            startReturnThread();
            unregsitQRCodeVisitedListener();
        }
    }

    private void regsitQRCodeVisitedListener() {
        qrCodeVisitedHandler = new QRCodeVisitedHandler();
        PushMessageReceiver.subscribe(Base.PUSH_ACTION_QRCODE_VISITED, qrCodeVisitedHandler);
    }

    private void unregsitQRCodeVisitedListener() {
        PushMessageReceiver.unsubscribe(Base.PUSH_ACTION_QRCODE_VISITED);
    }

    /** 将购物车列表按商品id分组保存 */
    public List<ConfirmGoods> translate(List<TrolleyGoods> trolleyGoods) {
        if (CollectionUtils.isEmpty(trolleyGoods)) {
            return null;
        }
        Map<Integer, List<TrolleyGoods>> map = trolleyGoods.stream().collect(Collectors.groupingBy(TrolleyGoods::getGoodId));
        if (CollectionUtils.isEmpty(map)) {
            return null;
        }

        List<ConfirmGoods> confirmGoods = new ArrayList<>();
        Iterator<Integer> iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            Integer goodsId = iterator.next();
            List<TrolleyGoods> goods = map.get(goodsId);
            List<ConfirmSku> skus = goods.stream().map(x -> {
                ConfirmSku confirmSku = new ConfirmSku();
                confirmSku.setSkuId(x.getSkuId());
                confirmSku.setCount(x.getCount());
                return confirmSku;
            }).collect(Collectors.toList());

            ConfirmGoods g = new ConfirmGoods();
            g.setGoodsId(goodsId);
            g.setSkus(skus);
            confirmGoods.add(g);
        }
        return confirmGoods;
    }

    public List<ConfirmGoods> translate(Goods goods, Sku sku, Integer count) {
        if (goods == null || sku == null || count <= 0) {
            return null;
        }

        ConfirmSku confirmSku = new ConfirmSku();
        confirmSku.setSkuId(sku.getSkuId());
        confirmSku.setCount(count);
        List<ConfirmSku> skus = Arrays.asList(confirmSku);

        ConfirmGoods confirmGoods = new ConfirmGoods();
        confirmGoods.setGoodsId(goods.getGoodsId());
        confirmGoods.setSkus(skus);
        return Arrays.asList(confirmGoods);
    }
}
