package ai.pai.lensman.printer;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;

import com.android.common.utils.LogHelper;
import com.gprinter.aidl.GpService;
import com.gprinter.command.EscCommand;
import com.gprinter.command.GpCom;
import com.gprinter.io.GpDevice;
import com.gprinter.io.PortParameters;
import com.gprinter.service.GpPrintService;

import org.apache.commons.lang.ArrayUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import ai.pai.lensman.App;
import ai.pai.lensman.R;
import ai.pai.lensman.db.Preferences;


public class PrinterSettingPresenter implements PrinterSettingContract.Presenter {

    private Context context;
    private PrinterSettingContract.View view;
    private  BluetoothAdapter bluetoothAdapter;

    private GpService mGpService;
    private PrinterServiceConnection conn = null;

    private static final String TAG = "PrinterSettingPresenter";

    class PrinterServiceConnection implements ServiceConnection {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected() called");
            mGpService = null;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected() called");
            mGpService = GpService.Stub.asInterface(service);
        }
    }


    public PrinterSettingPresenter(Context context, PrinterSettingContract.View view){
        this.view = view;
        this.context = context;
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    }

    @Override
    public void start() {
        registerPrinterBroadcast();
        startAndBindPrintService();
        if(queryBluetoothStatus()){
            view.onBluetoothEnabled();
            view.onPairedDeviceDiscovered(queryPairedDevices());
            discoverNewDevices();

        }else{
            view.onBluetoothDisabled();
            view.showToast(context.getString(R.string.bt_is_disabled));
        }
    }

    @Override
    public void stop() {
        cancelDiscovery();
        if (conn != null) {
            App.getAppContext().unbindService(conn);
        }
        context.unregisterReceiver(PrinterStatusBroadcastReceiver);
    }

    @Override
    public void queryPrinterStatus() {
        try {
            int status = mGpService.queryPrinterStatus(0, 10000);
            String str = new String();
            if (status == GpCom.STATE_NO_ERR) {
                str = "打印机正常";
            } else {
                str = "打印机 ";
                if ((byte) (status & GpCom.STATE_OFFLINE) > 0) {
                    str += "脱机";
                }
                if ((byte) (status & GpCom.STATE_PAPER_ERR) > 0) {
                    str += "缺纸";
                }
                if ((byte) (status & GpCom.STATE_COVER_OPEN) > 0) {
                    str += "打印机开盖";
                }
                if ((byte) (status & GpCom.STATE_ERR_OCCURS) > 0) {
                    str += "打印机出错";
                }
                if ((byte) (status & GpCom.STATE_TIMES_OUT) > 0) {
                    str += "查询超时";
                }
            }
            view.onPrinterStatusFetched(str);

        } catch (Exception e1) {
            view.showToast(context.getString(R.string.printer_status_query_fail));
        }
    }


    @Override
    public void printQR(String qrCodeStr) {
        if(TextUtils.isEmpty(Preferences.getInstance().getPrinterMac())){
            view.showToast(App.getAppContext().getString(R.string.not_set_printer_yet));
            return;
        }
        EscCommand esc = new EscCommand();
		/*打印文字*/
        esc.addSelectPrintModes(EscCommand.FONT.FONTA, EscCommand.ENABLE.OFF, EscCommand.ENABLE.OFF,
                EscCommand.ENABLE.OFF, EscCommand.ENABLE.OFF);//取消倍高倍宽
        esc.addSelectJustification(EscCommand.JUSTIFICATION.CENTER);//设置打印左对齐
        esc.addText("拍爱\n");   //  打印文字
        esc.addPrintAndLineFeed();
		/*QRCode命令打印
			此命令只在支持QRCode命令打印的机型才能使用。
			在不支持二维码指令打印的机型上，则需要发送二维条码图片
		*/
        esc.addSelectErrorCorrectionLevelForQRCode((byte) 0x31); //设置纠错等级
        esc.addSelectSizeOfModuleForQRCode((byte)8);//设置qrcode模块大小
        esc.addStoreQRCodeData(qrCodeStr);//设置qrcode内容
        esc.addSelectJustification(EscCommand.JUSTIFICATION.CENTER);//设置打印中心对齐
        esc.addPrintQRCode();//打印QRCode
        esc.addPrintAndFeedLines((byte) 1);
//        esc.addSelectJustification(EscCommand.JUSTIFICATION.LEFT);//设置打印左对齐
//        esc.addText("拍摄日期 "+new SimpleDateFormat("yyyy/MM/dd HH:mm").format(new Date()));
//        esc.addPrintAndFeedLines((byte) 2);

        Vector<Byte> datas = esc.getCommand(); //发送数据
        Byte[] Bytes = datas.toArray(new Byte[datas.size()]);
        byte[] bytes = ArrayUtils.toPrimitive(Bytes);
        String str = Base64.encodeToString(bytes, Base64.DEFAULT);
        int rel;
        try {
            rel = mGpService.sendEscCommand(0, str);
            GpCom.ERROR_CODE r = GpCom.ERROR_CODE.values()[rel];
            if (r != GpCom.ERROR_CODE.SUCCESS) {
                view.showToast( GpCom.getErrorText(r));
            }
        } catch (Exception e) {
            view.showToast(App.getAppContext().getString(R.string.go_check_printer));
        }
    }

    @Override
    public boolean queryBluetoothStatus() {
        if(bluetoothAdapter==null){
            return false;
        }
        return bluetoothAdapter.isEnabled();
    }

    @Override
    public List<BluetoothDevice> queryPairedDevices() {
        ArrayList<BluetoothDevice> pairedDevices = new ArrayList<>();
        Set<BluetoothDevice> deviceSet = bluetoothAdapter.getBondedDevices();
        for(BluetoothDevice device: deviceSet){
            pairedDevices.add(device);
        }
        return pairedDevices;

    }

    @Override
    public void discoverNewDevices() {
        // Register for broadcasts when a device is discovered
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        context.registerReceiver(mFindBlueToothReceiver, filter);
        // Register for broadcasts when discovery has finished
        filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        context.registerReceiver(mFindBlueToothReceiver, filter);
        bluetoothAdapter.startDiscovery();
    }

    @Override
    public void connectPrinter(BluetoothDevice device) {
        if(mGpService==null){
            view.showToast(context.getString(R.string.printer_service_boot_fail));
            return;
        }
        try {
            int code = mGpService.openPort(0, PortParameters.BLUETOOTH, device.getAddress(), 0);
            if(code==0){
                Preferences.getInstance().setPrinterMac(device.getAddress());
            }
            LogHelper.d(TAG,"open port return code ="+code);
        } catch (Exception e) {
            view.showToast(context.getString(R.string.printer_port_open_fail));
        }

    }

    @Override
    public void cancelDiscovery() {
        try{
            bluetoothAdapter.cancelDiscovery();
            context.unregisterReceiver(mFindBlueToothReceiver);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void startAndBindPrintService() {
        Intent intent = new Intent(App.getAppContext(), GpPrintService.class);
        App.getAppContext().startService(intent);
        conn = new PrinterServiceConnection();
        App.getAppContext().bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }

    // changes the title when discovery is finished
    private final BroadcastReceiver mFindBlueToothReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            // When discovery finds a device
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent
                        .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // If it's already paired, skip it, because it's been listed
                // already
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    view.onNewDeviceDiscovered(device);
                }
                // When discovery is finished, change the Activity title
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED
                    .equals(action)) {
                view.showToast(context.getString(R.string.bt_discover_complete));
            }
        }
    };

    private void registerPrinterBroadcast() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(GpCom.ACTION_CONNECT_STATUS);
        context.registerReceiver(PrinterStatusBroadcastReceiver, filter);
    }

    private BroadcastReceiver PrinterStatusBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (GpCom.ACTION_CONNECT_STATUS.equals(intent.getAction())) {
                int type = intent.getIntExtra(GpPrintService.CONNECT_STATUS, 0);
                int id = intent.getIntExtra(GpPrintService.PRINTER_ID, 0);
                Log.d(TAG, "connect status " + type);
                if (type == GpDevice.STATE_CONNECTING) {
                    view.onPrinterStatusFetched(context.getString(R.string.connecting));
                } else if (type == GpDevice.STATE_NONE) {

                } else if (type == GpDevice.STATE_VALID_PRINTER) {
                    view.onPrinterStatusFetched(context.getString(R.string.printer_is_connected));
                } else if (type == GpDevice.STATE_INVALID_PRINTER) {
                    view.onPrinterStatusFetched(context.getString(R.string.printer_is_disconnected));
                }
            }
        }
    };

}
