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.Log;

import com.gprinter.command.GpCom;
import com.gprinter.io.GpDevice;
import com.gprinter.service.GpPrintService;

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

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 PrinterService printerService;
    private PrinterSettingContract.View view;
    private PrinterServiceConnection connection;
    private  BluetoothAdapter bluetoothAdapter;

    private static final String TAG = "PrinterSettingPresenter";

    private class PrinterServiceConnection implements ServiceConnection{

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            printerService = ((PrinterService.PrintServiceBinder)service).getService();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            printerService = null;
        }
    }

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

    @Override
    public void start() {
        registerPrinterBroadcast();
        context.startService(new Intent(context,PrinterService.class));
        context.bindService(new Intent(context,PrinterService.class),connection,Context.BIND_AUTO_CREATE);
        if(queryBluetoothStatus()){
            view.onBluetoothEnabled();
            view.onPairedDeviceDiscovered(queryPairedDevices());
            discoverNewDevices();
            if(Preferences.getInstance().isPrinterConnected()){
                view.onPrinterStatusFetched(context.getString(R.string.printer_is_connected));
            }else{
                view.onPrinterStatusFetched(context.getString(R.string.click_to_query));
            }
        }else{
            view.onBluetoothDisabled();
            view.showToast(context.getString(R.string.bt_is_disabled));
        }
    }

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

    @Override
    public void queryPrinterStatus() {
        if(printerService==null){
            view.showToast(context.getString(R.string.printer_status_query_fail));
            return;
        }
        view.onPrinterStatusFetched(printerService.queryPrinterStatus());
    }


    @Override
    public void printQR(String qrCodeStr) {
        if(printerService==null){
            view.showToast(context.getString(R.string.printer_service_boot_fail));
            return;
        }
        if(TextUtils.isEmpty(Preferences.getInstance().getPrinterMac())){
            view.showToast(App.getAppContext().getString(R.string.not_set_printer_yet));
            return;
        }
        int code = printerService.printQR(qrCodeStr);
        if(code == PrinterService.ERROR_CODE_PRINTER_SERVICE_EXCEPTION){
            view.showToast(context.getString(R.string.go_check_printer));
        }else if(code == PrinterService.ERROR_CODE_PRINTER_SERVICE_OFF){
            view.showToast(context.getString(R.string.go_check_printer));
        }else if( GpCom.ERROR_CODE.values()[code]!= GpCom.ERROR_CODE.SUCCESS){
            view.showToast( GpCom.getErrorText(GpCom.ERROR_CODE.values()[code]));
        }
    }

    @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(printerService==null){
            view.showToast(context.getString(R.string.printer_service_boot_fail));
            return;
        }
        int code = printerService.connectPrinter(device);
        if(code==0){
            Preferences.getInstance().setPrinterMac(device.getAddress());
            Preferences.getInstance().setPrinterConnected(true);
        }else{
            view.showToast(context.getString(R.string.printer_port_open_fail));
            Preferences.getInstance().setPrinterConnected(false);
        }

    }

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


    // 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);
                Log.d(TAG, "connect status " + type);
                if (type == GpDevice.STATE_CONNECTING) {
                    view.onPrinterStatusFetched(context.getString(R.string.connecting));
                } else if (type == GpDevice.STATE_NONE) {
                    view.onPrinterStatusFetched(context.getString(R.string.connecting));
                } 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));
                }
            }
        }
    };

}
